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