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 NodeTestFixture : 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 v8::Isolate* isolate_; 71 SetUpTestCase()72 static void SetUpTestCase() { 73 if (!node_initialized) { 74 uv_os_unsetenv("NODE_OPTIONS"); 75 node_initialized = true; 76 std::vector<std::string> argv { "cctest" }; 77 std::vector<std::string> exec_argv; 78 std::vector<std::string> errors; 79 80 int exitcode = node::InitializeNodeWithArgs(&argv, &exec_argv, &errors); 81 CHECK_EQ(exitcode, 0); 82 CHECK(errors.empty()); 83 } 84 85 tracing_agent = std::make_unique<node::tracing::Agent>(); 86 node::tracing::TraceEventHelper::SetAgent(tracing_agent.get()); 87 node::tracing::TracingController* tracing_controller = 88 tracing_agent->GetTracingController(); 89 CHECK_EQ(0, uv_loop_init(¤t_loop)); 90 static constexpr int kV8ThreadPoolSize = 4; 91 platform.reset( 92 new node::NodePlatform(kV8ThreadPoolSize, tracing_controller)); 93 v8::V8::InitializePlatform(platform.get()); 94 v8::V8::Initialize(); 95 } 96 TearDownTestCase()97 static void TearDownTestCase() { 98 platform->Shutdown(); 99 while (uv_loop_alive(¤t_loop)) { 100 uv_run(¤t_loop, UV_RUN_ONCE); 101 } 102 v8::V8::ShutdownPlatform(); 103 CHECK_EQ(0, uv_loop_close(¤t_loop)); 104 } 105 SetUp()106 void SetUp() override { 107 allocator = ArrayBufferUniquePtr(node::CreateArrayBufferAllocator(), 108 &node::FreeArrayBufferAllocator); 109 isolate_ = NewIsolate(allocator.get(), ¤t_loop, platform.get()); 110 CHECK_NE(isolate_, nullptr); 111 isolate_->Enter(); 112 } 113 TearDown()114 void TearDown() override { 115 platform->DrainTasks(isolate_); 116 isolate_->Exit(); 117 platform->UnregisterIsolate(isolate_); 118 isolate_->Dispose(); 119 isolate_ = nullptr; 120 } 121 }; 122 123 124 class EnvironmentTestFixture : public NodeTestFixture { 125 public: 126 class Env { 127 public: 128 Env(const v8::HandleScope& handle_scope, 129 const Argv& argv, 130 node::EnvironmentFlags::Flags flags = 131 node::EnvironmentFlags::kDefaultFlags) { 132 auto isolate = handle_scope.GetIsolate(); 133 context_ = node::NewContext(isolate); 134 CHECK(!context_.IsEmpty()); 135 context_->Enter(); 136 137 isolate_data_ = node::CreateIsolateData(isolate, 138 &NodeTestFixture::current_loop, 139 platform.get()); 140 CHECK_NE(nullptr, isolate_data_); 141 std::vector<std::string> args(*argv, *argv + 1); 142 std::vector<std::string> exec_args(*argv, *argv + 1); 143 environment_ = node::CreateEnvironment(isolate_data_, 144 context_, 145 args, 146 exec_args, 147 flags); 148 CHECK_NE(nullptr, environment_); 149 } 150 ~Env()151 ~Env() { 152 node::FreeEnvironment(environment_); 153 node::FreeIsolateData(isolate_data_); 154 context_->Exit(); 155 } 156 157 node::Environment* operator*() const { 158 return environment_; 159 } 160 context()161 v8::Local<v8::Context> context() const { 162 return context_; 163 } 164 165 Env(const Env&) = delete; 166 Env& operator=(const Env&) = delete; 167 168 private: 169 v8::Local<v8::Context> context_; 170 node::IsolateData* isolate_data_; 171 node::Environment* environment_; 172 }; 173 }; 174 175 #endif // TEST_CCTEST_NODE_TEST_FIXTURE_H_ 176