OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 <vector> | |
6 | |
7 #include "base/compiler_specific.h" | |
8 #include "base/memory/scoped_ptr.h" | |
9 #include "base/strings/string_util.h" | |
10 #include "testing/gtest/include/gtest/gtest.h" | |
11 #include "third_party/WebKit/public/web/WebBindings.h" | |
12 #include "webkit/renderer/cpp_variant.h" | |
13 | |
14 using blink::WebBindings; | |
15 using webkit_glue::CppVariant; | |
16 | |
17 // Creates a std::string from an NPVariant of string type. If the NPVariant | |
18 // is not a string, empties the std::string. | |
19 void MakeStdString(const NPVariant& np, std::string* std_string) { | |
20 if (np.type == NPVariantType_String) { | |
21 const char* chars = | |
22 reinterpret_cast<const char*>(np.value.stringValue.UTF8Characters); | |
23 (*std_string).assign(chars, np.value.stringValue.UTF8Length); | |
24 } else { | |
25 (*std_string).clear(); | |
26 } | |
27 } | |
28 | |
29 // Verifies that the actual NPVariant is a string and that its value matches | |
30 // the expected_str. | |
31 void CheckString(const std::string& expected_str, const NPVariant& actual) { | |
32 EXPECT_EQ(NPVariantType_String, actual.type); | |
33 std::string actual_str; | |
34 MakeStdString(actual, &actual_str); | |
35 EXPECT_EQ(expected_str, actual_str); | |
36 } | |
37 | |
38 // Verifies that both the actual and the expected NPVariants are strings and | |
39 // that their values match. | |
40 void CheckString(const NPVariant& expected, const NPVariant& actual) { | |
41 EXPECT_EQ(NPVariantType_String, expected.type); | |
42 std::string expected_str; | |
43 MakeStdString(expected, &expected_str); | |
44 CheckString(expected_str, actual); | |
45 } | |
46 | |
47 int g_allocate_call_count = 0; | |
48 int g_deallocate_call_count = 0; | |
49 | |
50 void CheckObject(const NPVariant& actual) { | |
51 EXPECT_EQ(NPVariantType_Object, actual.type); | |
52 EXPECT_TRUE(actual.value.objectValue); | |
53 EXPECT_EQ(1U, actual.value.objectValue->referenceCount); | |
54 EXPECT_EQ(1, g_allocate_call_count); | |
55 EXPECT_EQ(0, g_deallocate_call_count); | |
56 } | |
57 | |
58 NPObject* MockNPAllocate(NPP npp, NPClass* aClass) { | |
59 // This is a mock allocate method that mimics the behavior | |
60 // of WebBindings::createObject when allocate() is NULL | |
61 | |
62 ++g_allocate_call_count; | |
63 // Ignore npp and NPClass | |
64 return reinterpret_cast<NPObject*>(malloc(sizeof(NPObject))); | |
65 } | |
66 | |
67 void MockNPDeallocate(NPObject* npobj) { | |
68 // This is a mock deallocate method that mimics the behavior | |
69 // of NPN_DeallocateObject when deallocate() is NULL | |
70 | |
71 ++g_deallocate_call_count; | |
72 free(npobj); | |
73 } | |
74 | |
75 static NPClass void_class = { NP_CLASS_STRUCT_VERSION, | |
76 MockNPAllocate, | |
77 MockNPDeallocate, | |
78 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | |
79 | |
80 class CppVariantTest : public testing::Test { | |
81 public: | |
82 CppVariantTest() : npp_(new struct _NPP) {} | |
83 virtual ~CppVariantTest() {} | |
84 | |
85 virtual void SetUp() OVERRIDE { | |
86 WebBindings::registerObjectOwner(npp_.get()); | |
87 } | |
88 | |
89 virtual void TearDown() OVERRIDE { | |
90 WebBindings::unregisterObjectOwner(npp_.get()); | |
91 } | |
92 | |
93 struct _NPP* npp() { return npp_.get(); } | |
94 | |
95 NPObject* MakeVoidObject() { | |
96 g_allocate_call_count = 0; | |
97 g_deallocate_call_count = 0; | |
98 return WebBindings::createObject(npp_.get(), &void_class); | |
99 } | |
100 | |
101 private: | |
102 scoped_ptr<struct _NPP> npp_; | |
103 }; | |
104 | |
105 TEST_F(CppVariantTest, NewVariantHasNullType) { | |
106 CppVariant value; | |
107 EXPECT_EQ(NPVariantType_Null, value.type); | |
108 } | |
109 | |
110 TEST_F(CppVariantTest, SetNullSetsType) { | |
111 CppVariant value; | |
112 value.Set(17); | |
113 value.SetNull(); | |
114 EXPECT_EQ(NPVariantType_Null, value.type); | |
115 } | |
116 | |
117 TEST_F(CppVariantTest, CopyConstructorDoesDeepCopy) { | |
118 CppVariant source; | |
119 source.Set("test string"); | |
120 CppVariant dest = source; | |
121 EXPECT_EQ(NPVariantType_String, dest.type); | |
122 EXPECT_EQ(NPVariantType_String, source.type); | |
123 | |
124 // Ensure that the string was copied, not just the pointer. | |
125 EXPECT_NE(source.value.stringValue.UTF8Characters, | |
126 dest.value.stringValue.UTF8Characters); | |
127 | |
128 CheckString(source, dest); | |
129 } | |
130 | |
131 TEST_F(CppVariantTest, CopyConstructorIncrementsRefCount) { | |
132 CppVariant source; | |
133 NPObject *object = MakeVoidObject(); | |
134 source.Set(object); | |
135 // 2 references so far. | |
136 EXPECT_EQ(2U, source.value.objectValue->referenceCount); | |
137 | |
138 CppVariant dest = source; | |
139 EXPECT_EQ(3U, dest.value.objectValue->referenceCount); | |
140 EXPECT_EQ(1, g_allocate_call_count); | |
141 WebBindings::releaseObject(object); | |
142 source.SetNull(); | |
143 CheckObject(dest); | |
144 } | |
145 | |
146 TEST_F(CppVariantTest, AssignmentDoesDeepCopy) { | |
147 CppVariant source; | |
148 source.Set("test string"); | |
149 CppVariant dest; | |
150 dest = source; | |
151 EXPECT_EQ(NPVariantType_String, dest.type); | |
152 EXPECT_EQ(NPVariantType_String, source.type); | |
153 | |
154 // Ensure that the string was copied, not just the pointer. | |
155 EXPECT_NE(source.value.stringValue.UTF8Characters, | |
156 dest.value.stringValue.UTF8Characters); | |
157 | |
158 CheckString(source, dest); | |
159 } | |
160 | |
161 TEST_F(CppVariantTest, AssignmentIncrementsRefCount) { | |
162 CppVariant source; | |
163 NPObject *object = MakeVoidObject(); | |
164 source.Set(object); | |
165 // 2 references so far. | |
166 EXPECT_EQ(2U, source.value.objectValue->referenceCount); | |
167 | |
168 CppVariant dest; | |
169 dest = source; | |
170 EXPECT_EQ(3U, dest.value.objectValue->referenceCount); | |
171 EXPECT_EQ(1, g_allocate_call_count); | |
172 | |
173 WebBindings::releaseObject(object); | |
174 source.SetNull(); | |
175 CheckObject(dest); | |
176 } | |
177 | |
178 TEST_F(CppVariantTest, DestroyingCopyDoesNotCorruptSource) { | |
179 CppVariant source; | |
180 source.Set("test string"); | |
181 std::string before; | |
182 MakeStdString(source, &before); | |
183 { | |
184 CppVariant dest = source; | |
185 } | |
186 CheckString(before, source); | |
187 | |
188 NPObject *object = MakeVoidObject(); | |
189 source.Set(object); | |
190 { | |
191 CppVariant dest2 = source; | |
192 } | |
193 WebBindings::releaseObject(object); | |
194 CheckObject(source); | |
195 } | |
196 | |
197 TEST_F(CppVariantTest, CopiesTypeAndValueToNPVariant) { | |
198 NPVariant np; | |
199 CppVariant cpp; | |
200 | |
201 cpp.Set(true); | |
202 cpp.CopyToNPVariant(&np); | |
203 EXPECT_EQ(cpp.type, np.type); | |
204 EXPECT_EQ(cpp.value.boolValue, np.value.boolValue); | |
205 WebBindings::releaseVariantValue(&np); | |
206 | |
207 cpp.Set(17); | |
208 cpp.CopyToNPVariant(&np); | |
209 EXPECT_EQ(cpp.type, np.type); | |
210 EXPECT_EQ(cpp.value.intValue, np.value.intValue); | |
211 WebBindings::releaseVariantValue(&np); | |
212 | |
213 cpp.Set(3.1415); | |
214 cpp.CopyToNPVariant(&np); | |
215 EXPECT_EQ(cpp.type, np.type); | |
216 EXPECT_EQ(cpp.value.doubleValue, np.value.doubleValue); | |
217 WebBindings::releaseVariantValue(&np); | |
218 | |
219 cpp.Set("test value"); | |
220 cpp.CopyToNPVariant(&np); | |
221 CheckString("test value", np); | |
222 WebBindings::releaseVariantValue(&np); | |
223 | |
224 cpp.SetNull(); | |
225 cpp.CopyToNPVariant(&np); | |
226 EXPECT_EQ(cpp.type, np.type); | |
227 WebBindings::releaseVariantValue(&np); | |
228 | |
229 NPObject *object = MakeVoidObject(); | |
230 cpp.Set(object); | |
231 cpp.CopyToNPVariant(&np); | |
232 WebBindings::releaseObject(object); | |
233 cpp.SetNull(); | |
234 CheckObject(np); | |
235 WebBindings::releaseVariantValue(&np); | |
236 } | |
237 | |
238 TEST_F(CppVariantTest, SetsTypeAndValueFromNPVariant) { | |
239 NPVariant np; | |
240 CppVariant cpp; | |
241 | |
242 VOID_TO_NPVARIANT(np); | |
243 cpp.Set(np); | |
244 EXPECT_EQ(np.type, cpp.type); | |
245 WebBindings::releaseVariantValue(&np); | |
246 | |
247 NULL_TO_NPVARIANT(np); | |
248 cpp.Set(np); | |
249 EXPECT_EQ(np.type, cpp.type); | |
250 WebBindings::releaseVariantValue(&np); | |
251 | |
252 BOOLEAN_TO_NPVARIANT(true, np); | |
253 cpp.Set(np); | |
254 EXPECT_EQ(np.type, cpp.type); | |
255 EXPECT_EQ(np.value.boolValue, cpp.value.boolValue); | |
256 WebBindings::releaseVariantValue(&np); | |
257 | |
258 INT32_TO_NPVARIANT(15, np); | |
259 cpp.Set(np); | |
260 EXPECT_EQ(np.type, cpp.type); | |
261 EXPECT_EQ(np.value.intValue, cpp.value.intValue); | |
262 WebBindings::releaseVariantValue(&np); | |
263 | |
264 DOUBLE_TO_NPVARIANT(2.71828, np); | |
265 cpp.Set(np); | |
266 EXPECT_EQ(np.type, cpp.type); | |
267 EXPECT_EQ(np.value.doubleValue, cpp.value.doubleValue); | |
268 WebBindings::releaseVariantValue(&np); | |
269 | |
270 NPString np_ascii_str = { "1st test value", | |
271 static_cast<uint32_t>(strlen("1st test value")) }; | |
272 WebBindings::initializeVariantWithStringCopy(&np, &np_ascii_str); | |
273 cpp.Set(np); | |
274 CheckString("1st test value", cpp); | |
275 WebBindings::releaseVariantValue(&np); | |
276 | |
277 // Test characters represented in 2/3/4 bytes in UTF-8 | |
278 // Greek alpha, Chinese number 1 (horizontal bar), | |
279 // Deseret letter (similar to 'O') | |
280 NPString np_intl_str = { "\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84", | |
281 static_cast<uint32_t>(strlen( | |
282 "\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84")) }; | |
283 WebBindings::initializeVariantWithStringCopy(&np, &np_intl_str); | |
284 cpp.Set(np); | |
285 CheckString("\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84", cpp); | |
286 WebBindings::releaseVariantValue(&np); | |
287 | |
288 NPObject *obj = MakeVoidObject(); | |
289 OBJECT_TO_NPVARIANT(obj, np); // Doesn't make a copy. | |
290 cpp.Set(np); | |
291 // Use this or WebBindings::releaseObject but NOT both. | |
292 WebBindings::releaseVariantValue(&np); | |
293 CheckObject(cpp); | |
294 } | |
295 | |
296 TEST_F(CppVariantTest, SetsSimpleTypesAndValues) { | |
297 CppVariant cpp; | |
298 cpp.Set(true); | |
299 EXPECT_EQ(NPVariantType_Bool, cpp.type); | |
300 EXPECT_TRUE(cpp.value.boolValue); | |
301 | |
302 cpp.Set(5); | |
303 EXPECT_EQ(NPVariantType_Int32, cpp.type); | |
304 EXPECT_EQ(5, cpp.value.intValue); | |
305 | |
306 cpp.Set(1.234); | |
307 EXPECT_EQ(NPVariantType_Double, cpp.type); | |
308 EXPECT_EQ(1.234, cpp.value.doubleValue); | |
309 | |
310 // C string | |
311 cpp.Set("1st test string"); | |
312 CheckString("1st test string", cpp); | |
313 | |
314 // std::string | |
315 std::string source("std test string"); | |
316 cpp.Set(source); | |
317 CheckString("std test string", cpp); | |
318 | |
319 // NPString | |
320 NPString np_ascii_str = { "test NPString", | |
321 static_cast<uint32_t>(strlen("test NPString")) }; | |
322 cpp.Set(np_ascii_str); | |
323 std::string expected("test NPString"); | |
324 CheckString(expected, cpp); | |
325 | |
326 // Test characters represented in 2/3/4 bytes in UTF-8 | |
327 // Greek alpha, Chinese number 1 (horizontal bar), | |
328 // Deseret letter (similar to 'O') | |
329 NPString np_intl_str = { "\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84", | |
330 static_cast<uint32_t>(strlen( | |
331 "\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84")) }; | |
332 cpp.Set(np_intl_str); | |
333 expected = std::string("\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84"); | |
334 CheckString(expected, cpp); | |
335 | |
336 NPObject* obj = MakeVoidObject(); | |
337 cpp.Set(obj); | |
338 WebBindings::releaseObject(obj); | |
339 CheckObject(cpp); | |
340 } | |
341 | |
342 TEST_F(CppVariantTest, FreeDataSetsToVoid) { | |
343 CppVariant cpp; | |
344 EXPECT_EQ(NPVariantType_Null, cpp.type); | |
345 cpp.Set(12); | |
346 EXPECT_EQ(NPVariantType_Int32, cpp.type); | |
347 cpp.FreeData(); | |
348 EXPECT_EQ(NPVariantType_Void, cpp.type); | |
349 } | |
350 | |
351 TEST_F(CppVariantTest, FreeDataReleasesObject) { | |
352 CppVariant cpp; | |
353 NPObject* object = MakeVoidObject(); | |
354 cpp.Set(object); | |
355 EXPECT_EQ(2U, object->referenceCount); | |
356 cpp.FreeData(); | |
357 EXPECT_EQ(1U, object->referenceCount); | |
358 EXPECT_EQ(0, g_deallocate_call_count); | |
359 | |
360 cpp.Set(object); | |
361 WebBindings::releaseObject(object); | |
362 EXPECT_EQ(0, g_deallocate_call_count); | |
363 cpp.FreeData(); | |
364 EXPECT_EQ(1, g_deallocate_call_count); | |
365 } | |
366 | |
367 TEST_F(CppVariantTest, IsTypeFunctionsWork) { | |
368 CppVariant cpp; | |
369 // These should not happen in practice, since voids are not supported | |
370 // This test must be first since it just clobbers internal data without | |
371 // releasing. | |
372 VOID_TO_NPVARIANT(cpp); | |
373 EXPECT_FALSE(cpp.isBool()); | |
374 EXPECT_FALSE(cpp.isInt32()); | |
375 EXPECT_FALSE(cpp.isDouble()); | |
376 EXPECT_FALSE(cpp.isNumber()); | |
377 EXPECT_FALSE(cpp.isString()); | |
378 EXPECT_TRUE(cpp.isVoid()); | |
379 EXPECT_FALSE(cpp.isNull()); | |
380 EXPECT_TRUE(cpp.isEmpty()); | |
381 | |
382 cpp.Set(true); | |
383 EXPECT_TRUE(cpp.isBool()); | |
384 EXPECT_FALSE(cpp.isInt32()); | |
385 EXPECT_FALSE(cpp.isDouble()); | |
386 EXPECT_FALSE(cpp.isNumber()); | |
387 EXPECT_FALSE(cpp.isString()); | |
388 EXPECT_FALSE(cpp.isVoid()); | |
389 EXPECT_FALSE(cpp.isNull()); | |
390 EXPECT_FALSE(cpp.isEmpty()); | |
391 EXPECT_FALSE(cpp.isObject()); | |
392 | |
393 cpp.Set(12); | |
394 EXPECT_FALSE(cpp.isBool()); | |
395 EXPECT_TRUE(cpp.isInt32()); | |
396 EXPECT_FALSE(cpp.isDouble()); | |
397 EXPECT_TRUE(cpp.isNumber()); | |
398 EXPECT_FALSE(cpp.isString()); | |
399 EXPECT_FALSE(cpp.isVoid()); | |
400 EXPECT_FALSE(cpp.isNull()); | |
401 EXPECT_FALSE(cpp.isEmpty()); | |
402 EXPECT_FALSE(cpp.isObject()); | |
403 | |
404 cpp.Set(3.1415); | |
405 EXPECT_FALSE(cpp.isBool()); | |
406 EXPECT_FALSE(cpp.isInt32()); | |
407 EXPECT_TRUE(cpp.isDouble()); | |
408 EXPECT_TRUE(cpp.isNumber()); | |
409 EXPECT_FALSE(cpp.isString()); | |
410 EXPECT_FALSE(cpp.isVoid()); | |
411 EXPECT_FALSE(cpp.isNull()); | |
412 EXPECT_FALSE(cpp.isEmpty()); | |
413 EXPECT_FALSE(cpp.isObject()); | |
414 | |
415 cpp.Set("a string"); | |
416 EXPECT_FALSE(cpp.isBool()); | |
417 EXPECT_FALSE(cpp.isInt32()); | |
418 EXPECT_FALSE(cpp.isDouble()); | |
419 EXPECT_FALSE(cpp.isNumber()); | |
420 EXPECT_TRUE(cpp.isString()); | |
421 EXPECT_FALSE(cpp.isVoid()); | |
422 EXPECT_FALSE(cpp.isNull()); | |
423 EXPECT_FALSE(cpp.isEmpty()); | |
424 EXPECT_FALSE(cpp.isObject()); | |
425 | |
426 cpp.SetNull(); | |
427 EXPECT_FALSE(cpp.isBool()); | |
428 EXPECT_FALSE(cpp.isInt32()); | |
429 EXPECT_FALSE(cpp.isDouble()); | |
430 EXPECT_FALSE(cpp.isNumber()); | |
431 EXPECT_FALSE(cpp.isString()); | |
432 EXPECT_FALSE(cpp.isVoid()); | |
433 EXPECT_TRUE(cpp.isNull()); | |
434 EXPECT_TRUE(cpp.isEmpty()); | |
435 EXPECT_FALSE(cpp.isObject()); | |
436 | |
437 NPObject *obj = MakeVoidObject(); | |
438 cpp.Set(obj); | |
439 EXPECT_FALSE(cpp.isBool()); | |
440 EXPECT_FALSE(cpp.isInt32()); | |
441 EXPECT_FALSE(cpp.isDouble()); | |
442 EXPECT_FALSE(cpp.isNumber()); | |
443 EXPECT_FALSE(cpp.isString()); | |
444 EXPECT_FALSE(cpp.isVoid()); | |
445 EXPECT_FALSE(cpp.isNull()); | |
446 EXPECT_FALSE(cpp.isEmpty()); | |
447 EXPECT_TRUE(cpp.isObject()); | |
448 WebBindings::releaseObject(obj); | |
449 CheckObject(cpp); | |
450 } | |
451 | |
452 bool MockNPHasPropertyFunction(NPObject *npobj, NPIdentifier name) { | |
453 return true; | |
454 } | |
455 | |
456 bool MockNPGetPropertyFunction(NPObject *npobj, NPIdentifier name, | |
457 NPVariant *result) { | |
458 if (WebBindings::getStringIdentifier("length") == name) { | |
459 DOUBLE_TO_NPVARIANT(4, *result); | |
460 } else if (WebBindings::getIntIdentifier(0) == name) { | |
461 DOUBLE_TO_NPVARIANT(0, *result); | |
462 } else if (WebBindings::getIntIdentifier(1) == name) { | |
463 BOOLEAN_TO_NPVARIANT(true, *result); | |
464 } else if (WebBindings::getIntIdentifier(2) == name) { | |
465 NULL_TO_NPVARIANT(*result); | |
466 } else if (WebBindings::getIntIdentifier(3) == name) { | |
467 const char* s = "string"; | |
468 size_t length = strlen(s); | |
469 char* mem = static_cast<char*>(malloc(length + 1)); | |
470 base::strlcpy(mem, s, length + 1); | |
471 STRINGZ_TO_NPVARIANT(mem, *result); | |
472 } | |
473 | |
474 return true; | |
475 } | |
476 | |
477 TEST_F(CppVariantTest, ToVector) { | |
478 NPClass array_like_class = { | |
479 NP_CLASS_STRUCT_VERSION, | |
480 0, // NPAllocateFunctionPtr allocate; | |
481 0, // NPDeallocateFunctionPtr deallocate; | |
482 0, // NPInvalidateFunctionPtr invalidate; | |
483 0, // NPHasMethodFunctionPtr hasMethod; | |
484 0, // NPInvokeFunctionPtr invoke; | |
485 0, // NPInvokeDefaultFunctionPtr invokeDefault; | |
486 MockNPHasPropertyFunction, // NPHasPropertyFunctionPtr hasProperty; | |
487 MockNPGetPropertyFunction, // NPGetPropertyFunctionPtr getProperty; | |
488 0, // NPSetPropertyFunctionPtr setProperty; | |
489 0, // NPRemovePropertyFunctionPtr removeProperty; | |
490 0, // NPEnumerationFunctionPtr enumerate; | |
491 0 // NPConstructFunctionPtr construct; | |
492 }; | |
493 | |
494 NPObject* obj = WebBindings::createObject(npp(), &array_like_class); | |
495 | |
496 CppVariant cpp; | |
497 cpp.Set(obj); | |
498 | |
499 std::vector<CppVariant> cpp_vector = cpp.ToVector(); | |
500 EXPECT_EQ(4u, cpp_vector.size()); | |
501 | |
502 EXPECT_TRUE(cpp_vector[0].isDouble()); | |
503 EXPECT_EQ(0, cpp_vector[0].ToDouble()); | |
504 | |
505 EXPECT_TRUE(cpp_vector[1].isBool()); | |
506 EXPECT_EQ(true, cpp_vector[1].ToBoolean()); | |
507 | |
508 EXPECT_TRUE(cpp_vector[2].isNull()); | |
509 | |
510 EXPECT_TRUE(cpp_vector[3].isString()); | |
511 CheckString("string", cpp_vector[3]); | |
512 | |
513 WebBindings::releaseObject(obj); | |
514 } | |
OLD | NEW |