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.
5 #include "ppapi/tests/test_var_deprecated.h"
11 #include "ppapi/c/pp_var.h"
12 #include "ppapi/c/dev/ppb_testing_dev.h"
13 #include "ppapi/c/dev/ppb_var_deprecated.h"
14 #include "ppapi/cpp/dev/scriptable_object_deprecated.h"
15 #include "ppapi/cpp/instance.h"
16 #include "ppapi/cpp/module.h"
17 #include "ppapi/cpp/private/var_private.h"
18 #include "ppapi/cpp/var.h"
19 #include "ppapi/tests/testing_instance.h"
23 uint32_t kInvalidLength
= static_cast<uint32_t>(-1);
25 static const char kSetValueFunction
[] = "SetValue";
27 // ScriptableObject used by the var tests.
28 class VarScriptableObject
: public pp::deprecated::ScriptableObject
{
30 VarScriptableObject(TestVarDeprecated
* v
) : test_var_deprecated_(v
) {}
32 // pp::deprecated::ScriptableObject overrides.
33 bool HasMethod(const pp::Var
& name
, pp::Var
* exception
);
34 pp::Var
Call(const pp::Var
& name
,
35 const std::vector
<pp::Var
>& args
,
39 TestVarDeprecated
* test_var_deprecated_
;
42 bool VarScriptableObject::HasMethod(const pp::Var
& name
, pp::Var
* exception
) {
43 if (!name
.is_string())
45 return name
.AsString() == kSetValueFunction
;
48 pp::Var
VarScriptableObject::Call(const pp::Var
& method_name
,
49 const std::vector
<pp::Var
>& args
,
51 if (!method_name
.is_string())
53 std::string name
= method_name
.AsString();
55 if (name
== kSetValueFunction
) {
57 *exception
= pp::Var("Bad argument to SetValue(<value>)");
59 test_var_deprecated_
->set_var_from_page(pp::VarPrivate(args
[0]));
67 REGISTER_TEST_CASE(VarDeprecated
);
69 bool TestVarDeprecated::Init() {
70 var_interface_
= static_cast<const PPB_Var_Deprecated
*>(
71 pp::Module::Get()->GetBrowserInterface(PPB_VAR_DEPRECATED_INTERFACE
));
72 return var_interface_
&& CheckTestingInterface();
75 void TestVarDeprecated::RunTests(const std::string
& filter
) {
76 RUN_TEST(BasicString
, filter
);
77 RUN_TEST(InvalidAndEmpty
, filter
);
78 RUN_TEST(InvalidUtf8
, filter
);
79 RUN_TEST(NullInputInUtf8Conversion
, filter
);
80 RUN_TEST(ValidUtf8
, filter
);
81 RUN_TEST(Utf8WithEmbeddedNulls
, filter
);
82 RUN_TEST(VarToUtf8ForWrongType
, filter
);
83 RUN_TEST(HasPropertyAndMethod
, filter
);
84 RUN_TEST(PassReference
, filter
);
87 pp::deprecated::ScriptableObject
* TestVarDeprecated::CreateTestObject() {
88 return new VarScriptableObject(this);
91 std::string
TestVarDeprecated::TestBasicString() {
92 uint32_t before_object
= testing_interface_
->GetLiveObjectsForInstance(
93 instance_
->pp_instance());
95 const char kStr
[] = "Hello";
96 const uint32_t kStrLen(sizeof(kStr
) - 1);
97 PP_Var str
= var_interface_
->VarFromUtf8(pp::Module::Get()->pp_module(),
99 ASSERT_EQ(PP_VARTYPE_STRING
, str
.type
);
101 // Reading back the string should work.
103 const char* result
= var_interface_
->VarToUtf8(str
, &len
);
104 ASSERT_EQ(kStrLen
, len
);
105 ASSERT_EQ(0, strncmp(kStr
, result
, kStrLen
));
107 // Destroy the string, readback should now fail.
108 var_interface_
->Release(str
);
109 result
= var_interface_
->VarToUtf8(str
, &len
);
111 ASSERT_EQ(NULL
, result
);
114 // Make sure nothing leaked.
115 ASSERT_TRUE(testing_interface_
->GetLiveObjectsForInstance(
116 instance_
->pp_instance()) == before_object
);
121 std::string
TestVarDeprecated::TestInvalidAndEmpty() {
122 PP_Var invalid_string
;
123 invalid_string
.type
= PP_VARTYPE_STRING
;
124 invalid_string
.value
.as_id
= 31415926;
126 // Invalid strings should give NULL as the return value.
127 uint32_t len
= std::numeric_limits
<uint32_t>::max();
128 const char* result
= var_interface_
->VarToUtf8(invalid_string
, &len
);
130 ASSERT_EQ(NULL
, result
);
132 // Same with vars that are not strings.
133 len
= std::numeric_limits
<uint32_t>::max();
135 result
= var_interface_
->VarToUtf8(int_var
.pp_var(), &len
);
137 ASSERT_EQ(NULL
, result
);
139 // Empty strings should return non-NULL.
140 pp::Var
empty_string("");
141 len
= std::numeric_limits
<uint32_t>::max();
142 result
= var_interface_
->VarToUtf8(empty_string
.pp_var(), &len
);
144 ASSERT_NE(NULL
, result
);
149 std::string
TestVarDeprecated::TestInvalidUtf8() {
150 // utf8ăăăȘă (japanese for "is not utf8") in shift-jis encoding.
151 static const char kSjisString
[] = "utf8\x82\xb6\x82\xe1\x82\xc8\x82\xa2";
152 pp::Var
sjis(kSjisString
);
154 return "Non-UTF8 string was permitted erroneously.";
159 std::string
TestVarDeprecated::TestNullInputInUtf8Conversion() {
160 // This test talks directly to the C interface to access edge cases that
161 // cannot be exercised via the C++ interface.
162 PP_Var converted_string
;
164 // 0-length string should not dereference input string, and should produce
166 converted_string
= var_interface_
->VarFromUtf8(
167 pp::Module::Get()->pp_module(), NULL
, 0);
168 if (converted_string
.type
!= PP_VARTYPE_STRING
) {
169 return "Expected 0 length to return empty string.";
172 // Now convert it back.
173 uint32_t length
= kInvalidLength
;
174 const char* result
= NULL
;
175 result
= var_interface_
->VarToUtf8(converted_string
, &length
);
177 return "Expected 0 length string on conversion.";
179 if (result
== NULL
) {
180 return "Expected a non-null result for 0-lengthed string from VarToUtf8.";
182 var_interface_
->Release(converted_string
);
184 // Should not crash, and make an empty string.
185 const char* null_string
= NULL
;
186 pp::Var
null_var(null_string
);
187 if (!null_var
.is_string() || null_var
.AsString() != "") {
188 return "Expected NULL input to make an empty string Var.";
194 std::string
TestVarDeprecated::TestValidUtf8() {
195 // From UTF8 string -> PP_Var.
196 // Chinese for "I am utf8."
197 static const char kValidUtf8
[] = "\xe6\x88\x91\xe6\x98\xafutf8.";
198 pp::Var
converted_string(kValidUtf8
);
200 if (converted_string
.is_null())
201 return "Unable to convert valid utf8 to var.";
203 // Since we're already here, test PP_Var back to UTF8 string.
204 std::string returned_string
= converted_string
.AsString();
206 // We need to check against 1 less than sizeof because the resulting string
207 // is technically not NULL terminated by API design.
208 if (returned_string
.size() != sizeof(kValidUtf8
) - 1) {
209 return "Unable to convert utf8 string back from var.";
211 if (returned_string
!= kValidUtf8
) {
212 return "String mismatches on conversion back from PP_Var.";
218 std::string
TestVarDeprecated::TestUtf8WithEmbeddedNulls() {
219 // From UTF8 string with embedded nulls -> PP_Var.
220 // Chinese for "also utf8."
221 static const char kUtf8WithEmbededNull
[] = "\xe6\xb9\x9f\xe6\x98\xaf\0utf8.";
222 std::string
orig_string(kUtf8WithEmbededNull
,
223 sizeof(kUtf8WithEmbededNull
) -1);
224 pp::Var
converted_string(orig_string
);
226 if (converted_string
.is_null())
227 return "Unable to convert utf8 with embedded nulls to var.";
229 // Since we're already here, test PP_Var back to UTF8 string.
230 std::string returned_string
= converted_string
.AsString();
232 if (returned_string
.size() != orig_string
.size()) {
233 return "Unable to convert utf8 with embedded nulls back from var.";
235 if (returned_string
!= orig_string
) {
236 return "String mismatches on conversion back from PP_Var.";
242 std::string
TestVarDeprecated::TestVarToUtf8ForWrongType() {
243 uint32_t length
= kInvalidLength
;
244 const char* result
= NULL
;
245 result
= var_interface_
->VarToUtf8(PP_MakeUndefined(), &length
);
247 return "Expected 0 on string conversion from Void var.";
249 if (result
!= NULL
) {
250 return "Expected NULL on string conversion from Void var.";
253 length
= kInvalidLength
;
255 result
= var_interface_
->VarToUtf8(PP_MakeNull(), &length
);
257 return "Expected 0 on string conversion from Null var.";
259 if (result
!= NULL
) {
260 return "Expected NULL on string conversion from Null var.";
263 length
= kInvalidLength
;
265 result
= var_interface_
->VarToUtf8(PP_MakeBool(PP_TRUE
), &length
);
267 return "Expected 0 on string conversion from Bool var.";
269 if (result
!= NULL
) {
270 return "Expected NULL on string conversion from Bool var.";
273 length
= kInvalidLength
;
275 result
= var_interface_
->VarToUtf8(PP_MakeInt32(1), &length
);
277 return "Expected 0 on string conversion from Int32 var.";
279 if (result
!= NULL
) {
280 return "Expected NULL on string conversion from Int32 var.";
283 length
= kInvalidLength
;
285 result
= var_interface_
->VarToUtf8(PP_MakeDouble(1.0), &length
);
287 return "Expected 0 on string conversion from Double var.";
289 if (result
!= NULL
) {
290 return "Expected NULL on string conversion from Double var.";
296 std::string
TestVarDeprecated::TestHasPropertyAndMethod() {
297 pp::VarPrivate window
= instance_
->GetWindowObject();
298 ASSERT_TRUE(window
.is_object());
302 ASSERT_TRUE(window
.HasProperty("scrollX", &exception
));
303 ASSERT_TRUE(exception
.is_undefined());
304 ASSERT_FALSE(window
.HasMethod("scrollX", &exception
));
305 ASSERT_TRUE(exception
.is_undefined());
307 // Regular method (also counts as HasProperty).
308 ASSERT_TRUE(window
.HasProperty("find", &exception
));
309 ASSERT_TRUE(exception
.is_undefined());
310 ASSERT_TRUE(window
.HasMethod("find", &exception
));
311 ASSERT_TRUE(exception
.is_undefined());
313 // Nonexistant ones should return false and not set the exception.
314 ASSERT_FALSE(window
.HasProperty("superEvilBit", &exception
));
315 ASSERT_TRUE(exception
.is_undefined());
316 ASSERT_FALSE(window
.HasMethod("superEvilBit", &exception
));
317 ASSERT_TRUE(exception
.is_undefined());
319 // Check exception and return false on invalid property name.
320 ASSERT_FALSE(window
.HasProperty(3.14159, &exception
));
321 ASSERT_FALSE(exception
.is_undefined());
322 exception
= pp::Var();
324 exception
= pp::Var();
325 ASSERT_FALSE(window
.HasMethod(3.14159, &exception
));
326 ASSERT_FALSE(exception
.is_undefined());
328 // Try to use something not an object.
329 exception
= pp::Var();
330 pp::VarPrivate
string_object("asdf");
331 ASSERT_FALSE(string_object
.HasProperty("find", &exception
));
332 ASSERT_FALSE(exception
.is_undefined());
333 exception
= pp::Var();
334 ASSERT_FALSE(string_object
.HasMethod("find", &exception
));
335 ASSERT_FALSE(exception
.is_undefined());
337 // Try to use an invalid object (need to use the C API).
338 PP_Var invalid_object
;
339 invalid_object
.type
= PP_VARTYPE_OBJECT
;
340 invalid_object
.value
.as_id
= static_cast<int64_t>(-1234567);
341 PP_Var exception2
= PP_MakeUndefined();
342 ASSERT_FALSE(var_interface_
->HasProperty(invalid_object
,
343 pp::Var("find").pp_var(),
345 ASSERT_NE(PP_VARTYPE_UNDEFINED
, exception2
.type
);
346 var_interface_
->Release(exception2
);
348 exception2
= PP_MakeUndefined();
349 ASSERT_FALSE(var_interface_
->HasMethod(invalid_object
,
350 pp::Var("find").pp_var(),
352 ASSERT_NE(PP_VARTYPE_UNDEFINED
, exception2
.type
);
353 var_interface_
->Release(exception2
);
355 // Getting a valid property/method when the exception is set returns false.
356 exception
= pp::Var("Bad something-or-other exception");
357 ASSERT_FALSE(window
.HasProperty("find", &exception
));
358 ASSERT_FALSE(exception
.is_undefined());
359 ASSERT_FALSE(window
.HasMethod("find", &exception
));
360 ASSERT_FALSE(exception
.is_undefined());
365 // Tests that when the page sends an object to the plugin via a function call,
366 // that the refcounting works properly (bug 79813).
367 std::string
TestVarDeprecated::TestPassReference() {
368 var_from_page_
= pp::Var();
370 // Send a JS object from the page to the plugin.
372 pp::Var ret
= instance_
->ExecuteScript(
373 "document.getElementById('plugin').SetValue(function(arg) {"
374 "return 'works' + arg;"
377 ASSERT_TRUE(exception
.is_undefined());
379 // We should have gotten an object set for our var_from_page.
380 ASSERT_TRUE(var_from_page_
.is_object());
382 // If the reference counting works, the object should be valid. We can test
383 // this by executing it (it was a function we defined above) and it should
384 // return "works" concatenated with the argument.
385 pp::VarPrivate
function(var_from_page_
);
386 pp::Var result
= var_from_page_
.Call(pp::Var(), "nice");
387 ASSERT_TRUE(result
.is_string());
388 ASSERT_TRUE(result
.AsString() == "worksnice");
390 // Reset var_from_page_ so it doesn't seem like a leak to the var leak
392 var_from_page_
= pp::Var();