test_var_deprecated.cc 13 KB

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