1// Copyright (c) 2010 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 "content/test/plugin/plugin_test.h"
6
7#include "base/strings/string_number_conversions.h"
8#include "base/strings/string_util.h"
9#include "content/test/plugin/npapi_constants.h"
10
11namespace NPAPIClient {
12
13PluginTest::PluginTest(NPP id, NPNetscapeFuncs *host_functions) {
14  id_ = id;
15  id_->pdata = this;
16  host_functions_ = host_functions;
17  test_completed_ = false;
18}
19
20PluginTest::~PluginTest() {}
21
22bool PluginTest::IsWindowless() const { return false; }
23
24NPError PluginTest::New(uint16 mode, int16 argc, const char* argn[],
25                        const char* argv[], NPSavedData* saved) {
26  test_name_ = this->GetArgValue("name", argc, argn, argv);
27  const char* id = this->GetArgValue("id", argc, argn, argv);
28  if (id)  // NULL for NP_FULL
29    test_id_ = id;
30  return NPERR_NO_ERROR;
31}
32
33NPError PluginTest::Destroy() {
34  return NPERR_NO_ERROR;
35}
36
37NPError PluginTest::SetWindow(NPWindow* pNPWindow) {
38  return NPERR_NO_ERROR;
39}
40
41// It's a shame I have to implement URLEncode.  But, using webkit's
42// or using chrome's means a ball of string of dlls and dependencies that
43// is very very long.  After spending far too much time on it,
44// I'll just encode it myself.  Too bad Microsoft doesn't implement
45// this in a reusable way either.  Both webkit and chrome will
46// end up using libicu, which is a string of dependencies we don't
47// want.
48
49inline unsigned char toHex(const unsigned char x) {
50  return x > 9 ? (x + 'A' - 10) : (x + '0');
51}
52
53std::string URLEncode(const std::string &sIn) {
54  std::string sOut;
55
56  const size_t length = sIn.length();
57  for (size_t idx = 0; idx < length;) {
58    const char ch = sIn.at(idx);
59    if (isalnum(ch)) {
60      sOut.append(1, ch);
61    } else if (isspace(ch) && ((ch != '\n') && (ch != '\r'))) {
62      sOut.append(1, '+');
63    } else {
64      sOut.append(1, '%');
65      sOut.append(1, toHex(ch>>4));
66      sOut.append(1, toHex(ch%16));
67    }
68    idx++;
69  }
70  return sOut;
71}
72
73void PluginTest::SignalTestCompleted() {
74  NPObject *window_obj = NULL;
75  host_functions_->getvalue(id_, NPNVWindowNPObject, &window_obj);
76  if (!window_obj)
77    return;
78
79  test_completed_ = true;
80  // To signal test completion, we expect a couple of
81  // javascript functions to be defined in the webpage
82  // which hosts this plugin:
83  //    onSuccess(test_name, test_id)
84  //    onFailure(test_name, test_id, error_message)
85  std::string script("javascript:");
86  if (Succeeded()) {
87    script.append("onSuccess(\"");
88    script.append(test_name_);
89    script.append("\",\"");
90    script.append(test_id_);
91    script.append("\");");
92  } else {
93    script.append("onFailure(\"");
94    script.append(test_name_);
95    script.append("\",\"");
96    script.append(test_id_);
97    script.append("\",\"");
98    script.append(test_status_);
99    script.append("\");");
100  }
101
102  NPString script_string;
103  script_string.UTF8Characters = script.c_str();
104  script_string.UTF8Length = static_cast<unsigned int>(script.length());
105
106  NPVariant result_var;
107  host_functions_->evaluate(id_, window_obj, &script_string, &result_var);
108}
109
110const char *PluginTest::GetArgValue(const char *name, const int16 argc,
111                                    const char *argn[], const char *argv[]) {
112  for (int idx = 0; idx < argc; idx++)
113    if (base::strcasecmp(argn[idx], name) == 0)
114      return argv[idx];
115  return NULL;
116}
117
118void PluginTest::SetError(const std::string &msg) {
119  test_status_.append(msg);
120}
121
122void PluginTest::ExpectStringLowerCaseEqual(const std::string &val1,
123                                            const std::string &val2) {
124  if (!LowerCaseEqualsASCII(val1, val2.c_str())) {
125    std::string err;
126    err = "Expected Equal for '";
127    err.append(val1);
128    err.append("' and '");
129    err.append(val2);
130    err.append("'");
131    SetError(err);
132  }
133}
134
135void PluginTest::ExpectAsciiStringNotEqual(const char *val1, const char *val2) {
136  if (val1 == val2) {
137    std::string err;
138    err = "Expected Not Equal for '";
139    err.append(val1);
140    err.append("' and '");
141    err.append(val2);
142    err.append("'");
143    SetError(err);
144  }
145}
146
147void PluginTest::ExpectIntegerEqual(int val1, int val2) {
148  if (val1 != val2) {
149    std::string err;
150    err = "Expected Equal for '";
151    err.append(base::IntToString(val1));
152    err.append("' and '");
153    err.append(base::IntToString(val2));
154    err.append("'");
155    SetError(err);
156  }
157}
158
159NPError PluginTest::NewStream(NPMIMEType type, NPStream* stream,
160                              NPBool seekable, uint16* stype) {
161  // There is no default action here.
162  return NPERR_NO_ERROR;
163}
164
165int32 PluginTest::WriteReady(NPStream *stream) {
166  // Take data in small chunks
167  return 4096;
168}
169
170int32 PluginTest::Write(NPStream *stream, int32 offset, int32 len,
171                           void *buffer) {
172  // Pretend that we took all the data.
173  return len;
174}
175
176NPError PluginTest::DestroyStream(NPStream *stream, NPError reason) {
177  // There is no default action.
178  return NPERR_NO_ERROR;
179}
180
181void PluginTest::StreamAsFile(NPStream* stream, const char* fname) {
182  // There is no default action.
183}
184
185void PluginTest::URLNotify(const char* url, NPReason reason, void* data) {
186  // There is no default action
187}
188
189int16 PluginTest::HandleEvent(void* event) {
190  // There is no default action
191  return 0;
192}
193
194void PluginTest::URLRedirectNotify(const char* url, int32_t status,
195                                   void* notify_data) {
196  // There is no default action
197}
198
199} // namespace NPAPIClient
200