|  | // Copyright 2020 The Fuchsia 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 "tools/fidlcat/lib/code_generator/code_generator.h" | 
|  |  | 
|  | #include <sstream> | 
|  |  | 
|  | #include <gtest/gtest.h> | 
|  |  | 
|  | #include "src/lib/fidl_codec/wire_object.h" | 
|  | #include "src/lib/fidl_codec/wire_types.h" | 
|  | #include "tools/fidlcat/lib/code_generator/test_generator.h" | 
|  |  | 
|  | namespace fidlcat { | 
|  |  | 
|  | TEST(CodeGenerator, ToSnakeCase) { | 
|  | ASSERT_EQ(ToSnakeCase("fidl.examples.echo/EchoString"), "fidl_examples_echo__echo_string"); | 
|  | ASSERT_EQ(ToSnakeCase("EchoString"), "echo_string"); | 
|  | ASSERT_EQ(ToSnakeCase("TheFIDLMessage"), "the_fidlmessage"); | 
|  | } | 
|  |  | 
|  | class CodeGeneratorTest : public ::testing::Test { | 
|  | public: | 
|  | CodeGeneratorTest() { code_generator_.AddFidlHeaderForInterface("fidl.examples.echo"); } | 
|  |  | 
|  | void SetUp() { os_.str(""); } | 
|  |  | 
|  | protected: | 
|  | std::stringstream os_; | 
|  |  | 
|  | fidl_codec::PrettyPrinter printer_ = | 
|  | fidl_codec::PrettyPrinter(os_, fidl_codec::WithoutColors, true, "", 0, false); | 
|  |  | 
|  | CodeGenerator code_generator_; | 
|  | }; | 
|  |  | 
|  | TEST(CodeGenerator, FidlMethodToIncludePath) { | 
|  | ASSERT_EQ(FidlMethodToIncludePath("fidl.examples.echo"), "fidl/examples/echo/cpp/fidl.h"); | 
|  | } | 
|  |  | 
|  | TEST_F(CodeGeneratorTest, GenerateFidlIncludes) { | 
|  | code_generator_.GenerateFidlIncludes(printer_); | 
|  |  | 
|  | std::string expected = "#include <fidl/examples/echo/cpp/fidl.h>\n"; | 
|  | ASSERT_EQ(os_.str(), expected); | 
|  | } | 
|  |  | 
|  | TEST_F(CodeGeneratorTest, GenerateIncludes) { | 
|  | code_generator_.GenerateIncludes(printer_); | 
|  | ASSERT_EQ(os_.str(), | 
|  | "#include <lib/async-loop/cpp/loop.h>\n" | 
|  | "#include <lib/async-loop/default.h>\n" | 
|  | "#include <lib/async/default.h>\n" | 
|  | "#include <lib/syslog/cpp/macros.h>\n" | 
|  | "\n" | 
|  | "#include <gtest/gtest.h>\n" | 
|  | "\n" | 
|  | "#include \"lib/sys/cpp/component_context.h\"\n" | 
|  | "\n" | 
|  | "#include <fidl/examples/echo/cpp/fidl.h>\n" | 
|  | "\n"); | 
|  | } | 
|  |  | 
|  | class TestGeneratorTest : public ::testing::Test { | 
|  | public: | 
|  | TestGeneratorTest() : test_generator_(nullptr, "") { | 
|  | struct_def_input_ = std::make_shared<fidl_codec::Struct>("StructInput"); | 
|  | struct_def_input_->AddMember("base", std::make_unique<fidl_codec::Int64Type>()); | 
|  | struct_def_input_->AddMember("exponent", std::make_unique<fidl_codec::Int64Type>()); | 
|  | payload_def_input_ = | 
|  | std::make_shared<fidl_codec::Payload>(nullptr, nullptr, nullptr, struct_def_input_.get()); | 
|  |  | 
|  | struct_def_output_ = std::make_shared<fidl_codec::Struct>("StructOutput"); | 
|  | struct_def_output_->AddMember("result", std::make_unique<fidl_codec::Int64Type>()); | 
|  | struct_def_output_->AddMember("result_words", std::make_unique<fidl_codec::StringType>()); | 
|  | payload_def_output_ = | 
|  | std::make_shared<fidl_codec::Payload>(nullptr, nullptr, nullptr, struct_def_output_.get()); | 
|  |  | 
|  | zx_handle_t handle_id = 1234; | 
|  | zx_txid_t txid_1 = 1; | 
|  | zx_txid_t txid_2 = 2; | 
|  | zx_txid_t txid_3 = 3; | 
|  | zx_txid_t txid_4 = 4; | 
|  |  | 
|  | struct_input_1_ = std::make_shared<fidl_codec::StructValue>(*struct_def_input_.get()); | 
|  | struct_input_1_->AddField("base", std::make_unique<fidl_codec::IntegerValue>(int64_t(2))); | 
|  | struct_input_1_->AddField("exponent", std::make_unique<fidl_codec::IntegerValue>(int64_t(3))); | 
|  |  | 
|  | call_write_1_ = std::make_shared<FidlCallInfo>( | 
|  | false, "fidl.examples.calculator", handle_id, txid_1, SyscallKind::kChannelWrite, | 
|  | "Exponentiation", payload_def_input_.get(), payload_def_output_.get(), | 
|  | struct_input_1_.get(), nullptr); | 
|  |  | 
|  | struct_input_2_ = std::make_shared<fidl_codec::StructValue>(*struct_def_input_.get()); | 
|  | struct_input_2_->AddField("base", std::make_unique<fidl_codec::IntegerValue>(int64_t(3))); | 
|  | struct_input_2_->AddField("exponent", std::make_unique<fidl_codec::IntegerValue>(int64_t(2))); | 
|  |  | 
|  | call_write_2_ = std::make_shared<FidlCallInfo>( | 
|  | false, "fidl.examples.calculator", handle_id, txid_2, SyscallKind::kChannelWrite, | 
|  | "ExponentiationSlow", payload_def_input_.get(), payload_def_output_.get(), | 
|  | struct_input_2_.get(), nullptr); | 
|  |  | 
|  | struct_output_1_ = std::make_shared<fidl_codec::StructValue>(*struct_def_output_.get()); | 
|  | struct_output_1_->AddField("result", std::make_unique<fidl_codec::IntegerValue>(int64_t(8))); | 
|  | struct_output_1_->AddField("result_words", std::make_unique<fidl_codec::StringValue>("eight")); | 
|  |  | 
|  | call_read_1_ = std::make_shared<FidlCallInfo>( | 
|  | false, "fidl.examples.calculator", handle_id, txid_1, SyscallKind::kChannelRead, | 
|  | "Exponentiation", nullptr, nullptr, nullptr, struct_output_1_.get()); | 
|  |  | 
|  | struct_output_2_ = std::make_shared<fidl_codec::StructValue>(*struct_def_output_.get()); | 
|  | struct_output_2_->AddField("result", std::make_unique<fidl_codec::IntegerValue>(int64_t(9))); | 
|  | struct_output_2_->AddField("result_words", std::make_unique<fidl_codec::StringValue>("nine")); | 
|  |  | 
|  | call_read_2_ = std::make_shared<FidlCallInfo>( | 
|  | false, "fidl.examples.calculator", handle_id, txid_2, SyscallKind::kChannelRead, | 
|  | "ExponentiationSlow", nullptr, nullptr, nullptr, struct_output_2_.get()); | 
|  |  | 
|  | call_sync_ = std::make_shared<FidlCallInfo>(false, "fidl.examples.calculator", handle_id, | 
|  | txid_3, SyscallKind::kChannelCall, "Exponentiation", | 
|  | payload_def_input_.get(), payload_def_output_.get(), | 
|  | struct_input_1_.get(), struct_output_1_.get()); | 
|  |  | 
|  | call_event_ = std::make_shared<FidlCallInfo>( | 
|  | false, "fidl.examples.calculator", handle_id, 0, SyscallKind::kChannelRead, "OnTimeout", | 
|  | nullptr, payload_def_output_.get(), nullptr, struct_output_1_.get()); | 
|  |  | 
|  | call_fire_and_forget_ = std::make_shared<FidlCallInfo>( | 
|  | false, "fidl.examples.calculator", handle_id, txid_4, SyscallKind::kChannelWrite, "TurnOn", | 
|  | payload_def_input_.get(), nullptr, struct_input_1_.get(), nullptr); | 
|  | } | 
|  |  | 
|  | void SetUp() { os_.str(""); } | 
|  |  | 
|  | protected: | 
|  | TestGenerator test_generator_; | 
|  |  | 
|  | std::stringstream os_; | 
|  | fidl_codec::PrettyPrinter printer_ = | 
|  | fidl_codec::PrettyPrinter(os_, fidl_codec::WithoutColors, true, "", 0, false); | 
|  |  | 
|  | std::shared_ptr<fidl_codec::StructValue> struct_input_1_; | 
|  | std::shared_ptr<fidl_codec::StructValue> struct_input_2_; | 
|  | std::shared_ptr<fidl_codec::StructValue> struct_output_1_; | 
|  | std::shared_ptr<fidl_codec::StructValue> struct_output_2_; | 
|  | std::shared_ptr<fidl_codec::Struct> struct_def_input_; | 
|  | std::shared_ptr<fidl_codec::Struct> struct_def_output_; | 
|  | std::shared_ptr<fidl_codec::Payload> payload_def_input_; | 
|  | std::shared_ptr<fidl_codec::Payload> payload_def_output_; | 
|  | std::shared_ptr<FidlCallInfo> call_write_1_; | 
|  | std::shared_ptr<FidlCallInfo> call_read_1_; | 
|  | std::shared_ptr<FidlCallInfo> call_write_2_; | 
|  | std::shared_ptr<FidlCallInfo> call_read_2_; | 
|  | std::shared_ptr<FidlCallInfo> call_sync_; | 
|  | std::shared_ptr<FidlCallInfo> call_event_; | 
|  | std::shared_ptr<FidlCallInfo> call_fire_and_forget_; | 
|  | }; | 
|  |  | 
|  | TEST_F(TestGeneratorTest, GenerateAsyncCall) { | 
|  | // Call fidl.examples.calculator/Exponentiation twice | 
|  | auto pair1 = std::pair<FidlCallInfo*, FidlCallInfo*>(call_write_1_.get(), call_read_1_.get()); | 
|  | auto pair2 = std::pair<FidlCallInfo*, FidlCallInfo*>(call_write_2_.get(), call_read_2_.get()); | 
|  | std::vector<std::pair<FidlCallInfo*, FidlCallInfo*>> async_calls = {pair1, pair2}; | 
|  |  | 
|  | test_generator_.GenerateAsyncCallsFromIterator(printer_, async_calls, async_calls.begin(), | 
|  | "// end of async calls\n", false); | 
|  |  | 
|  | std::string expected = | 
|  | "int64_t in_base_0 = 2;\n" | 
|  | "int64_t in_exponent_0 = 3;\n" | 
|  | "int64_t out_result_0;\n" | 
|  | "std::string out_result_words_0;\n" | 
|  | "proxy_->Exponentiation(in_base_0, in_exponent_0, [this](int64_t out_result_0, std::string " | 
|  | "out_result_words_0) {\n" | 
|  | "  int64_t out_result_0_expected = 8;\n" | 
|  | "  ASSERT_EQ(out_result_0, out_result_0_expected);\n" | 
|  | "\n" | 
|  | "  std::string out_result_words_0_expected = \"eight\";\n" | 
|  | "  ASSERT_EQ(out_result_words_0, out_result_words_0_expected);\n" | 
|  | "\n" | 
|  | "  int64_t in_base_1 = 3;\n" | 
|  | "  int64_t in_exponent_1 = 2;\n" | 
|  | "  int64_t out_result_1;\n" | 
|  | "  std::string out_result_words_1;\n" | 
|  | "  proxy_->ExponentiationSlow(in_base_1, in_exponent_1, [this](int64_t out_result_1, " | 
|  | "std::string " | 
|  | "out_result_words_1) {\n" | 
|  | "    int64_t out_result_1_expected = 9;\n" | 
|  | "    ASSERT_EQ(out_result_1, out_result_1_expected);\n" | 
|  | "\n" | 
|  | "    std::string out_result_words_1_expected = \"nine\";\n" | 
|  | "    ASSERT_EQ(out_result_words_1, out_result_words_1_expected);\n" | 
|  | "\n" | 
|  | "    // end of async calls\n" | 
|  | "  });\n" | 
|  | "});\n"; | 
|  |  | 
|  | EXPECT_EQ(os_.str(), expected); | 
|  | } | 
|  |  | 
|  | TEST_F(TestGeneratorTest, GenerateInputInitializers) { | 
|  | test_generator_.GenerateInputInitializers(printer_, call_write_1_.get()); | 
|  | EXPECT_EQ(os_.str(), | 
|  | "int64_t in_base_0 = 2;\n" | 
|  | "int64_t in_exponent_0 = 3;\n"); | 
|  | } | 
|  |  | 
|  | TEST_F(TestGeneratorTest, GenerateInitializationStruct) { | 
|  | fidl_codec::CppVisitor visitor("my_struct_var"); | 
|  |  | 
|  | auto struct_input_type = | 
|  | std::make_unique<fidl_codec::StructType>(*(struct_def_input_.get()), false); | 
|  |  | 
|  | auto struct_output_type = | 
|  | std::make_unique<fidl_codec::StructType>(*(struct_def_output_.get()), false); | 
|  |  | 
|  | auto struct_dummy_input = std::make_unique<fidl_codec::StructValue>(*struct_def_input_.get()); | 
|  | struct_dummy_input->AddField("base", std::make_unique<fidl_codec::IntegerValue>(int64_t(3))); | 
|  | struct_dummy_input->AddField("exponent", std::make_unique<fidl_codec::IntegerValue>(int64_t(2))); | 
|  |  | 
|  | auto struct_dummy_output = std::make_unique<fidl_codec::StructValue>(*struct_def_output_.get()); | 
|  | struct_dummy_output->AddField("result", std::make_unique<fidl_codec::IntegerValue>(int64_t(8))); | 
|  | struct_dummy_output->AddField("result_words", std::make_unique<fidl_codec::StringValue>("eight")); | 
|  |  | 
|  | auto struct_def_recursive = std::make_shared<fidl_codec::Struct>("struct_recursive"); | 
|  | struct_def_recursive->AddMember("input", std::move(struct_input_type)); | 
|  | struct_def_recursive->AddMember("output", std::move(struct_output_type)); | 
|  |  | 
|  | auto struct_recursive = std::make_shared<fidl_codec::StructValue>(*struct_def_recursive.get()); | 
|  | struct_recursive->AddField("input", std::move(struct_dummy_input)); | 
|  | struct_recursive->AddField("output", std::move(struct_dummy_output)); | 
|  |  | 
|  | auto struct_recursive_type = | 
|  | std::make_unique<fidl_codec::StructType>(*(struct_def_recursive.get()), false); | 
|  | struct_recursive->Visit(&visitor, struct_recursive_type.get()); | 
|  | std::shared_ptr<fidl_codec::CppVariable> cpp_var = visitor.result(); | 
|  |  | 
|  | cpp_var->GenerateInitialization(printer_); | 
|  |  | 
|  | // TODO(nimaj): | 
|  | // Generate literals and avoid creating new variables for int and strings. | 
|  | EXPECT_EQ(os_.str(), | 
|  | "int64_t my_struct_var_input_base = 3;\n" | 
|  | "int64_t my_struct_var_input_exponent = 2;\n" | 
|  | "StructInput my_struct_var_input = { my_struct_var_input_base, " | 
|  | "my_struct_var_input_exponent };\n" | 
|  | "int64_t my_struct_var_output_result = 8;\n" | 
|  | "std::string my_struct_var_output_result_words = \"eight\";\n" | 
|  | "StructOutput my_struct_var_output = { my_struct_var_output_result, " | 
|  | "my_struct_var_output_result_words };\n" | 
|  | "struct_recursive my_struct_var = { my_struct_var_input, my_struct_var_output };\n"); | 
|  | } | 
|  |  | 
|  | TEST_F(TestGeneratorTest, GenerateInitializationVector) { | 
|  | fidl_codec::CppVisitor visitor("my_vector_var"); | 
|  |  | 
|  | auto struct_input_type = | 
|  | std::make_unique<fidl_codec::StructType>(*(struct_def_input_.get()), false); | 
|  |  | 
|  | auto my_vector_type = std::make_shared<fidl_codec::VectorType>(std::move(struct_input_type)); | 
|  |  | 
|  | auto elem_0 = std::make_unique<fidl_codec::StructValue>(*struct_def_input_.get()); | 
|  | elem_0->AddField("base", std::make_unique<fidl_codec::IntegerValue>(int64_t(2))); | 
|  | elem_0->AddField("exponent", std::make_unique<fidl_codec::IntegerValue>(int64_t(3))); | 
|  |  | 
|  | auto elem_1 = std::make_unique<fidl_codec::StructValue>(*struct_def_input_.get()); | 
|  | elem_1->AddField("base", std::make_unique<fidl_codec::IntegerValue>(int64_t(4))); | 
|  | elem_1->AddField("exponent", std::make_unique<fidl_codec::IntegerValue>(int64_t(5))); | 
|  |  | 
|  | auto my_vector_value = std::make_shared<fidl_codec::VectorValue>(); | 
|  | my_vector_value->AddValue(std::move(elem_0)); | 
|  | my_vector_value->AddValue(std::move(elem_1)); | 
|  |  | 
|  | my_vector_value->Visit(&visitor, my_vector_type.get()); | 
|  | std::shared_ptr<fidl_codec::CppVariable> cpp_var = visitor.result(); | 
|  |  | 
|  | cpp_var->GenerateInitialization(printer_); | 
|  |  | 
|  | // TODO(nimaj): | 
|  | // Aim to generate something like this: | 
|  | // std::vector<StructInput> my_vector_var; | 
|  | // my_vector_var.emplace_back({ .base = 2, .exponent = 3 }); | 
|  | // my_vector_var.emplace_back({ .base = 4, .exponent = 5 }); | 
|  | EXPECT_EQ(os_.str(), | 
|  | "int64_t my_vector_var_elem_0_base = 2;\n" | 
|  | "int64_t my_vector_var_elem_0_exponent = 3;\n" | 
|  | "StructInput my_vector_var_elem_0 = { my_vector_var_elem_0_base, " | 
|  | "my_vector_var_elem_0_exponent };\n" | 
|  | "int64_t my_vector_var_elem_1_base = 4;\n" | 
|  | "int64_t my_vector_var_elem_1_exponent = 5;\n" | 
|  | "StructInput my_vector_var_elem_1 = { my_vector_var_elem_1_base, " | 
|  | "my_vector_var_elem_1_exponent };\n" | 
|  | "std::vector<StructInput> my_vector_var = { my_vector_var_elem_0, " | 
|  | "my_vector_var_elem_1 };\n"); | 
|  | } | 
|  |  | 
|  | TEST_F(TestGeneratorTest, GenerateOutputDeclarations) { | 
|  | test_generator_.GenerateOutputDeclarations(printer_, call_read_1_.get()); | 
|  | EXPECT_EQ(os_.str(), | 
|  | "int64_t out_result_0;\n" | 
|  | "std::string out_result_words_0;\n"); | 
|  | } | 
|  |  | 
|  | TEST_F(TestGeneratorTest, CollectArgumentsFromDecodedValue) { | 
|  | std::vector<std::shared_ptr<fidl_codec::CppVariable>> vars1 = | 
|  | test_generator_.CollectArgumentsFromDecodedValue("in_", struct_input_1_.get()); | 
|  |  | 
|  | EXPECT_EQ(vars1[0]->name(), "in_base_0"); | 
|  | EXPECT_EQ(vars1[1]->name(), "in_exponent_0"); | 
|  |  | 
|  | // Variables will have the same prefix, so AcquireUniqueName will bump up the counter | 
|  | std::vector<std::shared_ptr<fidl_codec::CppVariable>> vars2 = | 
|  | test_generator_.CollectArgumentsFromDecodedValue("in_", struct_input_1_.get()); | 
|  |  | 
|  | EXPECT_EQ(vars2[0]->name(), "in_base_1"); | 
|  | EXPECT_EQ(vars2[1]->name(), "in_exponent_1"); | 
|  | } | 
|  |  | 
|  | TEST_F(TestGeneratorTest, AcquireUniqueName) { | 
|  | EXPECT_EQ(test_generator_.AcquireUniqueName("foo"), "foo_0"); | 
|  | EXPECT_EQ(test_generator_.AcquireUniqueName("bar"), "bar_0"); | 
|  | EXPECT_EQ(test_generator_.AcquireUniqueName("foo"), "foo_1"); | 
|  | EXPECT_EQ(test_generator_.AcquireUniqueName("bar"), "bar_1"); | 
|  | } | 
|  |  | 
|  | TEST_F(TestGeneratorTest, GenerateSyncCall) { | 
|  | test_generator_.GenerateSyncCall(printer_, call_sync_.get()); | 
|  |  | 
|  | std::string expected = | 
|  | "int64_t in_base_0 = 2;\n" | 
|  | "int64_t in_exponent_0 = 3;\n" | 
|  | "int64_t out_result_0;\n" | 
|  | "std::string out_result_words_0;\n" | 
|  | "proxy_sync_->Exponentiation(in_base_0, in_exponent_0, &out_result_0, &out_result_words_0);\n" | 
|  | "\n" | 
|  | "int64_t out_result_0_expected = 8;\n" | 
|  | "ASSERT_EQ(out_result_0, out_result_0_expected);\n" | 
|  | "\n" | 
|  | "std::string out_result_words_0_expected = \"eight\";\n" | 
|  | "ASSERT_EQ(out_result_words_0, out_result_words_0_expected);\n"; | 
|  |  | 
|  | EXPECT_EQ(os_.str(), expected); | 
|  | } | 
|  |  | 
|  | TEST_F(TestGeneratorTest, GenerateEvent) { | 
|  | test_generator_.GenerateEvent(printer_, call_event_.get(), "// end of event\n"); | 
|  |  | 
|  | std::string expected = | 
|  | "int64_t out_result_0;\n" | 
|  | "std::string out_result_words_0;\n" | 
|  | "proxy_.events().OnTimeout = [this](int64_t out_result_0, std::string out_result_words_0) " | 
|  | "{\n" | 
|  | "  int64_t out_result_0_expected = 8;\n" | 
|  | "  ASSERT_EQ(out_result_0, out_result_0_expected);\n" | 
|  | "\n" | 
|  | "  std::string out_result_words_0_expected = \"eight\";\n" | 
|  | "  ASSERT_EQ(out_result_words_0, out_result_words_0_expected);\n" | 
|  | "\n" | 
|  | "  // end of event\n" | 
|  | "};\n"; | 
|  |  | 
|  | EXPECT_EQ(os_.str(), expected); | 
|  | } | 
|  |  | 
|  | TEST_F(TestGeneratorTest, GenerateFireAndForget) { | 
|  | test_generator_.GenerateFireAndForget(printer_, call_fire_and_forget_.get()); | 
|  |  | 
|  | std::string expected = | 
|  | "int64_t in_base_0 = 2;\n" | 
|  | "int64_t in_exponent_0 = 3;\n" | 
|  | "proxy_->TurnOn(in_base_0, in_exponent_0);\n"; | 
|  |  | 
|  | EXPECT_EQ(os_.str(), expected); | 
|  | } | 
|  |  | 
|  | TEST_F(TestGeneratorTest, GenerateGroup) { | 
|  | auto pair1 = std::pair<FidlCallInfo*, FidlCallInfo*>(call_write_1_.get(), call_read_1_.get()); | 
|  | auto pair2 = std::pair<FidlCallInfo*, FidlCallInfo*>(call_write_2_.get(), call_read_2_.get()); | 
|  | auto group_1 = std::make_unique<std::vector<std::pair<FidlCallInfo*, FidlCallInfo*>>>(); | 
|  | group_1->push_back(pair1); | 
|  | group_1->push_back(pair2); | 
|  |  | 
|  | auto pair3 = std::pair<FidlCallInfo*, FidlCallInfo*>(nullptr, call_event_.get()); | 
|  | auto group_2 = std::make_unique<std::vector<std::pair<FidlCallInfo*, FidlCallInfo*>>>(); | 
|  | group_2->push_back(pair3); | 
|  |  | 
|  | std::vector<std::unique_ptr<std::vector<std::pair<FidlCallInfo*, FidlCallInfo*>>>> groups; | 
|  | groups.emplace_back(std::move(group_1)); | 
|  | groups.emplace_back(std::move(group_2)); | 
|  |  | 
|  | test_generator_.GenerateGroup(printer_, groups, 0, false); | 
|  |  | 
|  | std::string expected_1 = | 
|  | "void Proxy::group_0() {\n" | 
|  | "  int64_t in_base_0 = 2;\n" | 
|  | "  int64_t in_exponent_0 = 3;\n" | 
|  | "  int64_t out_result_0;\n" | 
|  | "  std::string out_result_words_0;\n" | 
|  | "  proxy_->Exponentiation(in_base_0, in_exponent_0, [this](int64_t " | 
|  | "out_result_0, std::string " | 
|  | "out_result_words_0) {\n" | 
|  | "    int64_t out_result_0_expected = 8;\n" | 
|  | "    ASSERT_EQ(out_result_0, out_result_0_expected);\n" | 
|  | "\n" | 
|  | "    std::string out_result_words_0_expected = \"eight\";\n" | 
|  | "    ASSERT_EQ(out_result_words_0, out_result_words_0_expected);\n" | 
|  | "\n" | 
|  | "    received_0_0_ = true;\n" | 
|  | "    if (received_0_1_) {\n" | 
|  | "      group_1();\n" | 
|  | "    }\n" | 
|  | "  });\n" | 
|  | "  int64_t in_base_1 = 3;\n" | 
|  | "  int64_t in_exponent_1 = 2;\n" | 
|  | "  int64_t out_result_1;\n" | 
|  | "  std::string out_result_words_1;\n" | 
|  | "  proxy_->ExponentiationSlow(in_base_1, in_exponent_1, [this" | 
|  | "](int64_t " | 
|  | "out_result_1, std::string " | 
|  | "out_result_words_1) {\n" | 
|  | "    int64_t out_result_1_expected = 9;\n" | 
|  | "    ASSERT_EQ(out_result_1, out_result_1_expected);\n" | 
|  | "\n" | 
|  | "    std::string out_result_words_1_expected = \"nine\";\n" | 
|  | "    ASSERT_EQ(out_result_words_1, out_result_words_1_expected);\n" | 
|  | "\n" | 
|  | "    received_0_1_ = true;\n" | 
|  | "    if (received_0_0_) {\n" | 
|  | "      group_1();\n" | 
|  | "    }\n" | 
|  | "  });\n" | 
|  | "}\n"; | 
|  |  | 
|  | EXPECT_EQ(os_.str(), expected_1); | 
|  |  | 
|  | os_.str(""); | 
|  |  | 
|  | test_generator_.GenerateGroup(printer_, groups, 1, true); | 
|  |  | 
|  | std::string expected_2 = | 
|  | "\n" | 
|  | "void Proxy::group_1() {\n" | 
|  | "  int64_t out_result_2;\n" | 
|  | "  std::string out_result_words_2;\n" | 
|  | "  proxy_.events().OnTimeout = [this](int64_t out_result_2, std::string " | 
|  | "out_result_words_2) {\n" | 
|  | "    int64_t out_result_2_expected = 8;\n" | 
|  | "    ASSERT_EQ(out_result_2, out_result_2_expected);\n" | 
|  | "\n" | 
|  | "    std::string out_result_words_2_expected = \"eight\";\n" | 
|  | "    ASSERT_EQ(out_result_words_2, out_result_words_2_expected);\n" | 
|  | "\n" | 
|  | "    loop_.Quit();\n" | 
|  | "  };\n" | 
|  | "}\n"; | 
|  |  | 
|  | EXPECT_EQ(os_.str(), expected_2); | 
|  | } | 
|  |  | 
|  | TEST_F(TestGeneratorTest, SplitChannelCallsIntoGroupsOneGroup) { | 
|  | std::vector<FidlCallInfo*> calls; | 
|  | calls.push_back(call_write_1_.get()); | 
|  | calls.push_back(call_write_2_.get()); | 
|  | calls.push_back(call_read_1_.get()); | 
|  | calls.push_back(call_read_2_.get()); | 
|  |  | 
|  | std::vector<std::unique_ptr<std::vector<std::pair<FidlCallInfo*, FidlCallInfo*>>>> groups = | 
|  | test_generator_.SplitChannelCallsIntoGroups(calls); | 
|  |  | 
|  | EXPECT_EQ(groups.size(), 1u); | 
|  | EXPECT_EQ(groups[0]->size(), 2u); | 
|  | EXPECT_EQ(groups[0]->at(0).first, call_write_1_.get()); | 
|  | EXPECT_EQ(groups[0]->at(0).second, call_read_1_.get()); | 
|  | EXPECT_EQ(groups[0]->at(1).first, call_write_2_.get()); | 
|  | EXPECT_EQ(groups[0]->at(1).second, call_read_2_.get()); | 
|  | } | 
|  |  | 
|  | TEST_F(TestGeneratorTest, SplitChannelCallsIntoGroupsTwoGroups) { | 
|  | std::vector<FidlCallInfo*> calls; | 
|  | calls.push_back(call_write_1_.get()); | 
|  | calls.push_back(call_read_1_.get()); | 
|  | calls.push_back(call_write_2_.get()); | 
|  | calls.push_back(call_read_2_.get()); | 
|  |  | 
|  | std::vector<std::unique_ptr<std::vector<std::pair<FidlCallInfo*, FidlCallInfo*>>>> groups = | 
|  | test_generator_.SplitChannelCallsIntoGroups(calls); | 
|  |  | 
|  | EXPECT_EQ(groups.size(), 2u); | 
|  | EXPECT_EQ(groups[0]->size(), 1u); | 
|  | EXPECT_EQ(groups[0]->at(0).first, call_write_1_.get()); | 
|  | EXPECT_EQ(groups[0]->at(0).second, call_read_1_.get()); | 
|  |  | 
|  | EXPECT_EQ(groups[1]->size(), 1u); | 
|  | EXPECT_EQ(groups[1]->at(0).first, call_write_2_.get()); | 
|  | EXPECT_EQ(groups[1]->at(0).second, call_read_2_.get()); | 
|  | } | 
|  |  | 
|  | TEST_F(TestGeneratorTest, GenerateProxy) { | 
|  | auto pair1 = std::pair<FidlCallInfo*, FidlCallInfo*>(call_write_1_.get(), call_read_1_.get()); | 
|  | auto pair2 = std::pair<FidlCallInfo*, FidlCallInfo*>(call_write_2_.get(), call_read_2_.get()); | 
|  | auto group_0 = std::make_unique<std::vector<std::pair<FidlCallInfo*, FidlCallInfo*>>>(); | 
|  | group_0->push_back(pair1); | 
|  | group_0->push_back(pair2); | 
|  |  | 
|  | auto pair3 = std::pair<FidlCallInfo*, FidlCallInfo*>(nullptr, call_event_.get()); | 
|  | auto group_1 = std::make_unique<std::vector<std::pair<FidlCallInfo*, FidlCallInfo*>>>(); | 
|  | group_1->push_back(pair3); | 
|  |  | 
|  | std::vector<std::unique_ptr<std::vector<std::pair<FidlCallInfo*, FidlCallInfo*>>>> groups; | 
|  | groups.emplace_back(std::move(group_0)); | 
|  | groups.emplace_back(std::move(group_1)); | 
|  |  | 
|  | ProxyPrinter pp(printer_, "/path/to/pkg", "Echo", "EchoString", groups); | 
|  | pp.GenerateProxyBooleans(); | 
|  |  | 
|  | // "bool received_1_0_ = false;\n" is skipped because group_1 has only one member | 
|  | EXPECT_EQ(os_.str(), | 
|  | "bool received_0_0_ = false;\n" | 
|  | "bool received_0_1_ = false;\n"); | 
|  |  | 
|  | os_.str(""); | 
|  | pp.GenerateProxyGroupsDecl(); | 
|  | EXPECT_EQ(os_.str(), | 
|  | "void group_0();\n\n" | 
|  | "void group_1();\n"); | 
|  | } | 
|  |  | 
|  | TEST_F(TestGeneratorTest, SplitChannelCallsIntoGroupsEvents) { | 
|  | std::vector<FidlCallInfo*> calls; | 
|  | calls.push_back(call_write_1_.get()); | 
|  | calls.push_back(call_read_1_.get()); | 
|  | calls.push_back(call_write_2_.get()); | 
|  | calls.push_back(call_event_.get()); | 
|  | calls.push_back(call_read_2_.get()); | 
|  |  | 
|  | std::vector<std::unique_ptr<std::vector<std::pair<FidlCallInfo*, FidlCallInfo*>>>> groups = | 
|  | test_generator_.SplitChannelCallsIntoGroups(calls); | 
|  |  | 
|  | EXPECT_EQ(groups.size(), 2u); | 
|  | EXPECT_EQ(groups[0]->size(), 1u); | 
|  | EXPECT_EQ(groups[0]->at(0).first, call_write_1_.get()); | 
|  | EXPECT_EQ(groups[0]->at(0).second, call_read_1_.get()); | 
|  |  | 
|  | EXPECT_EQ(groups[1]->size(), 2u); | 
|  | EXPECT_EQ(groups[1]->at(0).first, call_write_2_.get()); | 
|  | EXPECT_EQ(groups[1]->at(0).second, call_read_2_.get()); | 
|  | EXPECT_EQ(groups[1]->at(1).first, nullptr); | 
|  | EXPECT_EQ(groups[1]->at(1).second, call_event_.get()); | 
|  | } | 
|  |  | 
|  | TEST_F(TestGeneratorTest, SplitChannelCallsIntoGroupsFireAndForget) { | 
|  | std::vector<FidlCallInfo*> calls; | 
|  | calls.push_back(call_fire_and_forget_.get()); | 
|  | calls.push_back(call_write_1_.get()); | 
|  | calls.push_back(call_write_2_.get()); | 
|  | calls.push_back(call_read_2_.get()); | 
|  | calls.push_back(call_read_1_.get()); | 
|  |  | 
|  | std::vector<std::unique_ptr<std::vector<std::pair<FidlCallInfo*, FidlCallInfo*>>>> groups = | 
|  | test_generator_.SplitChannelCallsIntoGroups(calls); | 
|  |  | 
|  | EXPECT_EQ(groups.size(), 2u); | 
|  | EXPECT_EQ(groups[0]->size(), 1u); | 
|  | EXPECT_EQ(groups[0]->at(0).first, call_fire_and_forget_.get()); | 
|  | EXPECT_EQ(groups[0]->at(0).second, nullptr); | 
|  |  | 
|  | EXPECT_EQ(groups[1]->size(), 2u); | 
|  | EXPECT_EQ(groups[1]->at(0).first, call_write_1_.get()); | 
|  | EXPECT_EQ(groups[1]->at(0).second, call_read_1_.get()); | 
|  | EXPECT_EQ(groups[1]->at(1).first, call_write_2_.get()); | 
|  | EXPECT_EQ(groups[1]->at(1).second, call_read_2_.get()); | 
|  | } | 
|  |  | 
|  | }  // namespace fidlcat |