• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #if (__GNUC__ >= 8) && !defined(__clang__)
2 #pragma GCC diagnostic push
3 #pragma GCC diagnostic ignored "-Wcast-function-type"
4 #endif
5 #include "v8.h"
6 #if (__GNUC__ >= 8) && !defined(__clang__)
7 #pragma GCC diagnostic pop
8 #endif
9 #include "aliased_buffer.h"
10 #include "node_test_fixture.h"
11 
12 using node::AliasedBufferBase;
13 
14 class AliasBufferTest : public NodeTestFixture {};
15 
16 template <class NativeT>
CreateOracleValues(std::vector<NativeT> * buf)17 void CreateOracleValues(std::vector<NativeT>* buf) {
18   for (size_t i = 0, j = buf->size(); i < buf->size(); i++, j--) {
19     (*buf)[i] = static_cast<NativeT>(j);
20   }
21 }
22 
23 template <class NativeT, class V8T>
WriteViaOperator(AliasedBufferBase<NativeT,V8T> * aliasedBuffer,const std::vector<NativeT> & oracle)24 void WriteViaOperator(AliasedBufferBase<NativeT, V8T>* aliasedBuffer,
25                       const std::vector<NativeT>& oracle) {
26   // write through the API
27   for (size_t i = 0; i < oracle.size(); i++) {
28     (*aliasedBuffer)[i] = oracle[i];
29   }
30 }
31 
32 template <class NativeT, class V8T>
WriteViaSetValue(AliasedBufferBase<NativeT,V8T> * aliasedBuffer,const std::vector<NativeT> & oracle)33 void WriteViaSetValue(AliasedBufferBase<NativeT, V8T>* aliasedBuffer,
34                       const std::vector<NativeT>& oracle) {
35   // write through the API
36   for (size_t i = 0; i < oracle.size(); i++) {
37     aliasedBuffer->SetValue(i, oracle[i]);
38   }
39 }
40 
41 template <class NativeT, class V8T>
ReadAndValidate(v8::Isolate * isolate,v8::Local<v8::Context> context,AliasedBufferBase<NativeT,V8T> * aliasedBuffer,const std::vector<NativeT> & oracle)42 void ReadAndValidate(v8::Isolate* isolate,
43                      v8::Local<v8::Context> context,
44                      AliasedBufferBase<NativeT, V8T>* aliasedBuffer,
45                      const std::vector<NativeT>& oracle) {
46   // read through the API
47   for (size_t i = 0; i < oracle.size(); i++) {
48     NativeT v1 = (*aliasedBuffer)[i];
49     NativeT v2 = aliasedBuffer->GetValue(i);
50     EXPECT_TRUE(v1 == oracle[i]);
51     EXPECT_TRUE(v2 == oracle[i]);
52   }
53 
54   // validate size of JS Buffer
55   EXPECT_TRUE(aliasedBuffer->GetJSArray()->Length() == oracle.size());
56   EXPECT_TRUE(
57     aliasedBuffer->GetJSArray()->ByteLength() ==
58     (oracle.size() * sizeof(NativeT)));
59 
60   // validate operator * and GetBuffer are the same
61   EXPECT_TRUE(aliasedBuffer->GetNativeBuffer() == *(*aliasedBuffer));
62 
63   // read through the JS API
64   for (size_t i = 0; i < oracle.size(); i++) {
65     v8::Local<V8T> v8TypedArray = aliasedBuffer->GetJSArray();
66     v8::MaybeLocal<v8::Value> v = v8TypedArray->Get(context, i);
67     EXPECT_TRUE(v.IsEmpty() == false);
68     v8::Local<v8::Value> v2 = v.ToLocalChecked();
69     EXPECT_TRUE(v2->IsNumber());
70     v8::MaybeLocal<v8::Number> v3 = v2->ToNumber(context);
71     v8::Local<v8::Number> v4 = v3.ToLocalChecked();
72     NativeT actualValue = static_cast<NativeT>(v4->Value());
73     EXPECT_TRUE(actualValue == oracle[i]);
74   }
75 }
76 
77 template <class NativeT, class V8T>
ReadWriteTest(v8::Isolate * isolate)78 void ReadWriteTest(v8::Isolate* isolate) {
79   v8::Isolate::Scope isolate_scope(isolate);
80   v8::HandleScope handle_scope(isolate);
81   v8::Local<v8::Context> context = v8::Context::New(isolate);
82   v8::Context::Scope context_scope(context);
83 
84   const size_t size = 100;
85   AliasedBufferBase<NativeT, V8T> ab(isolate, size);
86   std::vector<NativeT> oracle(size);
87   CreateOracleValues(&oracle);
88   WriteViaOperator(&ab, oracle);
89   ReadAndValidate(isolate, context, &ab, oracle);
90 
91   WriteViaSetValue(&ab, oracle);
92 
93   // validate copy constructor
94   {
95     AliasedBufferBase<NativeT, V8T> ab2(ab);
96     ReadAndValidate(isolate, context, &ab2, oracle);
97   }
98   ReadAndValidate(isolate, context, &ab, oracle);
99 }
100 
101 template <
102     class NativeT_A, class V8T_A,
103     class NativeT_B, class V8T_B,
104     class NativeT_C, class V8T_C>
SharedBufferTest(v8::Isolate * isolate,size_t count_A,size_t count_B,size_t count_C)105 void SharedBufferTest(
106     v8::Isolate* isolate,
107     size_t count_A,
108     size_t count_B,
109     size_t count_C) {
110   v8::Isolate::Scope isolate_scope(isolate);
111   v8::HandleScope handle_scope(isolate);
112   v8::Local<v8::Context> context = v8::Context::New(isolate);
113   v8::Context::Scope context_scope(context);
114 
115   size_t sizeInBytes_A = count_A * sizeof(NativeT_A);
116   size_t sizeInBytes_B = count_B * sizeof(NativeT_B);
117   size_t sizeInBytes_C = count_C * sizeof(NativeT_C);
118 
119   AliasedBufferBase<uint8_t, v8::Uint8Array> rootBuffer(
120       isolate, sizeInBytes_A + sizeInBytes_B + sizeInBytes_C);
121   AliasedBufferBase<NativeT_A, V8T_A> ab_A(isolate, 0, count_A, rootBuffer);
122   AliasedBufferBase<NativeT_B, V8T_B> ab_B(
123       isolate, sizeInBytes_A, count_B, rootBuffer);
124   AliasedBufferBase<NativeT_C, V8T_C> ab_C(
125       isolate, sizeInBytes_A + sizeInBytes_B, count_C, rootBuffer);
126 
127   std::vector<NativeT_A> oracle_A(count_A);
128   std::vector<NativeT_B> oracle_B(count_B);
129   std::vector<NativeT_C> oracle_C(count_C);
130   CreateOracleValues(&oracle_A);
131   CreateOracleValues(&oracle_B);
132   CreateOracleValues(&oracle_C);
133 
134   WriteViaOperator(&ab_A, oracle_A);
135   WriteViaOperator(&ab_B, oracle_B);
136   WriteViaOperator(&ab_C, oracle_C);
137 
138   ReadAndValidate(isolate, context, &ab_A, oracle_A);
139   ReadAndValidate(isolate, context, &ab_B, oracle_B);
140   ReadAndValidate(isolate, context, &ab_C, oracle_C);
141 
142   WriteViaSetValue(&ab_A, oracle_A);
143   WriteViaSetValue(&ab_B, oracle_B);
144   WriteViaSetValue(&ab_C, oracle_C);
145 
146   ReadAndValidate(isolate, context, &ab_A, oracle_A);
147   ReadAndValidate(isolate, context, &ab_B, oracle_B);
148   ReadAndValidate(isolate, context, &ab_C, oracle_C);
149 }
150 
TEST_F(AliasBufferTest,Uint8Array)151 TEST_F(AliasBufferTest, Uint8Array) {
152   ReadWriteTest<uint8_t, v8::Uint8Array>(isolate_);
153 }
154 
TEST_F(AliasBufferTest,Int8Array)155 TEST_F(AliasBufferTest, Int8Array) {
156   ReadWriteTest<int8_t, v8::Int8Array>(isolate_);
157 }
158 
TEST_F(AliasBufferTest,Uint16Array)159 TEST_F(AliasBufferTest, Uint16Array) {
160   ReadWriteTest<uint16_t, v8::Uint16Array>(isolate_);
161 }
162 
TEST_F(AliasBufferTest,Int16Array)163 TEST_F(AliasBufferTest, Int16Array) {
164   ReadWriteTest<int16_t, v8::Int16Array>(isolate_);
165 }
166 
TEST_F(AliasBufferTest,Uint32Array)167 TEST_F(AliasBufferTest, Uint32Array) {
168   ReadWriteTest<uint32_t, v8::Uint32Array>(isolate_);
169 }
170 
TEST_F(AliasBufferTest,Int32Array)171 TEST_F(AliasBufferTest, Int32Array) {
172   ReadWriteTest<int32_t, v8::Int32Array>(isolate_);
173 }
174 
TEST_F(AliasBufferTest,Float32Array)175 TEST_F(AliasBufferTest, Float32Array) {
176   ReadWriteTest<float, v8::Float32Array>(isolate_);
177 }
178 
TEST_F(AliasBufferTest,Float64Array)179 TEST_F(AliasBufferTest, Float64Array) {
180   ReadWriteTest<double, v8::Float64Array>(isolate_);
181 }
182 
TEST_F(AliasBufferTest,SharedArrayBuffer1)183 TEST_F(AliasBufferTest, SharedArrayBuffer1) {
184   SharedBufferTest<
185       uint32_t, v8::Uint32Array,
186       double, v8::Float64Array,
187       int8_t, v8::Int8Array>(isolate_, 100, 80, 8);
188 }
189 
TEST_F(AliasBufferTest,SharedArrayBuffer2)190 TEST_F(AliasBufferTest, SharedArrayBuffer2) {
191   SharedBufferTest<
192       double, v8::Float64Array,
193       int8_t, v8::Int8Array,
194       double, v8::Float64Array>(isolate_, 100, 8, 8);
195 }
196 
TEST_F(AliasBufferTest,SharedArrayBuffer3)197 TEST_F(AliasBufferTest, SharedArrayBuffer3) {
198   SharedBufferTest<
199       int8_t, v8::Int8Array,
200       int8_t, v8::Int8Array,
201       double, v8::Float64Array>(isolate_, 1, 7, 8);
202 }
203 
TEST_F(AliasBufferTest,SharedArrayBuffer4)204 TEST_F(AliasBufferTest, SharedArrayBuffer4) {
205   SharedBufferTest<
206       int8_t, v8::Int8Array,
207       int8_t, v8::Int8Array,
208       int32_t, v8::Int32Array>(isolate_, 1, 3, 1);
209 }
210 
TEST_F(AliasBufferTest,OperatorOverloads)211 TEST_F(AliasBufferTest, OperatorOverloads) {
212   v8::Isolate::Scope isolate_scope(isolate_);
213   v8::HandleScope handle_scope(isolate_);
214   v8::Local<v8::Context> context = v8::Context::New(isolate_);
215   v8::Context::Scope context_scope(context);
216   const size_t size = 10;
217   AliasedBufferBase<uint32_t, v8::Uint32Array> ab{isolate_, size};
218 
219   EXPECT_EQ(static_cast<uint32_t>(1), ab[0] = 1);
220   EXPECT_EQ(static_cast<uint32_t>(4), ab[0] += 3);
221   EXPECT_EQ(static_cast<uint32_t>(2), ab[0] -= 2);
222   EXPECT_EQ(static_cast<uint32_t>(-2), -ab[0]);
223 }
224 
TEST_F(AliasBufferTest,OperatorOverloadsRefs)225 TEST_F(AliasBufferTest, OperatorOverloadsRefs) {
226   v8::Isolate::Scope isolate_scope(isolate_);
227   v8::HandleScope handle_scope(isolate_);
228   v8::Local<v8::Context> context = v8::Context::New(isolate_);
229   v8::Context::Scope context_scope(context);
230   AliasedBufferBase<uint32_t, v8::Uint32Array> ab{isolate_, 2};
231   using Reference = AliasedBufferBase<uint32_t, v8::Uint32Array>::Reference;
232   Reference ref = ab[0];
233   Reference ref_value = ab[1] = 2;
234 
235   EXPECT_EQ(static_cast<uint32_t>(2), ref = ref_value);
236   EXPECT_EQ(static_cast<uint32_t>(4), ref += ref_value);
237   EXPECT_EQ(static_cast<uint32_t>(2), ref -= ref_value);
238   EXPECT_EQ(static_cast<uint32_t>(-2), -ref);
239 }
240