// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <unordered_set>

#include "gtest/gtest.h"
#include "src/ast/case_statement.h"
#include "src/demangler.h"
#include "src/reader/wgsl/parser.h"
#include "src/writer/wgsl/generator.h"

namespace tint {
namespace ast {
namespace {

TEST(ModuleCloneTest, Clone) {
#if TINT_BUILD_WGSL_READER && TINT_BUILD_WGSL_WRITER
  // Shader that exercises the bulk of the AST nodes and types.
  // See also fuzzers/tint_ast_clone_fuzzer.cc for further coverage of cloning.
  Source::File file("test.wgsl", R"([[block]]
struct S {
  [[offset(0)]]
  m0 : u32;
  [[offset(4)]]
  m1 : array<u32>;
};

type t0 = [[stride(16)]] array<vec4<f32>>;
type t1 = [[stride(32)]] array<vec4<f32>>;

const c0 : i32 = 10;
const c1 : bool = true;

var<uniform> g0 : u32 = 20u;
var<out> g1 : f32 = 123.0;
var<uniform> g2 : texture_2d<f32>;
var<uniform> g3 : texture_storage_ro_2d<r32uint>;
var<uniform> g4 : texture_storage_wo_2d<rg32float>;
var<uniform> g5 : texture_storage_ro_2d<r32uint>;
var<uniform> g6 : texture_storage_wo_2d<rg32float>;

[[builtin(position)]] var<uniform> g7 : vec3<f32>;
[[set(10), binding(20)]] var<storage_buffer> g7 : S;
[[set(10), binding(20)]] var<storage_buffer> g8 : [[access(read)]]
S;
[[set(10), binding(20)]] var<storage_buffer> g9 : [[access(read_write)]]
S;

fn f0(p0 : bool) -> f32 {
  if (p0) {
    return 1.0;
  }
  return 0.0;
}

fn f1(p0 : f32, p1 : i32) -> f32 {
  var l0 : i32 = 3;
  var l1 : f32 = 8;
  var l2 : u32 = bitcast<u32>(4);
  var l3 : vec2<u32> = vec2<u32>(l0, l1);
  var l4 : S;
  var l5 : u32 = l4.m1[5];
  var l6 : ptr<private, u32>;
  l6 = null;
  loop {
    l0 = (p1 + 2);
    if (((l0 % 4) == 0)) {
      continue;
    }

    continuing {
      if (1 == 2) {
        l0 = l0 - 1;
      } else {
        l0 = l0 - 2;
      }
    }
  }
  switch(l2) {
    case 0: {
      break;
    }
    case 1: {
      return f0(true);
    }
    default: {
      discard;
    }
  }
  return 1.0;
}

[[stage(fragment)]]
fn main() -> void {
  f1(1.0, 2);
}

)");

  // Parse the wgsl, create the src module
  reader::wgsl::Parser parser(&file);
  ASSERT_TRUE(parser.Parse()) << parser.error();
  auto src = parser.module();

  // Clone the src module to dst
  auto dst = src.Clone();

  // Expect the AST printed with to_str() to match
  Demangler demanger;
  EXPECT_EQ(demanger.Demangle(src, src.to_str()),
            demanger.Demangle(dst, dst.to_str()));

  // Check that none of the AST nodes or type pointers in dst are found in src
  std::unordered_set<ast::Node*> src_nodes;
  for (auto& src_node : src.nodes()) {
    src_nodes.emplace(src_node.get());
  }
  std::unordered_set<ast::type::Type*> src_types;
  for (auto& src_type : src.types()) {
    src_types.emplace(src_type.second.get());
  }
  for (auto& dst_node : dst.nodes()) {
    ASSERT_EQ(src_nodes.count(dst_node.get()), 0u) << dst_node->str();
  }
  for (auto& dst_type : dst.types()) {
    ASSERT_EQ(src_types.count(dst_type.second.get()), 0u)
        << dst_type.second->type_name();
  }

  // Regenerate the wgsl for the src module. We use this instead of the original
  // source so that reformatting doesn't impact the final wgsl comparision.
  // Note that the src module is moved into the generator and this generator has
  // a limited scope, so that the src module is released before we attempt to
  // print the dst module.
  // This guarantee that all the source module nodes and types are destructed
  // and freed.
  // ASAN should error if there's any remaining references in dst when we try to
  // reconstruct the WGSL.
  std::string src_wgsl;
  {
    writer::wgsl::Generator src_gen(std::move(src));
    ASSERT_TRUE(src_gen.Generate());
    src_wgsl = src_gen.result();
  }

  // Print the dst module, check it matches the original source
  writer::wgsl::Generator dst_gen(std::move(dst));
  ASSERT_TRUE(dst_gen.Generate());
  auto dst_wgsl = dst_gen.result();
  ASSERT_EQ(src_wgsl, dst_wgsl);

#else  // #if TINT_BUILD_WGSL_READER && TINT_BUILD_WGSL_WRITER
  GTEST_SKIP() << "ModuleCloneTest requires TINT_BUILD_WGSL_READER and "
                  "TINT_BUILD_WGSL_WRITER to be enabled";
#endif
}

}  // namespace
}  // namespace ast
}  // namespace tint
