xref: /aosp_15_r20/external/cronet/base/win/scoped_safearray_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2019 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/win/scoped_safearray.h"
6 
7 #include <stddef.h>
8 
9 #include <array>
10 #include <optional>
11 #include <utility>
12 #include <vector>
13 
14 #include "base/test/gtest_util.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
17 namespace base {
18 namespace win {
19 
20 namespace {
21 
22 static constexpr std::array<int, 5> kInputValues = {0, 1, 2, 1, 0};
23 
PopulateScopedSafearrayOfInts(ScopedSafearray & scoped_safe_array)24 static void PopulateScopedSafearrayOfInts(ScopedSafearray& scoped_safe_array) {
25   // TODO(crbug.com/1082005): Create a safer alternative to SAFEARRAY methods.
26   scoped_safe_array.Reset(SafeArrayCreateVector(
27       /*vartype=*/VT_I4, /*lower_bound=*/2,
28       /*element_count=*/kInputValues.size()));
29   ASSERT_NE(scoped_safe_array.Get(), nullptr);
30   ASSERT_EQ(SafeArrayGetDim(scoped_safe_array.Get()), 1U);
31   ASSERT_EQ(scoped_safe_array.GetCount(), kInputValues.size());
32 
33   int* int_array;
34   ASSERT_HRESULT_SUCCEEDED(SafeArrayAccessData(
35       scoped_safe_array.Get(), reinterpret_cast<void**>(&int_array)));
36   for (size_t i = 0; i < kInputValues.size(); ++i)
37     int_array[i] = kInputValues[i];
38   ASSERT_HRESULT_SUCCEEDED(SafeArrayUnaccessData(scoped_safe_array.Get()));
39 }
40 
41 }  // namespace
42 
TEST(ScopedSafearrayTest,ScopedSafearrayMethods)43 TEST(ScopedSafearrayTest, ScopedSafearrayMethods) {
44   ScopedSafearray empty_safe_array;
45   EXPECT_EQ(empty_safe_array.Get(), nullptr);
46   EXPECT_EQ(empty_safe_array.Release(), nullptr);
47   EXPECT_NE(empty_safe_array.Receive(), nullptr);
48 
49   SAFEARRAY* safe_array = SafeArrayCreateVector(
50       VT_R8 /* element type */, 0 /* lower bound */, 4 /* elements */);
51   ScopedSafearray scoped_safe_array(safe_array);
52   EXPECT_EQ(scoped_safe_array.Get(), safe_array);
53   EXPECT_EQ(scoped_safe_array.Release(), safe_array);
54   EXPECT_NE(scoped_safe_array.Receive(), nullptr);
55 
56   // The Release() call should have set the internal pointer to nullptr
57   EXPECT_EQ(scoped_safe_array.Get(), nullptr);
58 
59   scoped_safe_array.Reset(safe_array);
60   EXPECT_EQ(scoped_safe_array.Get(), safe_array);
61 
62   ScopedSafearray moved_safe_array(std::move(scoped_safe_array));
63   EXPECT_EQ(moved_safe_array.Get(), safe_array);
64   EXPECT_EQ(moved_safe_array.Release(), safe_array);
65   EXPECT_NE(moved_safe_array.Receive(), nullptr);
66 
67   // std::move should have cleared the values of scoped_safe_array
68   EXPECT_EQ(scoped_safe_array.Get(), nullptr);
69   EXPECT_EQ(scoped_safe_array.Release(), nullptr);
70   EXPECT_NE(scoped_safe_array.Receive(), nullptr);
71 
72   scoped_safe_array.Reset(safe_array);
73   EXPECT_EQ(scoped_safe_array.Get(), safe_array);
74 
75   ScopedSafearray assigment_moved_safe_array = std::move(scoped_safe_array);
76   EXPECT_EQ(assigment_moved_safe_array.Get(), safe_array);
77   EXPECT_EQ(assigment_moved_safe_array.Release(), safe_array);
78   EXPECT_NE(assigment_moved_safe_array.Receive(), nullptr);
79 
80   // The move-assign operator= should have cleared the values of
81   // scoped_safe_array
82   EXPECT_EQ(scoped_safe_array.Get(), nullptr);
83   EXPECT_EQ(scoped_safe_array.Release(), nullptr);
84   EXPECT_NE(scoped_safe_array.Receive(), nullptr);
85 
86   // Calling Receive() will free the existing reference
87   ScopedSafearray safe_array_received(SafeArrayCreateVector(
88       VT_R8 /* element type */, 0 /* lower bound */, 4 /* elements */));
89   EXPECT_NE(safe_array_received.Receive(), nullptr);
90   EXPECT_EQ(safe_array_received.Get(), nullptr);
91 }
92 
TEST(ScopedSafearrayTest,ScopedSafearrayMoveConstructor)93 TEST(ScopedSafearrayTest, ScopedSafearrayMoveConstructor) {
94   ScopedSafearray first;
95   PopulateScopedSafearrayOfInts(first);
96   EXPECT_NE(first.Get(), nullptr);
97   EXPECT_EQ(first.GetCount(), kInputValues.size());
98 
99   SAFEARRAY* safearray = first.Get();
100   ScopedSafearray second(std::move(first));
101   EXPECT_EQ(first.Get(), nullptr);
102   EXPECT_EQ(second.Get(), safearray);
103 }
104 
TEST(ScopedSafearrayTest,ScopedSafearrayMoveAssignOperator)105 TEST(ScopedSafearrayTest, ScopedSafearrayMoveAssignOperator) {
106   ScopedSafearray first, second;
107   PopulateScopedSafearrayOfInts(first);
108   EXPECT_NE(first.Get(), nullptr);
109   EXPECT_EQ(first.GetCount(), kInputValues.size());
110 
111   SAFEARRAY* safearray = first.Get();
112   second = std::move(first);
113   EXPECT_EQ(first.Get(), nullptr);
114   EXPECT_EQ(second.Get(), safearray);
115 
116   // Indirectly move |second| into itself.
117   ScopedSafearray& reference_to_second = second;
118   second = std::move(reference_to_second);
119   EXPECT_EQ(second.GetCount(), kInputValues.size());
120   EXPECT_EQ(second.Get(), safearray);
121 }
122 
TEST(ScopedSafearrayTest,ScopedSafearrayCast)123 TEST(ScopedSafearrayTest, ScopedSafearrayCast) {
124   SAFEARRAY* safe_array = SafeArrayCreateVector(
125       VT_R8 /* element type */, 1 /* lower bound */, 5 /* elements */);
126   ScopedSafearray scoped_safe_array(safe_array);
127   EXPECT_EQ(SafeArrayGetDim(scoped_safe_array.Get()), 1U);
128 
129   LONG lower_bound;
130   EXPECT_HRESULT_SUCCEEDED(
131       SafeArrayGetLBound(scoped_safe_array.Get(), 1, &lower_bound));
132   EXPECT_EQ(lower_bound, 1);
133 
134   LONG upper_bound;
135   EXPECT_HRESULT_SUCCEEDED(
136       SafeArrayGetUBound(scoped_safe_array.Get(), 1, &upper_bound));
137   EXPECT_EQ(upper_bound, 5);
138 
139   VARTYPE variable_type;
140   EXPECT_HRESULT_SUCCEEDED(
141       SafeArrayGetVartype(scoped_safe_array.Get(), &variable_type));
142   EXPECT_EQ(variable_type, VT_R8);
143 }
144 
TEST(ScopedSafearrayTest,InitiallyEmpty)145 TEST(ScopedSafearrayTest, InitiallyEmpty) {
146   ScopedSafearray empty_safe_array;
147   EXPECT_EQ(empty_safe_array.Get(), nullptr);
148   EXPECT_DCHECK_DEATH(empty_safe_array.GetCount());
149 }
150 
TEST(ScopedSafearrayTest,ScopedSafearrayGetCount)151 TEST(ScopedSafearrayTest, ScopedSafearrayGetCount) {
152   // TODO(crbug.com/1082005): Create a safer alternative to SAFEARRAY methods.
153   ScopedSafearray scoped_safe_array(SafeArrayCreateVector(
154       /*vartype=*/VT_I4, /*lower_bound=*/2, /*element_count=*/5));
155   ASSERT_NE(scoped_safe_array.Get(), nullptr);
156   EXPECT_EQ(SafeArrayGetDim(scoped_safe_array.Get()), 1U);
157 
158   LONG lower_bound;
159   EXPECT_HRESULT_SUCCEEDED(
160       SafeArrayGetLBound(scoped_safe_array.Get(), 1, &lower_bound));
161   EXPECT_EQ(lower_bound, 2);
162 
163   LONG upper_bound;
164   EXPECT_HRESULT_SUCCEEDED(
165       SafeArrayGetUBound(scoped_safe_array.Get(), 1, &upper_bound));
166   EXPECT_EQ(upper_bound, 6);
167 
168   EXPECT_EQ(scoped_safe_array.GetCount(), 5U);
169 }
170 
TEST(ScopedSafearrayTest,ScopedSafearrayInitialLockScope)171 TEST(ScopedSafearrayTest, ScopedSafearrayInitialLockScope) {
172   ScopedSafearray scoped_safe_array;
173   std::optional<ScopedSafearray::LockScope<VT_I4>> lock_scope =
174       scoped_safe_array.CreateLockScope<VT_I4>();
175   EXPECT_FALSE(lock_scope.has_value());
176 }
177 
TEST(ScopedSafearrayTest,ScopedSafearrayLockScopeMoveConstructor)178 TEST(ScopedSafearrayTest, ScopedSafearrayLockScopeMoveConstructor) {
179   ScopedSafearray scoped_safe_array;
180   PopulateScopedSafearrayOfInts(scoped_safe_array);
181 
182   std::optional<ScopedSafearray::LockScope<VT_I4>> first =
183       scoped_safe_array.CreateLockScope<VT_I4>();
184   ASSERT_TRUE(first.has_value());
185   EXPECT_EQ(first->Type(), VT_I4);
186   EXPECT_EQ(first->size(), kInputValues.size());
187 
188   ScopedSafearray::LockScope<VT_I4> second(std::move(*first));
189   EXPECT_EQ(first->Type(), VT_EMPTY);
190   EXPECT_EQ(first->size(), 0U);
191   EXPECT_EQ(second.Type(), VT_I4);
192   EXPECT_EQ(second.size(), kInputValues.size());
193 }
194 
TEST(ScopedSafearrayTest,ScopedSafearrayLockScopeMoveAssignOperator)195 TEST(ScopedSafearrayTest, ScopedSafearrayLockScopeMoveAssignOperator) {
196   ScopedSafearray scoped_safe_array;
197   PopulateScopedSafearrayOfInts(scoped_safe_array);
198 
199   std::optional<ScopedSafearray::LockScope<VT_I4>> first =
200       scoped_safe_array.CreateLockScope<VT_I4>();
201   ASSERT_TRUE(first.has_value());
202   EXPECT_EQ(first->Type(), VT_I4);
203   EXPECT_EQ(first->size(), kInputValues.size());
204 
205   ScopedSafearray::LockScope<VT_I4> second;
206   second = std::move(*first);
207   EXPECT_EQ(first->Type(), VT_EMPTY);
208   EXPECT_EQ(first->size(), 0U);
209   EXPECT_EQ(second.Type(), VT_I4);
210   EXPECT_EQ(second.size(), kInputValues.size());
211 
212   // Indirectly move |second| into itself.
213   ScopedSafearray::LockScope<VT_I4>& reference_to_second = second;
214   EXPECT_DCHECK_DEATH(second = std::move(reference_to_second));
215 }
216 
TEST(ScopedSafearrayTest,ScopedSafearrayLockScopeTypeMismatch)217 TEST(ScopedSafearrayTest, ScopedSafearrayLockScopeTypeMismatch) {
218   ScopedSafearray scoped_safe_array;
219   PopulateScopedSafearrayOfInts(scoped_safe_array);
220 
221   {
222     std::optional<ScopedSafearray::LockScope<VT_BSTR>> invalid_lock_scope =
223         scoped_safe_array.CreateLockScope<VT_BSTR>();
224     EXPECT_FALSE(invalid_lock_scope.has_value());
225   }
226 
227   {
228     std::optional<ScopedSafearray::LockScope<VT_UI4>> invalid_lock_scope =
229         scoped_safe_array.CreateLockScope<VT_UI4>();
230     EXPECT_FALSE(invalid_lock_scope.has_value());
231   }
232 }
233 
TEST(ScopedSafearrayTest,ScopedSafearrayLockScopeRandomAccess)234 TEST(ScopedSafearrayTest, ScopedSafearrayLockScopeRandomAccess) {
235   ScopedSafearray scoped_safe_array;
236   PopulateScopedSafearrayOfInts(scoped_safe_array);
237 
238   std::optional<ScopedSafearray::LockScope<VT_I4>> lock_scope =
239       scoped_safe_array.CreateLockScope<VT_I4>();
240   ASSERT_TRUE(lock_scope.has_value());
241   EXPECT_EQ(lock_scope->Type(), VT_I4);
242   EXPECT_EQ(lock_scope->size(), kInputValues.size());
243   for (size_t i = 0; i < kInputValues.size(); ++i) {
244     EXPECT_EQ(lock_scope->at(i), kInputValues[i]);
245     EXPECT_EQ((*lock_scope)[i], kInputValues[i]);
246   }
247 }
248 
TEST(ScopedSafearrayTest,ScopedSafearrayLockScopeIterator)249 TEST(ScopedSafearrayTest, ScopedSafearrayLockScopeIterator) {
250   ScopedSafearray scoped_safe_array;
251   PopulateScopedSafearrayOfInts(scoped_safe_array);
252 
253   std::optional<ScopedSafearray::LockScope<VT_I4>> lock_scope =
254       scoped_safe_array.CreateLockScope<VT_I4>();
255 
256   std::vector<int> unpacked_vector(lock_scope->begin(), lock_scope->end());
257   ASSERT_EQ(unpacked_vector.size(), kInputValues.size());
258   for (size_t i = 0; i < kInputValues.size(); ++i)
259     EXPECT_EQ(unpacked_vector[i], kInputValues[i]);
260 }
261 
262 }  // namespace win
263 }  // namespace base
264