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