• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "ppapi/tests/test_var_deprecated.h"
6 
7 #include <string.h>
8 
9 #include <limits>
10 
11 #include "ppapi/c/pp_var.h"
12 #include "ppapi/c/dev/ppb_var_deprecated.h"
13 #include "ppapi/cpp/dev/scriptable_object_deprecated.h"
14 #include "ppapi/cpp/instance.h"
15 #include "ppapi/cpp/module.h"
16 #include "ppapi/cpp/private/var_private.h"
17 #include "ppapi/cpp/var.h"
18 #include "ppapi/tests/testing_instance.h"
19 
20 namespace {
21 
22 uint32_t kInvalidLength = static_cast<uint32_t>(-1);
23 
24 static const char kSetValueFunction[] = "SetValue";
25 
26 // ScriptableObject used by the var tests.
27 class VarScriptableObject : public pp::deprecated::ScriptableObject {
28  public:
VarScriptableObject(TestVarDeprecated * v)29   VarScriptableObject(TestVarDeprecated* v) : test_var_deprecated_(v) {}
30 
31   // pp::deprecated::ScriptableObject overrides.
32   bool HasMethod(const pp::Var& name, pp::Var* exception);
33   pp::Var Call(const pp::Var& name,
34                const std::vector<pp::Var>& args,
35                pp::Var* exception);
36 
37  private:
38   TestVarDeprecated* test_var_deprecated_;
39 };
40 
HasMethod(const pp::Var & name,pp::Var * exception)41 bool VarScriptableObject::HasMethod(const pp::Var& name, pp::Var* exception) {
42   if (!name.is_string())
43     return false;
44   return name.AsString() == kSetValueFunction;
45 }
46 
Call(const pp::Var & method_name,const std::vector<pp::Var> & args,pp::Var * exception)47 pp::Var VarScriptableObject::Call(const pp::Var& method_name,
48                                   const std::vector<pp::Var>& args,
49                                   pp::Var* exception) {
50   if (!method_name.is_string())
51     return false;
52   std::string name = method_name.AsString();
53 
54   if (name == kSetValueFunction) {
55     if (args.size() != 1)
56       *exception = pp::Var("Bad argument to SetValue(<value>)");
57     else
58       test_var_deprecated_->set_var_from_page(pp::VarPrivate(args[0]));
59   }
60 
61   return pp::Var();
62 }
63 
64 }  // namespace
65 
66 REGISTER_TEST_CASE(VarDeprecated);
67 
Init()68 bool TestVarDeprecated::Init() {
69   var_interface_ = static_cast<const PPB_Var_Deprecated*>(
70       pp::Module::Get()->GetBrowserInterface(PPB_VAR_DEPRECATED_INTERFACE));
71   return var_interface_ && CheckTestingInterface();
72 }
73 
RunTests(const std::string & filter)74 void TestVarDeprecated::RunTests(const std::string& filter) {
75   RUN_TEST(BasicString, filter);
76   RUN_TEST(InvalidAndEmpty, filter);
77   RUN_TEST(InvalidUtf8, filter);
78   RUN_TEST(NullInputInUtf8Conversion, filter);
79   RUN_TEST(ValidUtf8, filter);
80   RUN_TEST(Utf8WithEmbeddedNulls, filter);
81   RUN_TEST(VarToUtf8ForWrongType, filter);
82   RUN_TEST(HasPropertyAndMethod, filter);
83   RUN_TEST(PassReference, filter);
84 }
85 
CreateTestObject()86 pp::deprecated::ScriptableObject* TestVarDeprecated::CreateTestObject() {
87   return new VarScriptableObject(this);
88 }
89 
TestBasicString()90 std::string TestVarDeprecated::TestBasicString() {
91   uint32_t before_object = testing_interface_->GetLiveObjectsForInstance(
92       instance_->pp_instance());
93   {
94     const char kStr[] = "Hello";
95     const uint32_t kStrLen(sizeof(kStr) - 1);
96     PP_Var str = var_interface_->VarFromUtf8(pp::Module::Get()->pp_module(),
97                                              kStr, kStrLen);
98     ASSERT_EQ(PP_VARTYPE_STRING, str.type);
99 
100     // Reading back the string should work.
101     uint32_t len = 0;
102     const char* result = var_interface_->VarToUtf8(str, &len);
103     ASSERT_EQ(kStrLen, len);
104     ASSERT_EQ(0, strncmp(kStr, result, kStrLen));
105 
106     // Destroy the string, readback should now fail.
107     var_interface_->Release(str);
108     result = var_interface_->VarToUtf8(str, &len);
109     ASSERT_EQ(0, len);
110     ASSERT_EQ(NULL, result);
111   }
112 
113   // Make sure nothing leaked.
114   ASSERT_TRUE(testing_interface_->GetLiveObjectsForInstance(
115       instance_->pp_instance()) == before_object);
116 
117   PASS();
118 }
119 
TestInvalidAndEmpty()120 std::string TestVarDeprecated::TestInvalidAndEmpty() {
121   PP_Var invalid_string;
122   invalid_string.type = PP_VARTYPE_STRING;
123   invalid_string.value.as_id = 31415926;
124 
125   // Invalid strings should give NULL as the return value.
126   uint32_t len = std::numeric_limits<uint32_t>::max();
127   const char* result = var_interface_->VarToUtf8(invalid_string, &len);
128   ASSERT_EQ(0, len);
129   ASSERT_EQ(NULL, result);
130 
131   // Same with vars that are not strings.
132   len = std::numeric_limits<uint32_t>::max();
133   pp::Var int_var(42);
134   result = var_interface_->VarToUtf8(int_var.pp_var(), &len);
135   ASSERT_EQ(0, len);
136   ASSERT_EQ(NULL, result);
137 
138   // Empty strings should return non-NULL.
139   pp::Var empty_string("");
140   len = std::numeric_limits<uint32_t>::max();
141   result = var_interface_->VarToUtf8(empty_string.pp_var(), &len);
142   ASSERT_EQ(0, len);
143   ASSERT_NE(NULL, result);
144 
145   PASS();
146 }
147 
TestInvalidUtf8()148 std::string TestVarDeprecated::TestInvalidUtf8() {
149   // utf8じゃない (japanese for "is not utf8") in shift-jis encoding.
150   static const char kSjisString[] = "utf8\x82\xb6\x82\xe1\x82\xc8\x82\xa2";
151   pp::Var sjis(kSjisString);
152   if (!sjis.is_null())
153     return "Non-UTF8 string was permitted erroneously.";
154 
155   PASS();
156 }
157 
TestNullInputInUtf8Conversion()158 std::string TestVarDeprecated::TestNullInputInUtf8Conversion() {
159   // This test talks directly to the C interface to access edge cases that
160   // cannot be exercised via the C++ interface.
161   PP_Var converted_string;
162 
163   // 0-length string should not dereference input string, and should produce
164   // an empty string.
165   converted_string = var_interface_->VarFromUtf8(
166       pp::Module::Get()->pp_module(), NULL, 0);
167   if (converted_string.type != PP_VARTYPE_STRING) {
168     return "Expected 0 length to return empty string.";
169   }
170 
171   // Now convert it back.
172   uint32_t length = kInvalidLength;
173   const char* result = NULL;
174   result = var_interface_->VarToUtf8(converted_string, &length);
175   if (length != 0) {
176     return "Expected 0 length string on conversion.";
177   }
178   if (result == NULL) {
179     return "Expected a non-null result for 0-lengthed string from VarToUtf8.";
180   }
181   var_interface_->Release(converted_string);
182 
183   // Should not crash, and make an empty string.
184   const char* null_string = NULL;
185   pp::Var null_var(null_string);
186   if (!null_var.is_string() || null_var.AsString() != "") {
187     return "Expected NULL input to make an empty string Var.";
188   }
189 
190   PASS();
191 }
192 
TestValidUtf8()193 std::string TestVarDeprecated::TestValidUtf8() {
194   // From UTF8 string -> PP_Var.
195   // Chinese for "I am utf8."
196   static const char kValidUtf8[] = "\xe6\x88\x91\xe6\x98\xafutf8.";
197   pp::Var converted_string(kValidUtf8);
198 
199   if (converted_string.is_null())
200     return "Unable to convert valid utf8 to var.";
201 
202   // Since we're already here, test PP_Var back to UTF8 string.
203   std::string returned_string = converted_string.AsString();
204 
205   // We need to check against 1 less than sizeof because the resulting string
206   // is technically not NULL terminated by API design.
207   if (returned_string.size() != sizeof(kValidUtf8) - 1) {
208     return "Unable to convert utf8 string back from var.";
209   }
210   if (returned_string != kValidUtf8) {
211     return "String mismatches on conversion back from PP_Var.";
212   }
213 
214   PASS();
215 }
216 
TestUtf8WithEmbeddedNulls()217 std::string TestVarDeprecated::TestUtf8WithEmbeddedNulls() {
218   // From UTF8 string with embedded nulls -> PP_Var.
219   // Chinese for "also utf8."
220   static const char kUtf8WithEmbededNull[] = "\xe6\xb9\x9f\xe6\x98\xaf\0utf8.";
221   std::string orig_string(kUtf8WithEmbededNull,
222                           sizeof(kUtf8WithEmbededNull) -1);
223   pp::Var converted_string(orig_string);
224 
225   if (converted_string.is_null())
226     return "Unable to convert utf8 with embedded nulls to var.";
227 
228   // Since we're already here, test PP_Var back to UTF8 string.
229   std::string returned_string = converted_string.AsString();
230 
231   if (returned_string.size() != orig_string.size()) {
232     return "Unable to convert utf8 with embedded nulls back from var.";
233   }
234   if (returned_string != orig_string) {
235     return "String mismatches on conversion back from PP_Var.";
236   }
237 
238   PASS();
239 }
240 
TestVarToUtf8ForWrongType()241 std::string TestVarDeprecated::TestVarToUtf8ForWrongType() {
242   uint32_t length = kInvalidLength;
243   const char* result = NULL;
244   result = var_interface_->VarToUtf8(PP_MakeUndefined(), &length);
245   if (length != 0) {
246     return "Expected 0 on string conversion from Void var.";
247   }
248   if (result != NULL) {
249     return "Expected NULL on string conversion from Void var.";
250   }
251 
252   length = kInvalidLength;
253   result = NULL;
254   result = var_interface_->VarToUtf8(PP_MakeNull(), &length);
255   if (length != 0) {
256     return "Expected 0 on string conversion from Null var.";
257   }
258   if (result != NULL) {
259     return "Expected NULL on string conversion from Null var.";
260   }
261 
262   length = kInvalidLength;
263   result = NULL;
264   result = var_interface_->VarToUtf8(PP_MakeBool(PP_TRUE), &length);
265   if (length != 0) {
266     return "Expected 0 on string conversion from Bool var.";
267   }
268   if (result != NULL) {
269     return "Expected NULL on string conversion from Bool var.";
270   }
271 
272   length = kInvalidLength;
273   result = NULL;
274   result = var_interface_->VarToUtf8(PP_MakeInt32(1), &length);
275   if (length != 0) {
276     return "Expected 0 on string conversion from Int32 var.";
277   }
278   if (result != NULL) {
279     return "Expected NULL on string conversion from Int32 var.";
280   }
281 
282   length = kInvalidLength;
283   result = NULL;
284   result = var_interface_->VarToUtf8(PP_MakeDouble(1.0), &length);
285   if (length != 0) {
286     return "Expected 0 on string conversion from Double var.";
287   }
288   if (result != NULL) {
289     return "Expected NULL on string conversion from Double var.";
290   }
291 
292   PASS();
293 }
294 
TestHasPropertyAndMethod()295 std::string TestVarDeprecated::TestHasPropertyAndMethod() {
296   pp::VarPrivate window = instance_->GetWindowObject();
297   ASSERT_TRUE(window.is_object());
298 
299   // Regular property.
300   pp::Var exception;
301   ASSERT_TRUE(window.HasProperty("scrollX", &exception));
302   ASSERT_TRUE(exception.is_undefined());
303   ASSERT_FALSE(window.HasMethod("scrollX", &exception));
304   ASSERT_TRUE(exception.is_undefined());
305 
306   // Regular method (also counts as HasProperty).
307   ASSERT_TRUE(window.HasProperty("find", &exception));
308   ASSERT_TRUE(exception.is_undefined());
309   ASSERT_TRUE(window.HasMethod("find", &exception));
310   ASSERT_TRUE(exception.is_undefined());
311 
312   // Nonexistant ones should return false and not set the exception.
313   ASSERT_FALSE(window.HasProperty("superEvilBit", &exception));
314   ASSERT_TRUE(exception.is_undefined());
315   ASSERT_FALSE(window.HasMethod("superEvilBit", &exception));
316   ASSERT_TRUE(exception.is_undefined());
317 
318   // Check exception and return false on invalid property name.
319   ASSERT_FALSE(window.HasProperty(3.14159, &exception));
320   ASSERT_FALSE(exception.is_undefined());
321   exception = pp::Var();
322 
323   exception = pp::Var();
324   ASSERT_FALSE(window.HasMethod(3.14159, &exception));
325   ASSERT_FALSE(exception.is_undefined());
326 
327   // Try to use something not an object.
328   exception = pp::Var();
329   pp::VarPrivate string_object("asdf");
330   ASSERT_FALSE(string_object.HasProperty("find", &exception));
331   ASSERT_FALSE(exception.is_undefined());
332   exception = pp::Var();
333   ASSERT_FALSE(string_object.HasMethod("find", &exception));
334   ASSERT_FALSE(exception.is_undefined());
335 
336   // Try to use an invalid object (need to use the C API).
337   PP_Var invalid_object;
338   invalid_object.type = PP_VARTYPE_OBJECT;
339   invalid_object.value.as_id = static_cast<int64_t>(-1234567);
340   PP_Var exception2 = PP_MakeUndefined();
341   ASSERT_FALSE(var_interface_->HasProperty(invalid_object,
342                                            pp::Var("find").pp_var(),
343                                            &exception2));
344   ASSERT_NE(PP_VARTYPE_UNDEFINED, exception2.type);
345   var_interface_->Release(exception2);
346 
347   exception2 = PP_MakeUndefined();
348   ASSERT_FALSE(var_interface_->HasMethod(invalid_object,
349                                          pp::Var("find").pp_var(),
350                                          &exception2));
351   ASSERT_NE(PP_VARTYPE_UNDEFINED, exception2.type);
352   var_interface_->Release(exception2);
353 
354   // Getting a valid property/method when the exception is set returns false.
355   exception = pp::Var("Bad something-or-other exception");
356   ASSERT_FALSE(window.HasProperty("find", &exception));
357   ASSERT_FALSE(exception.is_undefined());
358   ASSERT_FALSE(window.HasMethod("find", &exception));
359   ASSERT_FALSE(exception.is_undefined());
360 
361   PASS();
362 }
363 
364 // Tests that when the page sends an object to the plugin via a function call,
365 // that the refcounting works properly (bug 79813).
TestPassReference()366 std::string TestVarDeprecated::TestPassReference() {
367   var_from_page_ = pp::Var();
368 
369   // Send a JS object from the page to the plugin.
370   pp::Var exception;
371   pp::Var ret = instance_->ExecuteScript(
372       "document.getElementById('plugin').SetValue(function(arg) {"
373           "return 'works' + arg;"
374       "})",
375       &exception);
376   ASSERT_TRUE(exception.is_undefined());
377 
378   // We should have gotten an object set for our var_from_page.
379   ASSERT_TRUE(var_from_page_.is_object());
380 
381   // If the reference counting works, the object should be valid. We can test
382   // this by executing it (it was a function we defined above) and it should
383   // return "works" concatenated with the argument.
384   pp::VarPrivate function(var_from_page_);
385   pp::Var result = var_from_page_.Call(pp::Var(), "nice");
386   ASSERT_TRUE(result.is_string());
387   ASSERT_TRUE(result.AsString() == "worksnice");
388 
389   // Reset var_from_page_ so it doesn't seem like a leak to the var leak
390   // checking code.
391   var_from_page_ = pp::Var();
392 
393   PASS();
394 }
395 
396