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 NodeTestEnvironment final : public ::testing::Environment { 64 public: 65 NodeTestEnvironment() = default; 66 void SetUp() override; 67 void TearDown() override; 68 }; 69 70 class NodeTestFixture; 71 72 class NodeZeroIsolateTestFixture : public ::testing::Test { 73 protected: 74 static uv_loop_t current_loop; 75 static bool node_initialized; 76 static ArrayBufferUniquePtr allocator; 77 static NodePlatformUniquePtr platform; 78 static TracingAgentUniquePtr tracing_agent; 79 SetUpTestCase()80 static void SetUpTestCase() { 81 if (!node_initialized) { 82 node_initialized = true; 83 uv_os_unsetenv("NODE_OPTIONS"); 84 std::vector<std::string> argv { "cctest" }; 85 std::vector<std::string> exec_argv; 86 std::vector<std::string> errors; 87 88 int exitcode = node::InitializeNodeWithArgs(&argv, &exec_argv, &errors); 89 CHECK_EQ(exitcode, 0); 90 CHECK(errors.empty()); 91 } 92 CHECK_EQ(0, uv_loop_init(¤t_loop)); 93 } 94 TearDownTestCase()95 static void TearDownTestCase() { 96 while (uv_loop_alive(¤t_loop)) { 97 uv_run(¤t_loop, UV_RUN_ONCE); 98 } 99 CHECK_EQ(0, uv_loop_close(¤t_loop)); 100 } 101 SetUp()102 void SetUp() override { 103 allocator = ArrayBufferUniquePtr(node::CreateArrayBufferAllocator(), 104 &node::FreeArrayBufferAllocator); 105 } 106 107 friend NodeTestEnvironment; 108 friend NodeTestFixture; 109 }; 110 111 112 class NodeTestFixture : public NodeZeroIsolateTestFixture { 113 protected: 114 static 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 protected: 136 static node::IsolateData* isolate_data_; 137 SetUp()138 void SetUp() override { 139 NodeTestFixture::SetUp(); 140 isolate_data_ = node::CreateIsolateData(NodeTestFixture::isolate_, 141 &NodeTestFixture::current_loop, 142 platform.get()); 143 CHECK_NE(nullptr, isolate_data_); 144 } 145 TearDown()146 void TearDown() override { 147 node::FreeIsolateData(isolate_data_); 148 NodeTestFixture::TearDown(); 149 } 150 151 class Env { 152 public: 153 Env(const v8::HandleScope& handle_scope, 154 const Argv& argv, 155 node::EnvironmentFlags::Flags flags = 156 node::EnvironmentFlags::kDefaultFlags) { 157 auto isolate = handle_scope.GetIsolate(); 158 context_ = node::NewContext(isolate); 159 CHECK(!context_.IsEmpty()); 160 context_->Enter(); 161 162 std::vector<std::string> args(*argv, *argv + 1); 163 std::vector<std::string> exec_args(*argv, *argv + 1); 164 DCHECK_EQ(EnvironmentTestFixture::isolate_data_->isolate(), isolate); 165 environment_ = 166 node::CreateEnvironment(EnvironmentTestFixture::isolate_data_, 167 context_, 168 args, 169 exec_args, 170 flags); 171 CHECK_NE(nullptr, environment_); 172 } 173 ~Env()174 ~Env() { 175 node::FreeEnvironment(environment_); 176 context_->Exit(); 177 } 178 179 node::Environment* operator*() const { 180 return environment_; 181 } 182 context()183 v8::Local<v8::Context> context() const { 184 return context_; 185 } 186 187 Env(const Env&) = delete; 188 Env& operator=(const Env&) = delete; 189 190 private: 191 v8::Local<v8::Context> context_; 192 node::Environment* environment_; 193 }; 194 }; 195 196 #endif // TEST_CCTEST_NODE_TEST_FIXTURE_H_ 197