1// Copyright (c) 2013 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 <list>
6#include <string>
7
8#include "base/compiler_specific.h"
9#include "base/memory/scoped_ptr.h"
10#include "base/values.h"
11#include "chrome/test/chromedriver/chrome/devtools_client.h"
12#include "chrome/test/chromedriver/chrome/status.h"
13#include "chrome/test/chromedriver/chrome/web_view_impl.h"
14#include "testing/gtest/include/gtest/gtest.h"
15
16namespace {
17
18class FakeDevToolsClient : public DevToolsClient {
19 public:
20  FakeDevToolsClient() : id_("fake-id"), status_(kOk) {}
21  virtual ~FakeDevToolsClient() {}
22
23  void set_status(const Status& status) {
24    status_ = status;
25  }
26  void set_result(const base::DictionaryValue& result) {
27    result_.Clear();
28    result_.MergeDictionary(&result);
29  }
30
31  // Overridden from DevToolsClient:
32  virtual const std::string& GetId() OVERRIDE {
33    return id_;
34  }
35  virtual bool WasCrashed() OVERRIDE {
36    return false;
37  }
38  virtual Status ConnectIfNecessary() OVERRIDE {
39    return Status(kOk);
40  }
41  virtual Status SendCommand(const std::string& method,
42                             const base::DictionaryValue& params) OVERRIDE {
43    return SendCommandAndGetResult(method, params, NULL);
44  }
45  virtual Status SendCommandAndGetResult(
46      const std::string& method,
47      const base::DictionaryValue& params,
48      scoped_ptr<base::DictionaryValue>* result) OVERRIDE {
49    if (status_.IsError())
50      return status_;
51    result->reset(result_.DeepCopy());
52    return Status(kOk);
53  }
54  virtual void AddListener(DevToolsEventListener* listener) OVERRIDE {}
55  virtual Status HandleEventsUntil(
56      const ConditionalFunc& conditional_func,
57      const base::TimeDelta& timeout) OVERRIDE {
58    return Status(kOk);
59  }
60  virtual Status HandleReceivedEvents() OVERRIDE {
61    return Status(kOk);
62  }
63
64 private:
65  const std::string id_;
66  Status status_;
67  base::DictionaryValue result_;
68};
69
70void AssertEvalFails(const base::DictionaryValue& command_result) {
71  scoped_ptr<base::DictionaryValue> result;
72  FakeDevToolsClient client;
73  client.set_result(command_result);
74  Status status = internal::EvaluateScript(
75      &client, 0, std::string(), internal::ReturnByValue, &result);
76  ASSERT_EQ(kUnknownError, status.code());
77  ASSERT_FALSE(result);
78}
79
80}  // namespace
81
82TEST(EvaluateScript, CommandError) {
83  scoped_ptr<base::DictionaryValue> result;
84  FakeDevToolsClient client;
85  client.set_status(Status(kUnknownError));
86  Status status = internal::EvaluateScript(
87      &client, 0, std::string(), internal::ReturnByValue, &result);
88  ASSERT_EQ(kUnknownError, status.code());
89  ASSERT_FALSE(result);
90}
91
92TEST(EvaluateScript, MissingWasThrown) {
93  base::DictionaryValue dict;
94  ASSERT_NO_FATAL_FAILURE(AssertEvalFails(dict));
95}
96
97TEST(EvaluateScript, MissingResult) {
98  base::DictionaryValue dict;
99  dict.SetBoolean("wasThrown", false);
100  ASSERT_NO_FATAL_FAILURE(AssertEvalFails(dict));
101}
102
103TEST(EvaluateScript, Throws) {
104  base::DictionaryValue dict;
105  dict.SetBoolean("wasThrown", true);
106  dict.SetString("result.type", "undefined");
107  ASSERT_NO_FATAL_FAILURE(AssertEvalFails(dict));
108}
109
110TEST(EvaluateScript, Ok) {
111  scoped_ptr<base::DictionaryValue> result;
112  base::DictionaryValue dict;
113  dict.SetBoolean("wasThrown", false);
114  dict.SetInteger("result.key", 100);
115  FakeDevToolsClient client;
116  client.set_result(dict);
117  ASSERT_TRUE(internal::EvaluateScript(
118      &client, 0, std::string(), internal::ReturnByValue, &result).IsOk());
119  ASSERT_TRUE(result);
120  ASSERT_TRUE(result->HasKey("key"));
121}
122
123TEST(EvaluateScriptAndGetValue, MissingType) {
124  scoped_ptr<base::Value> result;
125  FakeDevToolsClient client;
126  base::DictionaryValue dict;
127  dict.SetBoolean("wasThrown", false);
128  dict.SetInteger("result.value", 1);
129  client.set_result(dict);
130  ASSERT_TRUE(internal::EvaluateScriptAndGetValue(
131      &client, 0, std::string(), &result).IsError());
132}
133
134TEST(EvaluateScriptAndGetValue, Undefined) {
135  scoped_ptr<base::Value> result;
136  FakeDevToolsClient client;
137  base::DictionaryValue dict;
138  dict.SetBoolean("wasThrown", false);
139  dict.SetString("result.type", "undefined");
140  client.set_result(dict);
141  Status status =
142      internal::EvaluateScriptAndGetValue(&client, 0, std::string(), &result);
143  ASSERT_EQ(kOk, status.code());
144  ASSERT_TRUE(result && result->IsType(base::Value::TYPE_NULL));
145}
146
147TEST(EvaluateScriptAndGetValue, Ok) {
148  scoped_ptr<base::Value> result;
149  FakeDevToolsClient client;
150  base::DictionaryValue dict;
151  dict.SetBoolean("wasThrown", false);
152  dict.SetString("result.type", "integer");
153  dict.SetInteger("result.value", 1);
154  client.set_result(dict);
155  Status status =
156      internal::EvaluateScriptAndGetValue(&client, 0, std::string(), &result);
157  ASSERT_EQ(kOk, status.code());
158  int value;
159  ASSERT_TRUE(result && result->GetAsInteger(&value));
160  ASSERT_EQ(1, value);
161}
162
163TEST(EvaluateScriptAndGetObject, NoObject) {
164  FakeDevToolsClient client;
165  base::DictionaryValue dict;
166  dict.SetBoolean("wasThrown", false);
167  dict.SetString("result.type", "integer");
168  client.set_result(dict);
169  bool got_object;
170  std::string object_id;
171  ASSERT_TRUE(internal::EvaluateScriptAndGetObject(
172      &client, 0, std::string(), &got_object, &object_id).IsOk());
173  ASSERT_FALSE(got_object);
174  ASSERT_TRUE(object_id.empty());
175}
176
177TEST(EvaluateScriptAndGetObject, Ok) {
178  FakeDevToolsClient client;
179  base::DictionaryValue dict;
180  dict.SetBoolean("wasThrown", false);
181  dict.SetString("result.objectId", "id");
182  client.set_result(dict);
183  bool got_object;
184  std::string object_id;
185  ASSERT_TRUE(internal::EvaluateScriptAndGetObject(
186      &client, 0, std::string(), &got_object, &object_id).IsOk());
187  ASSERT_TRUE(got_object);
188  ASSERT_STREQ("id", object_id.c_str());
189}
190
191TEST(ParseCallFunctionResult, NotDict) {
192  scoped_ptr<base::Value> result;
193  base::FundamentalValue value(1);
194  ASSERT_NE(kOk, internal::ParseCallFunctionResult(value, &result).code());
195}
196
197TEST(ParseCallFunctionResult, Ok) {
198  scoped_ptr<base::Value> result;
199  base::DictionaryValue dict;
200  dict.SetInteger("status", 0);
201  dict.SetInteger("value", 1);
202  Status status = internal::ParseCallFunctionResult(dict, &result);
203  ASSERT_EQ(kOk, status.code());
204  int value;
205  ASSERT_TRUE(result && result->GetAsInteger(&value));
206  ASSERT_EQ(1, value);
207}
208
209TEST(ParseCallFunctionResult, ScriptError) {
210  scoped_ptr<base::Value> result;
211  base::DictionaryValue dict;
212  dict.SetInteger("status", 1);
213  dict.SetInteger("value", 1);
214  Status status = internal::ParseCallFunctionResult(dict, &result);
215  ASSERT_EQ(1, status.code());
216  ASSERT_FALSE(result);
217}
218