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