• 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 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(&current_loop));
93   }
94 
TearDownTestCase()95   static void TearDownTestCase() {
96     while (uv_loop_alive(&current_loop)) {
97       uv_run(&current_loop, UV_RUN_ONCE);
98     }
99     CHECK_EQ(0, uv_loop_close(&current_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(), &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  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