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