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.h"
6
7#include <string.h>
8
9#include <limits>
10
11#include "ppapi/c/dev/ppb_testing_dev.h"
12#include "ppapi/c/pp_var.h"
13#include "ppapi/c/ppb_var.h"
14#include "ppapi/cpp/instance.h"
15#include "ppapi/cpp/module.h"
16#include "ppapi/cpp/var.h"
17#include "ppapi/tests/testing_instance.h"
18
19namespace {
20
21uint32_t kInvalidLength = static_cast<uint32_t>(-1);
22
23}  // namespace
24
25REGISTER_TEST_CASE(Var);
26
27bool TestVar::Init() {
28  var_interface_ = static_cast<const PPB_Var*>(
29      pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE));
30  return var_interface_ && CheckTestingInterface();
31}
32
33void TestVar::RunTests(const std::string& filter) {
34  RUN_TEST(BasicString, filter);
35  RUN_TEST(InvalidAndEmpty, filter);
36  RUN_TEST(InvalidUtf8, filter);
37  RUN_TEST(NullInputInUtf8Conversion, filter);
38  RUN_TEST(ValidUtf8, filter);
39  RUN_TEST(Utf8WithEmbeddedNulls, filter);
40  RUN_TEST(VarToUtf8ForWrongType, filter);
41}
42
43std::string TestVar::TestBasicString() {
44  uint32_t before_object = testing_interface_->GetLiveObjectsForInstance(
45      instance_->pp_instance());
46  {
47    const char kStr[] = "Hello";
48    const uint32_t kStrLen(sizeof(kStr) - 1);
49    PP_Var str = var_interface_->VarFromUtf8(kStr, kStrLen);
50    ASSERT_EQ(PP_VARTYPE_STRING, str.type);
51
52    // Reading back the string should work.
53    uint32_t len = 0;
54    const char* result = var_interface_->VarToUtf8(str, &len);
55    ASSERT_EQ(kStrLen, len);
56    ASSERT_EQ(0, strncmp(kStr, result, kStrLen));
57
58    // Destroy the string, readback should now fail.
59    var_interface_->Release(str);
60    result = var_interface_->VarToUtf8(str, &len);
61    ASSERT_EQ(0, len);
62    ASSERT_EQ(NULL, result);
63  }
64
65  // Make sure we can assign a C++ object to itself and it stays alive.
66  {
67    pp::Var a("test");
68    a = a;
69    ASSERT_TRUE(a.AsString() == "test");
70  }
71
72  // Make sure nothing leaked.
73  ASSERT_TRUE(testing_interface_->GetLiveObjectsForInstance(
74      instance_->pp_instance()) == before_object);
75
76  PASS();
77}
78
79std::string TestVar::TestInvalidAndEmpty() {
80  PP_Var invalid_string;
81  invalid_string.type = PP_VARTYPE_STRING;
82  invalid_string.value.as_id = 31415926;
83
84  // Invalid strings should give NULL as the return value.
85  uint32_t len = std::numeric_limits<uint32_t>::max();
86  const char* result = var_interface_->VarToUtf8(invalid_string, &len);
87  ASSERT_EQ(0, len);
88  ASSERT_EQ(NULL, result);
89
90  // Same with vars that are not strings.
91  len = std::numeric_limits<uint32_t>::max();
92  pp::Var int_var(42);
93  result = var_interface_->VarToUtf8(int_var.pp_var(), &len);
94  ASSERT_EQ(0, len);
95  ASSERT_EQ(NULL, result);
96
97  // Empty strings should return non-NULL.
98  pp::Var empty_string("");
99  len = std::numeric_limits<uint32_t>::max();
100  result = var_interface_->VarToUtf8(empty_string.pp_var(), &len);
101  ASSERT_EQ(0, len);
102  ASSERT_NE(NULL, result);
103
104  PASS();
105}
106
107std::string TestVar::TestInvalidUtf8() {
108  // utf8じゃない (japanese for "is not utf8") in shift-jis encoding.
109  static const char kSjisString[] = "utf8\x82\xb6\x82\xe1\x82\xc8\x82\xa2";
110  pp::Var sjis(kSjisString);
111  if (!sjis.is_null())
112    return "Non-UTF8 string was permitted erroneously.";
113
114  PASS();
115}
116
117std::string TestVar::TestNullInputInUtf8Conversion() {
118  // This test talks directly to the C interface to access edge cases that
119  // cannot be exercised via the C++ interface.
120  PP_Var converted_string;
121
122  // 0-length string should not dereference input string, and should produce
123  // an empty string.
124  converted_string = var_interface_->VarFromUtf8(NULL, 0);
125  if (converted_string.type != PP_VARTYPE_STRING) {
126    return "Expected 0 length to return empty string.";
127  }
128
129  // Now convert it back.
130  uint32_t length = kInvalidLength;
131  const char* result = NULL;
132  result = var_interface_->VarToUtf8(converted_string, &length);
133  if (length != 0) {
134    return "Expected 0 length string on conversion.";
135  }
136  if (result == NULL) {
137    return "Expected a non-null result for 0-lengthed string from VarToUtf8.";
138  }
139  var_interface_->Release(converted_string);
140
141  // Should not crash, and make an empty string.
142  const char* null_string = NULL;
143  pp::Var null_var(null_string);
144  if (!null_var.is_string() || null_var.AsString() != "") {
145    return "Expected NULL input to make an empty string Var.";
146  }
147
148  PASS();
149}
150
151std::string TestVar::TestValidUtf8() {
152  // From UTF8 string -> PP_Var.
153  // Chinese for "I am utf8."
154  static const char kValidUtf8[] = "\xe6\x88\x91\xe6\x98\xafutf8.";
155  pp::Var converted_string(kValidUtf8);
156
157  if (converted_string.is_null())
158    return "Unable to convert valid utf8 to var.";
159
160  // Since we're already here, test PP_Var back to UTF8 string.
161  std::string returned_string = converted_string.AsString();
162
163  // We need to check against 1 less than sizeof because the resulting string
164  // is technically not NULL terminated by API design.
165  if (returned_string.size() != sizeof(kValidUtf8) - 1) {
166    return "Unable to convert utf8 string back from var.";
167  }
168  if (returned_string != kValidUtf8) {
169    return "String mismatches on conversion back from PP_Var.";
170  }
171
172  PASS();
173}
174
175std::string TestVar::TestUtf8WithEmbeddedNulls() {
176  // From UTF8 string with embedded nulls -> PP_Var.
177  // Chinese for "also utf8."
178  static const char kUtf8WithEmbededNull[] = "\xe6\xb9\x9f\xe6\x98\xaf\0utf8.";
179  std::string orig_string(kUtf8WithEmbededNull,
180                          sizeof(kUtf8WithEmbededNull) -1);
181  pp::Var converted_string(orig_string);
182
183  if (converted_string.is_null())
184    return "Unable to convert utf8 with embedded nulls to var.";
185
186  // Since we're already here, test PP_Var back to UTF8 string.
187  std::string returned_string = converted_string.AsString();
188
189  if (returned_string.size() != orig_string.size()) {
190    return "Unable to convert utf8 with embedded nulls back from var.";
191  }
192  if (returned_string != orig_string) {
193    return "String mismatches on conversion back from PP_Var.";
194  }
195
196  PASS();
197}
198
199std::string TestVar::TestVarToUtf8ForWrongType() {
200  uint32_t length = kInvalidLength;
201  const char* result = NULL;
202  result = var_interface_->VarToUtf8(PP_MakeUndefined(), &length);
203  if (length != 0) {
204    return "Expected 0 on string conversion from Void var.";
205  }
206  if (result != NULL) {
207    return "Expected NULL on string conversion from Void var.";
208  }
209
210  length = kInvalidLength;
211  result = NULL;
212  result = var_interface_->VarToUtf8(PP_MakeNull(), &length);
213  if (length != 0) {
214    return "Expected 0 on string conversion from Null var.";
215  }
216  if (result != NULL) {
217    return "Expected NULL on string conversion from Null var.";
218  }
219
220  length = kInvalidLength;
221  result = NULL;
222  result = var_interface_->VarToUtf8(PP_MakeBool(PP_TRUE), &length);
223  if (length != 0) {
224    return "Expected 0 on string conversion from Bool var.";
225  }
226  if (result != NULL) {
227    return "Expected NULL on string conversion from Bool var.";
228  }
229
230  length = kInvalidLength;
231  result = NULL;
232  result = var_interface_->VarToUtf8(PP_MakeInt32(1), &length);
233  if (length != 0) {
234    return "Expected 0 on string conversion from Int32 var.";
235  }
236  if (result != NULL) {
237    return "Expected NULL on string conversion from Int32 var.";
238  }
239
240  length = kInvalidLength;
241  result = NULL;
242  result = var_interface_->VarToUtf8(PP_MakeDouble(1.0), &length);
243  if (length != 0) {
244    return "Expected 0 on string conversion from Double var.";
245  }
246  if (result != NULL) {
247    return "Expected NULL on string conversion from Double var.";
248  }
249
250  PASS();
251}
252
253