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