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