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