text: // Copyright 2019 the V8 project authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef TEST_WASM_API_TESTS_WASM_API_TEST_H_
  #define TEST_WASM_API_TESTS_WASM_API_TEST_H_
  
  #include "src/wasm/wasm-module-builder.h"
  #include "src/wasm/wasm-opcodes.h"
  #include "src/zone/accounting-allocator.h"
  #include "src/zone/zone.h"
  #include "test/common/wasm/wasm-macro-gen.h"
  #include "testing/gtest/include/gtest/gtest.h"
  #include "third_party/wasm-api/wasm.hh"
  
  namespace v8 {
  namespace internal {
  namespace wasm {
  
  using ::wasm::Engine;
  using ::wasm::Extern;
  using ::wasm::Foreign;
  using ::wasm::Func;
  using ::wasm::FuncType;
  using ::wasm::Global;
  using ::wasm::Instance;
  using ::wasm::Memory;
  using ::wasm::Module;
  using ::wasm::own;
  using ::wasm::ownvec;
  using ::wasm::Ref;
  using ::wasm::Store;
  using ::wasm::Table;
  using ::wasm::Trap;
  using ::wasm::Val;
  using ::wasm::ValType;
  using ::wasm::vec;
  
  class WasmCapiTest : public ::testing::Test {
   public:
    WasmCapiTest()
        : Test(),
          engine_(Engine::make()),
          allocator_(std::make_unique<AccountingAllocator>()),
          zone_(std::make_unique<Zone>(allocator_.get(), ZONE_NAME)),
          wire_bytes_(zone_.get()),
          builder_(zone_->New<WasmModuleBuilder>(zone_.get())),
          exports_(ownvec<Extern>::make()),
          wasm_i_i_sig_(1, 1, wasm_i_i_sig_types_) {
      store_ = Store::make(engine_.get());
      cpp_i_i_sig_ =
          FuncType::make(ownvec<ValType>::make(ValType::make(::wasm::I32)),
                         ownvec<ValType>::make(ValType::make(::wasm::I32)));
    }
  
    void Compile() {
      builder_->WriteTo(&wire_bytes_);
      size_t size = wire_bytes_.end() - wire_bytes_.begin();
      vec<byte_t> binary = vec<byte_t>::make(
          size,
          reinterpret_cast<byte_t*>(const_cast<byte*>(wire_bytes_.begin())));
  
      module_ = Module::make(store_.get(), binary);
      DCHECK_NE(module_.get(), nullptr);
    }
  
    void Instantiate(Extern* imports[]) {
      Compile();
      instance_ = Instance::make(store_.get(), module_.get(), imports);
      DCHECK_NE(instance_.get(), nullptr);
      exports_ = instance_->exports();
    }
  
    void AddExportedFunction(Vector<const char> name, byte code[],
                             size_t code_size, FunctionSig* sig) {
      WasmFunctionBuilder* fun = builder()->AddFunction(sig);
      fun->EmitCode(code, static_cast<uint32_t>(code_size));
      fun->Emit(kExprEnd);
      builder()->AddExport(name, fun);
    }
  
    void AddFunction(byte code[], size_t code_size, FunctionSig* sig) {
      WasmFunctionBuilder* fun = builder()->AddFunction(sig);
      fun->EmitCode(code, static_cast<uint32_t>(code_size));
      fun->Emit(kExprEnd);
    }
  
    Func* GetExportedFunction(size_t index) {
      DCHECK_GT(exports_.size(), index);
      Extern* exported = exports_[index].get();
      DCHECK_EQ(exported->kind(), ::wasm::EXTERN_FUNC);
      Func* func = exported->func();
      DCHECK_NE(func, nullptr);
      return func;
    }
  
    Global* GetExportedGlobal(size_t index) {
      DCHECK_GT(exports_.size(), index);
      Extern* exported = exports_[index].get();
      DCHECK_EQ(exported->kind(), ::wasm::EXTERN_GLOBAL);
      Global* global = exported->global();
      DCHECK_NE(global, nullptr);
      return global;
    }
  
    Memory* GetExportedMemory(size_t index) {
      DCHECK_GT(exports_.size(), index);
      Extern* exported = exports_[index].get();
      DCHECK_EQ(exported->kind(), ::wasm::EXTERN_MEMORY);
      Memory* memory = exported->memory();
      DCHECK_NE(memory, nullptr);
      return memory;
    }
  
    Table* GetExportedTable(size_t index) {
      DCHECK_GT(exports_.size(), index);
      Extern* exported = exports_[index].get();
      DCHECK_EQ(exported->kind(), ::wasm::EXTERN_TABLE);
      Table* table = exported->table();
      DCHECK_NE(table, nullptr);
      return table;
    }
  
    void Shutdown() {
      exports_.reset();
      instance_.reset();
      module_.reset();
      store_.reset();
      builder_ = nullptr;
      zone_.reset();
      allocator_.reset();
      engine_.reset();
    }
  
    WasmModuleBuilder* builder() { return builder_; }
    Engine* engine() { return engine_.get(); }
    Store* store() { return store_.get(); }
    Module* module() { return module_.get(); }
    Instance* instance() { return instance_.get(); }
    const ownvec<Extern>& exports() { return exports_; }
    ZoneBuffer* wire_bytes() { return &wire_bytes_; }
  
    FunctionSig* wasm_i_i_sig() { return &wasm_i_i_sig_; }
    FuncType* cpp_i_i_sig() { return cpp_i_i_sig_.get(); }
  
   private:
    own<Engine> engine_;
    own<AccountingAllocator> allocator_;
    own<Zone> zone_;
    ZoneBuffer wire_bytes_;
    WasmModuleBuilder* builder_;
    own<Store> store_;
    own<Module> module_;
    own<Instance> instance_;
    ownvec<Extern> exports_;
    own<FuncType> cpp_i_i_sig_;
    ValueType wasm_i_i_sig_types_[2] = {kWasmI32, kWasmI32};
    FunctionSig wasm_i_i_sig_;
  };
  
  }  // namespace wasm
  }  // namespace internal
  }  // namespace v8
  
  #endif  // TEST_WASM_API_TESTS_WASM_API_TEST_H_
  