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
14using blink::WebBindings;
15using 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.
19void 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.
31void 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.
40void 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
47int g_allocate_call_count = 0;
48int g_deallocate_call_count = 0;
49
50void 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
58NPObject* 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
67void 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
75static NPClass void_class = { NP_CLASS_STRUCT_VERSION,
76                              MockNPAllocate,
77                              MockNPDeallocate,
78                              0, 0, 0, 0, 0, 0, 0, 0, 0 };
79
80class CppVariantTest : public testing::Test {
81public:
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
101private:
102  scoped_ptr<struct _NPP> npp_;
103};
104
105TEST_F(CppVariantTest, NewVariantHasNullType) {
106  CppVariant value;
107  EXPECT_EQ(NPVariantType_Null, value.type);
108}
109
110TEST_F(CppVariantTest, SetNullSetsType) {
111  CppVariant value;
112  value.Set(17);
113  value.SetNull();
114  EXPECT_EQ(NPVariantType_Null, value.type);
115}
116
117TEST_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
131TEST_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
146TEST_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
161TEST_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
178TEST_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
197TEST_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
238TEST_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
296TEST_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
342TEST_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
351TEST_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
367TEST_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
452bool MockNPHasPropertyFunction(NPObject *npobj, NPIdentifier name) {
453  return true;
454}
455
456bool 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
477TEST_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}
515