1 #ifndef TEST_CCTEST_NODE_TEST_FIXTURE_H_ 2 #define TEST_CCTEST_NODE_TEST_FIXTURE_H_ 3 4 #include <cstdlib> 5 #include <memory> 6 #include "gtest/gtest.h" 7 #include "node.h" 8 #include "node_platform.h" 9 #include "node_internals.h" 10 #include "env-inl.h" 11 #include "util-inl.h" 12 #include "v8.h" 13 #include "libplatform/libplatform.h" 14 15 struct Argv { 16 public: ArgvArgv17 Argv() : Argv({"node", "-p", "process.version"}) {} 18 ArgvArgv19 Argv(const std::initializer_list<const char*> &args) { 20 nr_args_ = args.size(); 21 int total_len = 0; 22 for (auto it = args.begin(); it != args.end(); ++it) { 23 total_len += strlen(*it) + 1; 24 } 25 argv_ = static_cast<char**>(malloc(nr_args_ * sizeof(char*))); 26 argv_[0] = static_cast<char*>(malloc(total_len)); 27 int i = 0; 28 int offset = 0; 29 for (auto it = args.begin(); it != args.end(); ++it, ++i) { 30 int len = strlen(*it) + 1; 31 snprintf(argv_[0] + offset, len, "%s", *it); 32 // Skip argv_[0] as it points the correct location already 33 if (i > 0) { 34 argv_[i] = argv_[0] + offset; 35 } 36 offset += len; 37 } 38 } 39 ~ArgvArgv40 ~Argv() { 41 free(argv_[0]); 42 free(argv_); 43 } 44 nr_argsArgv45 int nr_args() const { 46 return nr_args_; 47 } 48 49 char** operator*() const { 50 return argv_; 51 } 52 53 private: 54 char** argv_; 55 int nr_args_; 56 }; 57 58 using ArrayBufferUniquePtr = std::unique_ptr<node::ArrayBufferAllocator, 59 decltype(&node::FreeArrayBufferAllocator)>; 60 using TracingAgentUniquePtr = std::unique_ptr<node::tracing::Agent>; 61 using NodePlatformUniquePtr = std::unique_ptr<node::NodePlatform>; 62 63 class NodeZeroIsolateTestFixture : public ::testing::Test { 64 protected: 65 static ArrayBufferUniquePtr allocator; 66 static TracingAgentUniquePtr tracing_agent; 67 static NodePlatformUniquePtr platform; 68 static uv_loop_t current_loop; 69 static bool node_initialized; 70 SetUpTestCase()71 static void SetUpTestCase() { 72 if (!node_initialized) { 73 uv_os_unsetenv("NODE_OPTIONS"); 74 node_initialized = true; 75 std::vector<std::string> argv { "cctest" }; 76 std::vector<std::string> exec_argv; 77 std::vector<std::string> errors; 78 79 int exitcode = node::InitializeNodeWithArgs(&argv, &exec_argv, &errors); 80 CHECK_EQ(exitcode, 0); 81 CHECK(errors.empty()); 82 } 83 84 tracing_agent = std::make_unique<node::tracing::Agent>(); 85 node::tracing::TraceEventHelper::SetAgent(tracing_agent.get()); 86 node::tracing::TracingController* tracing_controller = 87 tracing_agent->GetTracingController(); 88 CHECK_EQ(0, uv_loop_init(¤t_loop)); 89 static constexpr int kV8ThreadPoolSize = 4; 90 platform.reset( 91 new node::NodePlatform(kV8ThreadPoolSize, tracing_controller)); 92 v8::V8::InitializePlatform(platform.get()); 93 v8::V8::Initialize(); 94 } 95 TearDownTestCase()96 static void TearDownTestCase() { 97 platform->Shutdown(); 98 while (uv_loop_alive(¤t_loop)) { 99 uv_run(¤t_loop, UV_RUN_ONCE); 100 } 101 v8::V8::ShutdownPlatform(); 102 CHECK_EQ(0, uv_loop_close(¤t_loop)); 103 } 104 SetUp()105 void SetUp() override { 106 allocator = ArrayBufferUniquePtr(node::CreateArrayBufferAllocator(), 107 &node::FreeArrayBufferAllocator); 108 } 109 }; 110 111 112 class NodeTestFixture : public NodeZeroIsolateTestFixture { 113 protected: 114 v8::Isolate* isolate_; 115 SetUp()116 void SetUp() override { 117 NodeZeroIsolateTestFixture::SetUp(); 118 isolate_ = NewIsolate(allocator.get(), ¤t_loop, platform.get()); 119 CHECK_NOT_NULL(isolate_); 120 isolate_->Enter(); 121 } 122 TearDown()123 void TearDown() override { 124 platform->DrainTasks(isolate_); 125 isolate_->Exit(); 126 platform->UnregisterIsolate(isolate_); 127 isolate_->Dispose(); 128 isolate_ = nullptr; 129 NodeZeroIsolateTestFixture::TearDown(); 130 } 131 }; 132 133 134 class EnvironmentTestFixture : public NodeTestFixture { 135 public: 136 class Env { 137 public: 138 Env(const v8::HandleScope& handle_scope, 139 const Argv& argv, 140 node::EnvironmentFlags::Flags flags = 141 node::EnvironmentFlags::kDefaultFlags) { 142 auto isolate = handle_scope.GetIsolate(); 143 context_ = node::NewContext(isolate); 144 CHECK(!context_.IsEmpty()); 145 context_->Enter(); 146 147 isolate_data_ = node::CreateIsolateData(isolate, 148 &NodeTestFixture::current_loop, 149 platform.get()); 150 CHECK_NE(nullptr, isolate_data_); 151 std::vector<std::string> args(*argv, *argv + 1); 152 std::vector<std::string> exec_args(*argv, *argv + 1); 153 environment_ = node::CreateEnvironment(isolate_data_, 154 context_, 155 args, 156 exec_args, 157 flags); 158 CHECK_NE(nullptr, environment_); 159 } 160 ~Env()161 ~Env() { 162 node::FreeEnvironment(environment_); 163 node::FreeIsolateData(isolate_data_); 164 context_->Exit(); 165 } 166 167 node::Environment* operator*() const { 168 return environment_; 169 } 170 context()171 v8::Local<v8::Context> context() const { 172 return context_; 173 } 174 175 Env(const Env&) = delete; 176 Env& operator=(const Env&) = delete; 177 178 private: 179 v8::Local<v8::Context> context_; 180 node::IsolateData* isolate_data_; 181 node::Environment* environment_; 182 }; 183 }; 184 185 #endif // TEST_CCTEST_NODE_TEST_FIXTURE_H_ 186