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