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