diff options
Diffstat (limited to 'deps/v8/build/fuchsia/fidlgen_js/test')
-rw-r--r-- | deps/v8/build/fuchsia/fidlgen_js/test/fidlgen_js_unittest.cc | 1334 | ||||
-rw-r--r-- | deps/v8/build/fuchsia/fidlgen_js/test/simple.fidl | 142 |
2 files changed, 1476 insertions, 0 deletions
diff --git a/deps/v8/build/fuchsia/fidlgen_js/test/fidlgen_js_unittest.cc b/deps/v8/build/fuchsia/fidlgen_js/test/fidlgen_js_unittest.cc new file mode 100644 index 0000000000..ed025c878b --- /dev/null +++ b/deps/v8/build/fuchsia/fidlgen_js/test/fidlgen_js_unittest.cc @@ -0,0 +1,1334 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <lib/fidl/cpp/binding.h> +#include <lib/fidl/cpp/internal/pending_response.h> +#include <lib/fidl/cpp/internal/weak_stub_controller.h> +#include <lib/zx/debuglog.h> +#include <zircon/syscalls/log.h> + +#include "base/bind.h" +#include "base/files/file_util.h" +#include "base/fuchsia/fuchsia_logging.h" +#include "base/run_loop.h" +#include "base/stl_util.h" +#include "base/strings/stringprintf.h" +#include "base/test/launcher/unit_test_launcher.h" +#include "base/test/test_suite.h" +#include "base/test/test_timeouts.h" +#include "build/fuchsia/fidlgen_js/fidl/fidljstest/cpp/fidl.h" +#include "build/fuchsia/fidlgen_js/runtime/zircon.h" +#include "gin/converter.h" +#include "gin/modules/console.h" +#include "gin/object_template_builder.h" +#include "gin/public/isolate_holder.h" +#include "gin/shell_runner.h" +#include "gin/test/v8_test.h" +#include "gin/try_catch.h" +#include "v8/include/v8.h" + +static const char kRuntimeFile[] = + "/pkg/build/fuchsia/fidlgen_js/runtime/fidl.mjs"; +static const char kTestBindingFile[] = + "/pkg/build/fuchsia/fidlgen_js/fidl/fidljstest/js/fidl.js"; + +namespace { + +zx_koid_t GetKoidForHandle(zx_handle_t handle) { + zx_info_handle_basic_t info; + zx_status_t status = zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC, &info, + sizeof(info), nullptr, nullptr); + if (status != ZX_OK) { + ZX_LOG(ERROR, status) << "zx_object_get_info"; + return ZX_KOID_INVALID; + } + return info.koid; +} + +zx_koid_t GetKoidForHandle(const zx::object_base& object) { + return GetKoidForHandle(object.get()); +} + +} // namespace + +class FidlGenJsTestShellRunnerDelegate : public gin::ShellRunnerDelegate { + public: + FidlGenJsTestShellRunnerDelegate() {} + + v8::Local<v8::ObjectTemplate> GetGlobalTemplate( + gin::ShellRunner* runner, + v8::Isolate* isolate) override { + v8::Local<v8::ObjectTemplate> templ = + gin::ObjectTemplateBuilder(isolate).Build(); + gin::Console::Register(isolate, templ); + return templ; + } + + void UnhandledException(gin::ShellRunner* runner, + gin::TryCatch& try_catch) override { + LOG(ERROR) << try_catch.GetStackTrace(); + ADD_FAILURE(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(FidlGenJsTestShellRunnerDelegate); +}; + +using FidlGenJsTest = gin::V8Test; + +TEST_F(FidlGenJsTest, BasicJSSetup) { + v8::Isolate* isolate = instance_->isolate(); + + std::string source = "log('this is a log'); this.stuff = 'HAI';"; + FidlGenJsTestShellRunnerDelegate delegate; + gin::ShellRunner runner(&delegate, isolate); + gin::Runner::Scope scope(&runner); + runner.Run(source, "test.js"); + + std::string result; + EXPECT_TRUE(gin::Converter<std::string>::FromV8( + isolate, runner.global()->Get(gin::StringToV8(isolate, "stuff")), + &result)); + EXPECT_EQ("HAI", result); +} + +void LoadAndSource(gin::ShellRunner* runner, const base::FilePath& filename) { + std::string contents; + ASSERT_TRUE(base::ReadFileToString(filename, &contents)); + + runner->Run(contents, filename.MaybeAsASCII()); +} + +class BindingsSetupHelper { + public: + explicit BindingsSetupHelper(v8::Isolate* isolate) + : isolate_(isolate), + handle_scope_(isolate), + delegate_(), + runner_(&delegate_, isolate), + scope_(&runner_), + zx_bindings_( + std::make_unique<fidljs::ZxBindings>(isolate, runner_.global())) { + // TODO(scottmg): Figure out how to set up v8 import hooking and make + // fidl_Xyz into $fidl.Xyz. Manually inject the runtime support js files + // for now. https://crbug.com/883496. + LoadAndSource(&runner_, base::FilePath(kRuntimeFile)); + LoadAndSource(&runner_, base::FilePath(kTestBindingFile)); + + zx_status_t status = zx::channel::create(0, &server_, &client_); + EXPECT_EQ(status, ZX_OK); + + runner_.global()->Set(gin::StringToSymbol(isolate, "testHandle"), + gin::ConvertToV8(isolate, client_.get())); + } + + template <class T> + T Get(const std::string& name) { + T t; + EXPECT_TRUE(gin::Converter<T>::FromV8( + isolate_, runner_.global()->Get(gin::StringToV8(isolate_, name)), &t)); + return t; + } + + template <class T> + T FromV8BigInt(v8::Local<v8::Value> val); + + template <> + uint64_t FromV8BigInt(v8::Local<v8::Value> val) { + EXPECT_TRUE(val->IsBigInt()); + return val.As<v8::BigInt>()->Uint64Value(nullptr); + } + + template <> + int64_t FromV8BigInt(v8::Local<v8::Value> val) { + EXPECT_TRUE(val->IsBigInt()); + return val.As<v8::BigInt>()->Int64Value(nullptr); + } + + // Custom version of gin::Converter that handles int64/uint64 from BigInt as + // gin::Converter is quite tied to Number. + template <class T> + std::vector<T> GetBigIntVector(const std::string& name) { + v8::Local<v8::Value> val = + runner_.global()->Get(gin::StringToV8(isolate_, name)); + EXPECT_TRUE(val->IsArray()); + + std::vector<T> result; + v8::Local<v8::Array> array(v8::Local<v8::Array>::Cast(val)); + uint32_t length = array->Length(); + for (uint32_t i = 0; i < length; ++i) { + v8::Local<v8::Value> v8_item; + EXPECT_TRUE( + array->Get(isolate_->GetCurrentContext(), i).ToLocal(&v8_item)); + T item; + if (v8_item->IsNumber()) { + EXPECT_TRUE(gin::Converter<T>::FromV8(isolate_, v8_item, &item)); + } else if (v8_item->IsBigInt()) { + item = FromV8BigInt<T>(v8_item); + } else { + ADD_FAILURE(); + } + result.push_back(item); + } + + return result; + } + + bool IsNull(const std::string& name) { + return runner_.global()->Get(gin::StringToV8(isolate_, name))->IsNull(); + } + + void DestroyBindingsForTesting() { zx_bindings_.reset(); } + + zx::channel& server() { return server_; } + zx::channel& client() { return client_; } + gin::ShellRunner& runner() { return runner_; } + + private: + v8::Isolate* isolate_; + v8::HandleScope handle_scope_; + FidlGenJsTestShellRunnerDelegate delegate_; + gin::ShellRunner runner_; + gin::Runner::Scope scope_; + std::unique_ptr<fidljs::ZxBindings> zx_bindings_; + zx::channel server_; + zx::channel client_; + + DISALLOW_COPY_AND_ASSIGN(BindingsSetupHelper); +}; + +class AnotherInterfaceImpl : public fidljstest::AnotherInterface { + public: + AnotherInterfaceImpl( + fidl::InterfaceRequest<fidljstest::AnotherInterface> request) + : binding_(this, std::move(request)) {} + ~AnotherInterfaceImpl() override = default; + + void TimesTwo(int32_t a, TimesTwoCallback callback) override { + callback(a * 2); + } + + private: + fidl::Binding<fidljstest::AnotherInterface> binding_; + + DISALLOW_COPY_AND_ASSIGN(AnotherInterfaceImpl); +}; + +class TestolaImpl : public fidljstest::Testola { + public: + TestolaImpl() { + // Don't want the default values from the C++ side. + memset(&basic_struct_, -1, sizeof(basic_struct_)); + } + ~TestolaImpl() override {} + + void DoSomething() override { was_do_something_called_ = true; } + + void PrintInt(int32_t number) override { received_int_ = number; } + + void PrintMsg(std::string message) override { received_msg_ = message; } + + void VariousArgs(fidljstest::Blorp blorp, + std::string msg, + std::vector<uint32_t> stuff) override { + various_blorp_ = blorp; + various_msg_ = msg; + various_stuff_ = stuff; + } + + void WithResponse(int32_t a, + int32_t b, + WithResponseCallback callback) override { + response_callbacks_.push_back(base::BindOnce( + [](WithResponseCallback callback, int32_t result) { callback(result); }, + std::move(callback), a + b)); + } + + void SendAStruct(fidljstest::BasicStruct basic_struct) override { + basic_struct_ = basic_struct; + } + + void NestedStructsWithResponse( + fidljstest::BasicStruct basic_struct, + NestedStructsWithResponseCallback resp) override { + // Construct a response, echoing the passed in structure with some + // modifications, as well as additional data. + fidljstest::StuffAndThings sat; + sat.count = 123; + sat.id = "here is my id"; + sat.a_vector.push_back(1); + sat.a_vector.push_back(-2); + sat.a_vector.push_back(4); + sat.a_vector.push_back(-8); + sat.basic.b = !basic_struct.b; + sat.basic.i8 = basic_struct.i8 * 2; + sat.basic.i16 = basic_struct.i16 * 2; + sat.basic.i32 = basic_struct.i32 * 2; + sat.basic.u8 = basic_struct.u8 * 2; + sat.basic.u16 = basic_struct.u16 * 2; + sat.basic.u32 = basic_struct.u32 * 2; + sat.later_string = "ⓣⓔⓡⓜⓘⓝⓐⓣⓞⓡ"; + for (uint64_t i = 0; i < fidljstest::ARRRR_SIZE; ++i) { + sat.arrrr[i] = static_cast<int32_t>(i * 5) - 10; + } + sat.nullable_vector_of_string0 = nullptr; + std::vector<std::string> vector_of_str; + vector_of_str.push_back("passed_str0"); + vector_of_str.push_back("passed_str1"); + sat.nullable_vector_of_string1.reset(std::move(vector_of_str)); + std::vector<fidljstest::Blorp> vector_of_blorp; + vector_of_blorp.push_back(fidljstest::Blorp::GAMMA); + vector_of_blorp.push_back(fidljstest::Blorp::BETA); + vector_of_blorp.push_back(fidljstest::Blorp::BETA); + vector_of_blorp.push_back(fidljstest::Blorp::ALPHA); + sat.vector_of_blorp = std::move(vector_of_blorp); + + resp(std::move(sat)); + } + + void PassHandles(zx::job job, PassHandlesCallback callback) override { + EXPECT_EQ(GetKoidForHandle(job), GetKoidForHandle(*zx::job::default_job())); + zx::process process; + ASSERT_EQ(zx::process::self()->duplicate(ZX_RIGHT_SAME_RIGHTS, &process), + ZX_OK); + callback(std::move(process)); + } + + void ReceiveUnions(fidljstest::StructOfMultipleUnions somu) override { + EXPECT_TRUE(somu.initial.is_swb()); + EXPECT_TRUE(somu.initial.swb().some_bool); + + EXPECT_TRUE(somu.optional.get()); + EXPECT_TRUE(somu.optional->is_lswa()); + for (int i = 0; i < 32; ++i) { + EXPECT_EQ(somu.optional->lswa().components[i], i * 99); + } + + EXPECT_TRUE(somu.trailing.is_swu()); + EXPECT_EQ(somu.trailing.swu().num, 123456u); + + did_receive_union_ = true; + } + + void SendUnions(SendUnionsCallback callback) override { + fidljstest::StructOfMultipleUnions resp; + + resp.initial.set_swb(fidljstest::StructWithBool()); + resp.initial.swb().some_bool = true; + + resp.optional = std::make_unique<fidljstest::UnionOfStructs>(); + resp.optional->set_swu(fidljstest::StructWithUint()); + resp.optional->swu().num = 987654; + + resp.trailing.set_lswa(fidljstest::LargerStructWithArray()); + + callback(std::move(resp)); + } + + void SendVectorsOfString(std::vector<std::string> unsized, + std::vector<fidl::StringPtr> nullable, + std::vector<std::string> max_strlen) override { + ASSERT_EQ(unsized.size(), 3u); + EXPECT_EQ(unsized[0], "str0"); + EXPECT_EQ(unsized[1], "str1"); + EXPECT_EQ(unsized[2], "str2"); + + ASSERT_EQ(nullable.size(), 5u); + EXPECT_EQ(nullable[0], "str3"); + EXPECT_TRUE(nullable[1].is_null()); + EXPECT_TRUE(nullable[2].is_null()); + EXPECT_TRUE(nullable[3].is_null()); + EXPECT_EQ(nullable[4], "str4"); + + ASSERT_EQ(max_strlen.size(), 1u); + EXPECT_EQ(max_strlen[0], "0123456789"); + + did_get_vectors_of_string_ = true; + } + + void VectorOfStruct(std::vector<fidljstest::StructWithUint> stuff, + VectorOfStructCallback callback) override { + ASSERT_EQ(stuff.size(), 4u); + EXPECT_EQ(stuff[0].num, 456u); + EXPECT_EQ(stuff[1].num, 789u); + EXPECT_EQ(stuff[2].num, 123u); + EXPECT_EQ(stuff[3].num, 0xfffffu); + + std::vector<fidljstest::StructWithUint> response; + fidljstest::StructWithUint a; + a.num = 369; + response.push_back(a); + fidljstest::StructWithUint b; + b.num = 258; + response.push_back(b); + callback(std::move(response)); + } + + void PassVectorOfPrimitives( + fidljstest::VectorsOfPrimitives input, + PassVectorOfPrimitivesCallback callback) override { + ASSERT_EQ(input.v_bool.size(), 1u); + ASSERT_EQ(input.v_uint8.size(), 2u); + ASSERT_EQ(input.v_uint16.size(), 3u); + ASSERT_EQ(input.v_uint32.size(), 4u); + ASSERT_EQ(input.v_uint64.size(), 5u); + ASSERT_EQ(input.v_int8.size(), 6u); + ASSERT_EQ(input.v_int16.size(), 7u); + ASSERT_EQ(input.v_int32.size(), 8u); + ASSERT_EQ(input.v_int64.size(), 9u); + ASSERT_EQ(input.v_float32.size(), 10u); + ASSERT_EQ(input.v_float64.size(), 11u); + + EXPECT_EQ(input.v_bool[0], true); + + EXPECT_EQ(input.v_uint8[0], 2u); + EXPECT_EQ(input.v_uint8[1], 3u); + + EXPECT_EQ(input.v_uint16[0], 4u); + EXPECT_EQ(input.v_uint16[1], 5u); + EXPECT_EQ(input.v_uint16[2], 6u); + + EXPECT_EQ(input.v_uint32[0], 7u); + EXPECT_EQ(input.v_uint32[1], 8u); + EXPECT_EQ(input.v_uint32[2], 9u); + EXPECT_EQ(input.v_uint32[3], 10u); + + EXPECT_EQ(input.v_uint64[0], 11u); + EXPECT_EQ(input.v_uint64[1], 12u); + EXPECT_EQ(input.v_uint64[2], 13u); + EXPECT_EQ(input.v_uint64[3], 14u); + EXPECT_EQ(input.v_uint64[4], 0xffffffffffffff00ULL); + + EXPECT_EQ(input.v_int8[0], -16); + EXPECT_EQ(input.v_int8[1], -17); + EXPECT_EQ(input.v_int8[2], -18); + EXPECT_EQ(input.v_int8[3], -19); + EXPECT_EQ(input.v_int8[4], -20); + EXPECT_EQ(input.v_int8[5], -21); + + EXPECT_EQ(input.v_int16[0], -22); + EXPECT_EQ(input.v_int16[1], -23); + EXPECT_EQ(input.v_int16[2], -24); + EXPECT_EQ(input.v_int16[3], -25); + EXPECT_EQ(input.v_int16[4], -26); + EXPECT_EQ(input.v_int16[5], -27); + EXPECT_EQ(input.v_int16[6], -28); + + EXPECT_EQ(input.v_int32[0], -29); + EXPECT_EQ(input.v_int32[1], -30); + EXPECT_EQ(input.v_int32[2], -31); + EXPECT_EQ(input.v_int32[3], -32); + EXPECT_EQ(input.v_int32[4], -33); + EXPECT_EQ(input.v_int32[5], -34); + EXPECT_EQ(input.v_int32[6], -35); + EXPECT_EQ(input.v_int32[7], -36); + + EXPECT_EQ(input.v_int64[0], -37); + EXPECT_EQ(input.v_int64[1], -38); + EXPECT_EQ(input.v_int64[2], -39); + EXPECT_EQ(input.v_int64[3], -40); + EXPECT_EQ(input.v_int64[4], -41); + EXPECT_EQ(input.v_int64[5], -42); + EXPECT_EQ(input.v_int64[6], -43); + EXPECT_EQ(input.v_int64[7], -44); + EXPECT_EQ(input.v_int64[8], -0x7fffffffffffffffLL); + + EXPECT_EQ(input.v_float32[0], 46.f); + EXPECT_EQ(input.v_float32[1], 47.f); + EXPECT_EQ(input.v_float32[2], 48.f); + EXPECT_EQ(input.v_float32[3], 49.f); + EXPECT_EQ(input.v_float32[4], 50.f); + EXPECT_EQ(input.v_float32[5], 51.f); + EXPECT_EQ(input.v_float32[6], 52.f); + EXPECT_EQ(input.v_float32[7], 53.f); + EXPECT_EQ(input.v_float32[8], 54.f); + EXPECT_EQ(input.v_float32[9], 55.f); + + EXPECT_EQ(input.v_float64[0], 56.0); + EXPECT_EQ(input.v_float64[1], 57.0); + EXPECT_EQ(input.v_float64[2], 58.0); + EXPECT_EQ(input.v_float64[3], 59.0); + EXPECT_EQ(input.v_float64[4], 60.0); + EXPECT_EQ(input.v_float64[5], 61.0); + EXPECT_EQ(input.v_float64[6], 62.0); + EXPECT_EQ(input.v_float64[7], 63.0); + EXPECT_EQ(input.v_float64[8], 64.0); + EXPECT_EQ(input.v_float64[9], 65.0); + EXPECT_EQ(input.v_float64[10], 66.0); + + fidljstest::VectorsOfPrimitives output = std::move(input); +#define INC_OUTPUT_ARRAY(v) \ + for (size_t i = 0; i < output.v.size(); ++i) { \ + output.v[i] += 10; \ + } + INC_OUTPUT_ARRAY(v_uint8); + INC_OUTPUT_ARRAY(v_uint16); + INC_OUTPUT_ARRAY(v_uint32); + INC_OUTPUT_ARRAY(v_uint64); + INC_OUTPUT_ARRAY(v_int8); + INC_OUTPUT_ARRAY(v_int16); + INC_OUTPUT_ARRAY(v_int32); + INC_OUTPUT_ARRAY(v_int64); + INC_OUTPUT_ARRAY(v_float32); + INC_OUTPUT_ARRAY(v_float64); +#undef INC_OUTPUT_ARRAY + + callback(std::move(output)); + } + + void PassVectorOfVMO(fidljstest::VectorOfHandleToVMO input, + PassVectorOfVMOCallback callback) override { + callback(std::move(input)); + } + + bool was_do_something_called() const { return was_do_something_called_; } + int32_t received_int() const { return received_int_; } + const std::string& received_msg() const { return received_msg_; } + + fidljstest::Blorp various_blorp() const { return various_blorp_; } + const std::string& various_msg() const { return various_msg_; } + const std::vector<uint32_t>& various_stuff() const { return various_stuff_; } + + fidljstest::BasicStruct GetReceivedStruct() const { return basic_struct_; } + + bool did_receive_union() const { return did_receive_union_; } + + bool did_get_vectors_of_string() const { return did_get_vectors_of_string_; } + + void CallResponseCallbacks() { + for (auto& cb : response_callbacks_) { + std::move(cb).Run(); + } + response_callbacks_.clear(); + } + + void GetAnother( + fidl::InterfaceRequest<fidljstest::AnotherInterface> request) override { + another_interface_impl_ = + std::make_unique<AnotherInterfaceImpl>(std::move(request)); + } + + private: + bool was_do_something_called_ = false; + int32_t received_int_ = -1; + std::string received_msg_; + fidljstest::Blorp various_blorp_; + std::string various_msg_; + std::vector<uint32_t> various_stuff_; + fidljstest::BasicStruct basic_struct_; + std::vector<base::OnceClosure> response_callbacks_; + bool did_receive_union_ = false; + bool did_get_vectors_of_string_ = false; + std::unique_ptr<AnotherInterfaceImpl> another_interface_impl_; + + DISALLOW_COPY_AND_ASSIGN(TestolaImpl); +}; + +TEST_F(FidlGenJsTest, RawReceiveFidlMessage) { + v8::Isolate* isolate = instance_->isolate(); + BindingsSetupHelper helper(isolate); + + // Send the data from the JS side into the channel. + std::string source = R"( + var proxy = new TestolaProxy(); + proxy.$bind(testHandle); + proxy.DoSomething(); + )"; + helper.runner().Run(source, "test.js"); + + // Read it out, decode, and confirm it was dispatched. + TestolaImpl testola_impl; + fidljstest::Testola_Stub stub(&testola_impl); + uint8_t data[1024]; + zx_handle_t handles[1]; + uint32_t actual_bytes, actual_handles; + ASSERT_EQ( + helper.server().rea2(0, data, handles, base::size(data), + base::size(handles), &actual_bytes, &actual_handles), + ZX_OK); + EXPECT_EQ(actual_bytes, 16u); + EXPECT_EQ(actual_handles, 0u); + + fidl::Message message( + fidl::BytePart(data, actual_bytes, actual_bytes), + fidl::HandlePart(handles, actual_handles, actual_handles)); + stub.Dispatch_(std::move(message), fidl::internal::PendingResponse()); + + EXPECT_TRUE(testola_impl.was_do_something_called()); +} + +TEST_F(FidlGenJsTest, RawReceiveFidlMessageWithSimpleArg) { + v8::Isolate* isolate = instance_->isolate(); + BindingsSetupHelper helper(isolate); + + // Send the data from the JS side into the channel. + std::string source = R"( + var proxy = new TestolaProxy(); + proxy.$bind(testHandle); + proxy.PrintInt(12345); + )"; + helper.runner().Run(source, "test.js"); + + // Read it out, decode, and confirm it was dispatched. + TestolaImpl testola_impl; + fidljstest::Testola_Stub stub(&testola_impl); + uint8_t data[1024]; + zx_handle_t handles[1]; + uint32_t actual_bytes, actual_handles; + ASSERT_EQ( + helper.server().rea2(0, data, handles, base::size(data), + base::size(handles), &actual_bytes, &actual_handles), + ZX_OK); + // 24 rather than 20 because everything's 8 aligned. + EXPECT_EQ(actual_bytes, 24u); + EXPECT_EQ(actual_handles, 0u); + + fidl::Message message( + fidl::BytePart(data, actual_bytes, actual_bytes), + fidl::HandlePart(handles, actual_handles, actual_handles)); + stub.Dispatch_(std::move(message), fidl::internal::PendingResponse()); + + EXPECT_EQ(testola_impl.received_int(), 12345); +} + +TEST_F(FidlGenJsTest, RawReceiveFidlMessageWithStringArg) { + v8::Isolate* isolate = instance_->isolate(); + BindingsSetupHelper helper(isolate); + + // Send the data from the JS side into the channel. + std::string source = R"( + var proxy = new TestolaProxy(); + proxy.$bind(testHandle); + proxy.PrintMsg('Ça c\'est a 你好 from deep in JS'); + )"; + helper.runner().Run(source, "test.js"); + + // Read it out, decode, and confirm it was dispatched. + TestolaImpl testola_impl; + fidljstest::Testola_Stub stub(&testola_impl); + uint8_t data[1024]; + zx_handle_t handles[1]; + uint32_t actual_bytes, actual_handles; + ASSERT_EQ( + helper.server().rea2(0, data, handles, base::size(data), + base::size(handles), &actual_bytes, &actual_handles), + ZX_OK); + EXPECT_EQ(actual_handles, 0u); + + fidl::Message message( + fidl::BytePart(data, actual_bytes, actual_bytes), + fidl::HandlePart(handles, actual_handles, actual_handles)); + stub.Dispatch_(std::move(message), fidl::internal::PendingResponse()); + + EXPECT_EQ(testola_impl.received_msg(), "Ça c'est a 你好 from deep in JS"); +} + +TEST_F(FidlGenJsTest, RawReceiveFidlMessageWithMultipleArgs) { + v8::Isolate* isolate = instance_->isolate(); + BindingsSetupHelper helper(isolate); + + // Send the data from the JS side into the channel. + std::string source = R"( + var proxy = new TestolaProxy(); + proxy.$bind(testHandle); + proxy.VariousArgs(Blorp.GAMMA, 'zippy zap', [ 999, 987, 123456 ]); + )"; + helper.runner().Run(source, "test.js"); + + // Read it out, decode, and confirm it was dispatched. + TestolaImpl testola_impl; + fidljstest::Testola_Stub stub(&testola_impl); + uint8_t data[1024]; + zx_handle_t handles[1]; + uint32_t actual_bytes, actual_handles; + ASSERT_EQ( + helper.server().rea2(0, data, handles, base::size(data), + base::size(handles), &actual_bytes, &actual_handles), + ZX_OK); + EXPECT_EQ(actual_handles, 0u); + + fidl::Message message( + fidl::BytePart(data, actual_bytes, actual_bytes), + fidl::HandlePart(handles, actual_handles, actual_handles)); + stub.Dispatch_(std::move(message), fidl::internal::PendingResponse()); + + EXPECT_EQ(testola_impl.various_blorp(), fidljstest::Blorp::GAMMA); + EXPECT_EQ(testola_impl.various_msg(), "zippy zap"); + ASSERT_EQ(testola_impl.various_stuff().size(), 3u); + EXPECT_EQ(testola_impl.various_stuff()[0], 999u); + EXPECT_EQ(testola_impl.various_stuff()[1], 987u); + EXPECT_EQ(testola_impl.various_stuff()[2], 123456u); +} + +TEST_F(FidlGenJsTest, RawWithResponse) { + v8::Isolate* isolate = instance_->isolate(); + BindingsSetupHelper helper(isolate); + + TestolaImpl testola_impl; + fidl::Binding<fidljstest::Testola> binding(&testola_impl); + binding.Bind(std::move(helper.server())); + + // Send the data from the JS side into the channel. + std::string source = R"( + var proxy = new TestolaProxy(); + proxy.$bind(testHandle); + this.sum_result = -1; + proxy.WithResponse(72, 99) + .then(sum => { + this.sum_result = sum; + }) + .catch((e) => log('FAILED: ' + e)); + )"; + helper.runner().Run(source, "test.js"); + + base::RunLoop().RunUntilIdle(); + + testola_impl.CallResponseCallbacks(); + + base::RunLoop().RunUntilIdle(); + + // Confirm that the response was received with the correct value. + auto sum_result = helper.Get<int>("sum_result"); + EXPECT_EQ(sum_result, 72 + 99); +} + +TEST_F(FidlGenJsTest, NoResponseBeforeTearDown) { + v8::Isolate* isolate = instance_->isolate(); + + BindingsSetupHelper helper(isolate); + + TestolaImpl testola_impl; + fidl::Binding<fidljstest::Testola> binding(&testola_impl); + binding.Bind(std::move(helper.server())); + + // Send the data from the JS side into the channel. + std::string source = R"( + var proxy = new TestolaProxy(); + proxy.$bind(testHandle); + this.resolved = false; + this.rejected = false; + this.excepted = false; + proxy.WithResponse(1, 2) + .then(sum => { + this.resolved = true; + }, () => { + this.rejected = true; + }) + .catch((e) => { + log('FAILED: ' + e); + this.excepted = true; + }) + )"; + helper.runner().Run(source, "test.js"); + + // Run the message loop to read and queue the request, but don't send the + // response. + base::RunLoop().RunUntilIdle(); + + // This causes outstanding waits to be canceled. + helper.DestroyBindingsForTesting(); + + EXPECT_FALSE(helper.Get<bool>("resolved")); + EXPECT_TRUE(helper.Get<bool>("rejected")); + EXPECT_FALSE(helper.Get<bool>("excepted")); +} + +TEST_F(FidlGenJsTest, RawReceiveFidlStructMessage) { + v8::Isolate* isolate = instance_->isolate(); + BindingsSetupHelper helper(isolate); + + TestolaImpl testola_impl; + fidl::Binding<fidljstest::Testola> binding(&testola_impl); + binding.Bind(std::move(helper.server())); + + // Send the data from the JS side into the channel. + std::string source = R"( + var proxy = new TestolaProxy(); + proxy.$bind(testHandle); + var basicStruct = new BasicStruct( + true, -30, undefined, -789, 200, 65000, 0); + proxy.SendAStruct(basicStruct); + )"; + helper.runner().Run(source, "test.js"); + + // Run the dispatcher to read and dispatch the response. + base::RunLoop().RunUntilIdle(); + + fidljstest::BasicStruct received_struct = testola_impl.GetReceivedStruct(); + EXPECT_EQ(received_struct.b, true); + EXPECT_EQ(received_struct.i8, -30); + EXPECT_EQ(received_struct.i16, 18); // From defaults. + EXPECT_EQ(received_struct.i32, -789); + EXPECT_EQ(received_struct.u8, 200); + EXPECT_EQ(received_struct.u16, 65000); + // Make sure this didn't get defaulted, even though it has a false-ish value. + EXPECT_EQ(received_struct.u32, 0u); +} + +TEST_F(FidlGenJsTest, RawReceiveFidlNestedStructsAndRespond) { + v8::Isolate* isolate = instance_->isolate(); + BindingsSetupHelper helper(isolate); + + TestolaImpl testola_impl; + fidl::Binding<fidljstest::Testola> binding(&testola_impl); + binding.Bind(std::move(helper.server())); + + // Send the data from the JS side into the channel. + std::string source = R"( + var proxy = new TestolaProxy(); + proxy.$bind(testHandle); + var toSend = new BasicStruct(false, -5, -6, -7, 8, 32000, 2000000000); + proxy.NestedStructsWithResponse(toSend) + .then(sat => { + this.result_count = sat.count; + this.result_id = sat.id; + this.result_vector = sat.a_vector; + this.result_basic_b = sat.basic.b; + this.result_basic_i8 = sat.basic.i8; + this.result_basic_i16 = sat.basic.i16; + this.result_basic_i32 = sat.basic.i32; + this.result_basic_u8 = sat.basic.u8; + this.result_basic_u16 = sat.basic.u16; + this.result_basic_u32 = sat.basic.u32; + this.result_later_string = sat.later_string; + this.result_arrrr = sat.arrrr; + this.result_vs0 = sat.nullable_vector_of_string0; + this.result_vs1 = sat.nullable_vector_of_string1; + this.result_vblorp = sat.vector_of_blorp; + }) + .catch((e) => log('FAILED: ' + e)); + )"; + helper.runner().Run(source, "test.js"); + + // Run the message loop to read the request and write the response. + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(helper.Get<int>("result_count"), 123); + EXPECT_EQ(helper.Get<std::string>("result_id"), "here is my id"); + auto result_vector = helper.Get<std::vector<int>>("result_vector"); + ASSERT_EQ(result_vector.size(), 4u); + EXPECT_EQ(result_vector[0], 1); + EXPECT_EQ(result_vector[1], -2); + EXPECT_EQ(result_vector[2], 4); + EXPECT_EQ(result_vector[3], -8); + EXPECT_EQ(helper.Get<bool>("result_basic_b"), true); + EXPECT_EQ(helper.Get<int>("result_basic_i8"), -10); + EXPECT_EQ(helper.Get<int>("result_basic_i16"), -12); + EXPECT_EQ(helper.Get<int>("result_basic_i32"), -14); + EXPECT_EQ(helper.Get<unsigned int>("result_basic_u8"), 16u); + EXPECT_EQ(helper.Get<unsigned int>("result_basic_u16"), 64000u); + EXPECT_EQ(helper.Get<unsigned int>("result_basic_u32"), 4000000000u); + EXPECT_EQ(helper.Get<std::string>("result_later_string"), "ⓣⓔⓡⓜⓘⓝⓐⓣⓞⓡ"); + // Retrieve as a vector as there's no difference in representation in JS (and + // gin already supports vector), and verify the length matches the expected + // length of the fidl array. + auto result_arrrr = helper.Get<std::vector<int32_t>>("result_arrrr"); + ASSERT_EQ(result_arrrr.size(), fidljstest::ARRRR_SIZE); + for (uint64_t i = 0; i < fidljstest::ARRRR_SIZE; ++i) { + EXPECT_EQ(result_arrrr[i], static_cast<int32_t>(i * 5) - 10); + } + EXPECT_TRUE(helper.IsNull("result_vs0")); + EXPECT_FALSE(helper.IsNull("result_vs1")); + auto result_vs1 = helper.Get<std::vector<std::string>>("result_vs1"); + ASSERT_EQ(result_vs1.size(), 2u); + EXPECT_EQ(result_vs1[0], "passed_str0"); + EXPECT_EQ(result_vs1[1], "passed_str1"); + + // This is a vector of enum class fidljstest::Blorp, but gin can't retrieve + // those, so just get it as int, and cast to check values. + auto result_vblorp = helper.Get<std::vector<int>>("result_vblorp"); + ASSERT_EQ(result_vblorp.size(), 4u); + EXPECT_EQ(result_vblorp[0], static_cast<int>(fidljstest::Blorp::GAMMA)); + EXPECT_EQ(result_vblorp[1], static_cast<int>(fidljstest::Blorp::BETA)); + EXPECT_EQ(result_vblorp[2], static_cast<int>(fidljstest::Blorp::BETA)); + EXPECT_EQ(result_vblorp[3], static_cast<int>(fidljstest::Blorp::ALPHA)); +} + +TEST_F(FidlGenJsTest, HandlePassing) { + v8::Isolate* isolate = instance_->isolate(); + BindingsSetupHelper helper(isolate); + + TestolaImpl testola_impl; + fidl::Binding<fidljstest::Testola> binding(&testola_impl); + binding.Bind(std::move(helper.server())); + + zx::job default_job_copy; + ASSERT_EQ(zx::job::default_job()->duplicate(ZX_RIGHT_SAME_RIGHTS, + &default_job_copy), + ZX_OK); + helper.runner().global()->Set( + gin::StringToSymbol(isolate, "testJobHandle"), + gin::ConvertToV8(isolate, default_job_copy.get())); + + // TODO(crbug.com/883496): Handles wrapped in Transferrable once MessagePort + // is sorted out, and then stop treating handles as unmanaged |uint32_t|s. + std::string source = R"( + var proxy = new TestolaProxy(); + proxy.$bind(testHandle); + proxy.PassHandles(testJobHandle).then(h => { + this.processHandle = h; + }).catch((e) => log('FAILED: ' + e)); + )"; + helper.runner().Run(source, "test.js"); + + // Run the message loop to send the request and receive a response. + base::RunLoop().RunUntilIdle(); + + zx_handle_t process_handle_back_from_js = + helper.Get<uint32_t>("processHandle"); + EXPECT_EQ(GetKoidForHandle(process_handle_back_from_js), + GetKoidForHandle(*zx::process::self())); + + // Make sure we received the valid handle back correctly, and close it. Not + // stored into a zx::process in case it isn't valid, and to check the return + // value from closing it. + EXPECT_EQ(zx_handle_close(process_handle_back_from_js), ZX_OK); + + // Ensure we didn't pass away our default job, or process self. + EXPECT_NE(GetKoidForHandle(*zx::job::default_job()), ZX_KOID_INVALID); + EXPECT_NE(GetKoidForHandle(*zx::process::self()), ZX_KOID_INVALID); +} + +TEST_F(FidlGenJsTest, UnionSend) { + v8::Isolate* isolate = instance_->isolate(); + BindingsSetupHelper helper(isolate); + + TestolaImpl testola_impl; + fidl::Binding<fidljstest::Testola> binding(&testola_impl); + binding.Bind(std::move(helper.server())); + + std::string source = R"( + var proxy = new TestolaProxy(); + proxy.$bind(testHandle); + var somu = new StructOfMultipleUnions(); + + var swb = new StructWithBool(/*some_bool*/ true); + somu.initial.set_swb(swb); + + var lswa = new LargerStructWithArray([]); + for (var i = 0; i < 32; ++i) { + lswa.components[i] = i * 99; + } + somu.optional.set_lswa(lswa); + + somu.trailing.set_swu(new StructWithUint(123456)); + + proxy.ReceiveUnions(somu); + )"; + helper.runner().Run(source, "test.js"); + + base::RunLoop().RunUntilIdle(); + + // Expectations on the contents of the union are checked in the body of + // TestolaImpl::ReceiveAUnion(). + EXPECT_TRUE(testola_impl.did_receive_union()); +} + +TEST_F(FidlGenJsTest, UnionReceive) { + v8::Isolate* isolate = instance_->isolate(); + BindingsSetupHelper helper(isolate); + + TestolaImpl testola_impl; + fidl::Binding<fidljstest::Testola> binding(&testola_impl); + binding.Bind(std::move(helper.server())); + + std::string source = R"( + var proxy = new TestolaProxy(); + proxy.$bind(testHandle); + proxy.SendUnions().then(resp => { + this.result_initial_is_swb = resp.initial.is_swb(); + this.result_initial_is_swu = resp.initial.is_swu(); + this.result_initial_is_lswa = resp.initial.is_lswa(); + this.result_optional_is_swb = resp.optional.is_swb(); + this.result_optional_is_swu = resp.optional.is_swu(); + this.result_optional_is_lswa = resp.optional.is_lswa(); + this.result_trailing_is_swb = resp.trailing.is_swb(); + this.result_trailing_is_swu = resp.trailing.is_swu(); + this.result_trailing_is_lswa = resp.trailing.is_lswa(); + + this.result_initial_some_bool = resp.initial.swb.some_bool; + this.result_optional_num = resp.optional.swu.num; + }).catch((e) => log('FAILED: ' + e)); + )"; + helper.runner().Run(source, "test.js"); + + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(helper.Get<bool>("result_initial_is_swb")); + EXPECT_FALSE(helper.Get<bool>("result_initial_is_swu")); + EXPECT_FALSE(helper.Get<bool>("result_initial_is_lswa")); + + EXPECT_FALSE(helper.Get<bool>("result_optional_is_swb")); + EXPECT_TRUE(helper.Get<bool>("result_optional_is_swu")); + EXPECT_FALSE(helper.Get<bool>("result_optional_is_lswa")); + + EXPECT_FALSE(helper.Get<bool>("result_trailing_is_swb")); + EXPECT_FALSE(helper.Get<bool>("result_trailing_is_swu")); + EXPECT_TRUE(helper.Get<bool>("result_trailing_is_lswa")); + + EXPECT_TRUE(helper.Get<bool>("result_initial_some_bool")); + EXPECT_EQ(helper.Get<uint32_t>("result_optional_num"), 987654u); +} + +TEST_F(FidlGenJsTest, VariousDefaults) { + v8::Isolate* isolate = instance_->isolate(); + BindingsSetupHelper helper(isolate); + + std::string source = R"( + var temp = new VariousDefaults(); + this.result_blorp = temp.blorp_defaulting_to_beta; + this.result_timestamp = temp.int64_defaulting_to_no_timestamp; + this.result_another_copy = ANOTHER_COPY; + this.result_int64_const = temp.int64_defaulting_to_const; + this.result_string_in_struct = temp.string_with_default; + this.result_string_const = SOME_STRING; + )"; + helper.runner().Run(source, "test.js"); + + EXPECT_EQ(helper.Get<int>("result_blorp"), + static_cast<int>(fidljstest::Blorp::BETA)); + EXPECT_EQ(helper.FromV8BigInt<int64_t>(helper.runner().global()->Get( + gin::StringToV8(isolate, "result_timestamp"))), + fidljstest::NO_TIMESTAMP); + EXPECT_EQ(helper.FromV8BigInt<int64_t>(helper.runner().global()->Get( + gin::StringToV8(isolate, "result_another_copy"))), + fidljstest::ANOTHER_COPY); + EXPECT_EQ(helper.FromV8BigInt<int64_t>(helper.runner().global()->Get( + gin::StringToV8(isolate, "result_int64_const"))), + 0x7fffffffffffff11LL); + EXPECT_EQ(helper.Get<std::string>("result_string_const"), + "a 你好 thing\" containing ' quotes"); + EXPECT_EQ(helper.Get<std::string>("result_string_in_struct"), "stuff"); +} + +TEST_F(FidlGenJsTest, VectorOfStrings) { + v8::Isolate* isolate = instance_->isolate(); + BindingsSetupHelper helper(isolate); + + TestolaImpl testola_impl; + fidl::Binding<fidljstest::Testola> binding(&testola_impl); + binding.Bind(std::move(helper.server())); + + std::string source = R"( + var proxy = new TestolaProxy(); + proxy.$bind(testHandle); + + var v1 = ['str0', 'str1', 'str2']; + var v2 = ['str3', null, null, null, 'str4']; + var v3 = ['0123456789']; // This is the maximum allowed length. + proxy.SendVectorsOfString(v1, v2, v3); + )"; + helper.runner().Run(source, "test.js"); + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(testola_impl.did_get_vectors_of_string()); +} + +TEST_F(FidlGenJsTest, VectorOfStringsTooLongString) { + v8::Isolate* isolate = instance_->isolate(); + BindingsSetupHelper helper(isolate); + + TestolaImpl testola_impl; + fidl::Binding<fidljstest::Testola> binding(&testola_impl); + binding.Bind(std::move(helper.server())); + + std::string source = R"( + var proxy = new TestolaProxy(); + proxy.$bind(testHandle); + + var too_long = ['this string is longer than allowed']; + proxy.SendVectorsOfString([], [], too_long); + this.tried_to_send = true; + )"; + helper.runner().Run(source, "test.js"); + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(helper.Get<bool>("tried_to_send")); + EXPECT_FALSE(testola_impl.did_get_vectors_of_string()); +} + +TEST_F(FidlGenJsTest, VectorOfStruct) { + v8::Isolate* isolate = instance_->isolate(); + BindingsSetupHelper helper(isolate); + + TestolaImpl testola_impl; + fidl::Binding<fidljstest::Testola> binding(&testola_impl); + binding.Bind(std::move(helper.server())); + + std::string source = R"( + var proxy = new TestolaProxy(); + proxy.$bind(testHandle); + + var data = [ + new StructWithUint(456), + new StructWithUint(789), + new StructWithUint(123), + new StructWithUint(0xfffff), + ]; + proxy.VectorOfStruct(data).then(resp => { + this.result_length = resp.length; + this.result_0 = resp[0].num; + this.result_1 = resp[1].num; + }).catch((e) => log('FAILED: ' + e)); + )"; + helper.runner().Run(source, "test.js"); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(helper.Get<uint32_t>("result_length"), 2u); + EXPECT_EQ(helper.Get<int>("result_0"), 369); + EXPECT_EQ(helper.Get<int>("result_1"), 258); +} + +TEST_F(FidlGenJsTest, VectorsOfPrimitives) { + v8::Isolate* isolate = instance_->isolate(); + BindingsSetupHelper helper(isolate); + + TestolaImpl testola_impl; + fidl::Binding<fidljstest::Testola> binding(&testola_impl); + binding.Bind(std::move(helper.server())); + + std::string source = R"( + var proxy = new TestolaProxy(); + proxy.$bind(testHandle); + + var v_bool = [true]; + var v_uint8 = [2, 3]; + var v_uint16 = [4, 5, 6]; + var v_uint32 = [7, 8, 9, 10]; + var v_uint64 = [11, 12, 13, 14, 0xffffffffffffff00n]; + var v_int8 = [-16, -17, -18, -19, -20, -21]; + var v_int16 = [-22, -23, -24, -25, -26, -27, -28]; + var v_int32 = [-29, -30, -31, -32, -33, -34, -35, -36]; + var v_int64 = [-37, -38, -39, -40, -41, -42, -43, -44, + -0x7fffffffffffffffn]; + var v_float32 = [46, 47, 48, 49, 50, 51, 52, 53, 54, 55]; + var v_float64 = [56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66]; + + var data = new VectorsOfPrimitives( + v_bool, + v_uint8, + v_uint16, + v_uint32, + v_uint64, + v_int8, + v_int16, + v_int32, + v_int64, + v_float32, + v_float64); + + proxy.PassVectorOfPrimitives(data).then(resp => { + this.result_v_bool = resp.v_bool; + this.result_v_uint8 = resp.v_uint8; + this.result_v_uint16 = resp.v_uint16; + this.result_v_uint32 = resp.v_uint32; + this.result_v_uint64 = resp.v_uint64; + this.result_v_int8 = resp.v_int8; + this.result_v_int16 = resp.v_int16; + this.result_v_int32 = resp.v_int32; + this.result_v_int64 = resp.v_int64; + this.result_v_float32 = resp.v_float32; + this.result_v_float64 = resp.v_float64; + }).catch((e) => log('FAILED: ' + e)); + )"; + + helper.runner().Run(source, "test.js"); + base::RunLoop().RunUntilIdle(); + + auto result_v_bool = helper.Get<std::vector<bool>>("result_v_bool"); + auto result_v_uint8 = helper.Get<std::vector<unsigned int>>("result_v_uint8"); + auto result_v_uint16 = + helper.Get<std::vector<unsigned int>>("result_v_uint16"); + auto result_v_uint32 = helper.Get<std::vector<uint32_t>>("result_v_uint32"); + auto result_v_uint64 = helper.GetBigIntVector<uint64_t>("result_v_uint64"); + auto result_v_int8 = helper.Get<std::vector<int>>("result_v_int8"); + auto result_v_int16 = helper.Get<std::vector<int>>("result_v_int16"); + auto result_v_int32 = helper.Get<std::vector<int32_t>>("result_v_int32"); + auto result_v_int64 = helper.GetBigIntVector<int64_t>("result_v_int64"); + auto result_v_float32 = helper.Get<std::vector<float>>("result_v_float32"); + auto result_v_float64 = helper.Get<std::vector<double>>("result_v_float64"); + + ASSERT_EQ(result_v_bool.size(), 1u); + ASSERT_EQ(result_v_uint8.size(), 2u); + ASSERT_EQ(result_v_uint16.size(), 3u); + ASSERT_EQ(result_v_uint32.size(), 4u); + ASSERT_EQ(result_v_uint64.size(), 5u); + ASSERT_EQ(result_v_int8.size(), 6u); + ASSERT_EQ(result_v_int16.size(), 7u); + ASSERT_EQ(result_v_int32.size(), 8u); + ASSERT_EQ(result_v_int64.size(), 9u); + ASSERT_EQ(result_v_float32.size(), 10u); + ASSERT_EQ(result_v_float64.size(), 11u); + + // Check that all the responses have had 10 added to them (except bool). + + EXPECT_EQ(result_v_bool[0], true); + + EXPECT_EQ(result_v_uint8[0], 12u); + EXPECT_EQ(result_v_uint8[1], 13u); + + EXPECT_EQ(result_v_uint16[0], 14u); + EXPECT_EQ(result_v_uint16[1], 15u); + EXPECT_EQ(result_v_uint16[2], 16u); + + EXPECT_EQ(result_v_uint32[0], 17u); + EXPECT_EQ(result_v_uint32[1], 18u); + EXPECT_EQ(result_v_uint32[2], 19u); + EXPECT_EQ(result_v_uint32[3], 20u); + + EXPECT_EQ(result_v_uint64[0], 21u); + EXPECT_EQ(result_v_uint64[1], 22u); + EXPECT_EQ(result_v_uint64[2], 23u); + EXPECT_EQ(result_v_uint64[3], 24u); + EXPECT_EQ(result_v_uint64[4], 0xffffffffffffff0aULL); + + EXPECT_EQ(result_v_int8[0], -6); + EXPECT_EQ(result_v_int8[1], -7); + EXPECT_EQ(result_v_int8[2], -8); + EXPECT_EQ(result_v_int8[3], -9); + EXPECT_EQ(result_v_int8[4], -10); + EXPECT_EQ(result_v_int8[5], -11); + + EXPECT_EQ(result_v_int16[0], -12); + EXPECT_EQ(result_v_int16[1], -13); + EXPECT_EQ(result_v_int16[2], -14); + EXPECT_EQ(result_v_int16[3], -15); + EXPECT_EQ(result_v_int16[4], -16); + EXPECT_EQ(result_v_int16[5], -17); + EXPECT_EQ(result_v_int16[6], -18); + + EXPECT_EQ(result_v_int32[0], -19); + EXPECT_EQ(result_v_int32[1], -20); + EXPECT_EQ(result_v_int32[2], -21); + EXPECT_EQ(result_v_int32[3], -22); + EXPECT_EQ(result_v_int32[4], -23); + EXPECT_EQ(result_v_int32[5], -24); + EXPECT_EQ(result_v_int32[6], -25); + EXPECT_EQ(result_v_int32[7], -26); + + EXPECT_EQ(result_v_int64[0], -27); + EXPECT_EQ(result_v_int64[1], -28); + EXPECT_EQ(result_v_int64[2], -29); + EXPECT_EQ(result_v_int64[3], -30); + EXPECT_EQ(result_v_int64[4], -31); + EXPECT_EQ(result_v_int64[5], -32); + EXPECT_EQ(result_v_int64[6], -33); + EXPECT_EQ(result_v_int64[7], -34); + EXPECT_EQ(result_v_int64[8], -0x7ffffffffffffff5LL); + + EXPECT_EQ(result_v_float32[0], 56.f); + EXPECT_EQ(result_v_float32[1], 57.f); + EXPECT_EQ(result_v_float32[2], 58.f); + EXPECT_EQ(result_v_float32[3], 59.f); + EXPECT_EQ(result_v_float32[4], 60.f); + EXPECT_EQ(result_v_float32[5], 61.f); + EXPECT_EQ(result_v_float32[6], 62.f); + EXPECT_EQ(result_v_float32[7], 63.f); + EXPECT_EQ(result_v_float32[8], 64.f); + EXPECT_EQ(result_v_float32[9], 65.f); + + EXPECT_EQ(result_v_float64[0], 66.f); + EXPECT_EQ(result_v_float64[1], 67.f); + EXPECT_EQ(result_v_float64[2], 68.f); + EXPECT_EQ(result_v_float64[3], 69.f); + EXPECT_EQ(result_v_float64[4], 70.f); + EXPECT_EQ(result_v_float64[5], 71.f); + EXPECT_EQ(result_v_float64[6], 72.f); + EXPECT_EQ(result_v_float64[7], 73.f); + EXPECT_EQ(result_v_float64[8], 74.f); + EXPECT_EQ(result_v_float64[9], 75.f); + EXPECT_EQ(result_v_float64[10], 76.f); +} + +TEST_F(FidlGenJsTest, VectorOfHandle) { + v8::Isolate* isolate = instance_->isolate(); + BindingsSetupHelper helper(isolate); + + TestolaImpl testola_impl; + fidl::Binding<fidljstest::Testola> binding(&testola_impl); + binding.Bind(std::move(helper.server())); + + zx::vmo test_vmo0, test_vmo1; + ASSERT_EQ(zx::vmo::create(4096, 0, &test_vmo0), ZX_OK); + ASSERT_EQ(zx::vmo::create(16384, 0, &test_vmo1), ZX_OK); + + // Save to compare on return. + zx_koid_t koid_of_vmo0 = GetKoidForHandle(test_vmo0); + zx_koid_t koid_of_vmo1 = GetKoidForHandle(test_vmo1); + + helper.runner().global()->Set(gin::StringToSymbol(isolate, "vmo0"), + gin::ConvertToV8(isolate, test_vmo0.release())); + helper.runner().global()->Set(gin::StringToSymbol(isolate, "vmo1"), + gin::ConvertToV8(isolate, test_vmo1.release())); + + std::string source = R"( + var proxy = new TestolaProxy(); + proxy.$bind(testHandle); + + proxy.PassVectorOfVMO(new VectorOfHandleToVMO([vmo0, vmo1])).then( + resp => { + this.result_vmo0 = resp.vmos[0]; + this.result_vmo1 = resp.vmos[1]; + }).catch((e) => log('FAILED: ' + e)); + )"; + helper.runner().Run(source, "test.js"); + base::RunLoop().RunUntilIdle(); + + zx_handle_t result_vmo0 = helper.Get<zx_handle_t>("result_vmo0"); + zx_handle_t result_vmo1 = helper.Get<zx_handle_t>("result_vmo1"); + + EXPECT_EQ(GetKoidForHandle(result_vmo0), koid_of_vmo0); + EXPECT_EQ(GetKoidForHandle(result_vmo1), koid_of_vmo1); + + uint64_t size; + ASSERT_EQ(zx_vmo_get_size(result_vmo0, &size), ZX_OK); + EXPECT_EQ(size, 4096u); + ASSERT_EQ(zx_vmo_get_size(result_vmo1, &size), ZX_OK); + EXPECT_EQ(size, 16384u); + + EXPECT_EQ(zx_handle_close(result_vmo0), ZX_OK); + EXPECT_EQ(zx_handle_close(result_vmo1), ZX_OK); +} + +TEST_F(FidlGenJsTest, RequestInterface) { + v8::Isolate* isolate = instance_->isolate(); + BindingsSetupHelper helper(isolate); + + TestolaImpl testola_impl; + fidl::Binding<fidljstest::Testola> binding(&testola_impl); + binding.Bind(std::move(helper.server())); + + std::string source = R"( + var proxy = new TestolaProxy(); + proxy.$bind(testHandle); + + var another_proxy = new AnotherInterfaceProxy(); + + proxy.GetAnother(another_proxy.$request()); + this.is_bound = another_proxy.$is_bound(); + another_proxy.TimesTwo(456).then(resp => { + this.result = resp; + + // TODO(crbug.com/883496): Handle created by $request() must be manually + // closed for now to avoid leaking it. + another_proxy.$close(); + }).catch((e) => log('FAILED: ' + e)); + + // Use the original interface to make sure we didn't break its connection. + proxy.PrintInt(789); + )"; + helper.runner().Run(source, "test.js"); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(helper.Get<int>("result"), 456 * 2); + EXPECT_EQ(testola_impl.received_int(), 789); +} + +int main(int argc, char** argv) { + base::TestSuite test_suite(argc, argv); + + return base::LaunchUnitTests( + argc, argv, + base::BindOnce(&base::TestSuite::Run, base::Unretained(&test_suite))); +} diff --git a/deps/v8/build/fuchsia/fidlgen_js/test/simple.fidl b/deps/v8/build/fuchsia/fidlgen_js/test/simple.fidl new file mode 100644 index 0000000000..18770650fb --- /dev/null +++ b/deps/v8/build/fuchsia/fidlgen_js/test/simple.fidl @@ -0,0 +1,142 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +library fidljstest; + +enum Blorp : int8 { + ALPHA = 1; + BETA = 2; + GAMMA = 0x48; +}; + +// A struct of basic types, some with defaults and some without to test various +// paths of the generator. +struct BasicStruct { + bool b; + int8 i8; + int16 i16 = 18; + int32 i32; + uint8 u8; + uint16 u16; + uint32 u32 = 4000000000; +}; + +const uint64 ARRRR_SIZE = 32; + +struct StuffAndThings { + int32 count; + string id; + vector<int32> a_vector; + BasicStruct basic; + string later_string; + array<int32>:ARRRR_SIZE arrrr; + vector<string>? nullable_vector_of_string0; + vector<string>? nullable_vector_of_string1; + vector<Blorp> vector_of_blorp; +}; + +struct StructWithBool { + bool some_bool = false; +}; + +struct StructWithUint { + uint32 num; +}; + +struct LargerStructWithArray { + array<int32>:32 components; +}; + +union UnionOfStructs { + StructWithBool swb; + StructWithUint swu; + LargerStructWithArray lswa; +}; + +struct StructOfMultipleUnions { + UnionOfStructs initial; + UnionOfStructs? optional; + UnionOfStructs trailing; +}; + +const int64 NO_TIMESTAMP = 0x7fffffffffffffff; +const int64 ANOTHER_COPY = NO_TIMESTAMP; +const string SOME_STRING = "a 你好 thing\" containing ' quotes"; + +struct VariousDefaults { + Blorp blorp_defaulting_to_beta = BETA; + int64 int64_defaulting_to_no_timestamp = NO_TIMESTAMP; + int64 int64_defaulting_to_const = 0x7fffffffffffff11; + string string_with_default = "stuff"; +}; + +struct VectorsOfPrimitives { + vector<bool> v_bool; + vector<uint8> v_uint8; + vector<uint16> v_uint16; + vector<uint32> v_uint32; + vector<uint64> v_uint64; + vector<int8> v_int8; + vector<int16> v_int16; + vector<int32> v_int32; + vector<int64> v_int64; + vector<float32> v_float32; + vector<float64> v_float64; +}; + +struct VectorOfHandleToVMO { + vector<handle<vmo>> vmos; +}; + +// This is a compile-only test for gen.py to ensure that the size of +// AfterPreviousReference is available before the vector<AfterPreviousReference> +// is compiled in this struct. +struct LaterReference { + vector<AfterPreviousReference>? later; +}; + +struct AfterPreviousReference { + int32 an_int; +}; + +protocol AnotherInterface { + TimesTwo(int32 a) -> (int32 b); +}; + +protocol Testola { + DoSomething(); + + PrintInt(int32 num); + + PrintMsg(string msg); + + VariousArgs(Blorp blorp, string:32 msg, vector<uint32> stuff); + + WithResponse(int32 a, int32 b) -> (int32 sum); + + SendAStruct(BasicStruct basic); + + NestedStructsWithResponse(BasicStruct basic) -> (StuffAndThings resp); + + PassHandles(handle<job> job) -> (handle<process> process); + + ReceiveUnions(StructOfMultipleUnions somu); + + SendUnions() -> (StructOfMultipleUnions somu); + + SendVectorsOfString(vector<string> unsized, + vector<string?> nullable, + vector<string:10> max_strlen); + + VectorOfStruct(vector<StructWithUint> stuff) + -> (vector<StructWithUint> result); + + PassVectorOfPrimitives(VectorsOfPrimitives input) + -> (VectorsOfPrimitives output); + + PassVectorOfVMO(VectorOfHandleToVMO input) + -> (VectorOfHandleToVMO output); + + GetAnother(request<AnotherInterface> another); +}; |