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