• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&current_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(&current_loop)) {
99       uv_run(&current_loop, UV_RUN_ONCE);
100     }
101     v8::V8::ShutdownPlatform();
102     CHECK_EQ(0, uv_loop_close(&current_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(), &current_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