summaryrefslogtreecommitdiffstats
path: root/chrome/test/automation
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
commit09911bf300f1a419907a9412154760efd0b7abc3 (patch)
treef131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/test/automation
parent586acc5fe142f498261f52c66862fa417c3d52d2 (diff)
downloadchromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/test/automation')
-rw-r--r--chrome/test/automation/SConscript58
-rw-r--r--chrome/test/automation/autocomplete_edit_proxy.cc136
-rw-r--r--chrome/test/automation/autocomplete_edit_proxy.h169
-rw-r--r--chrome/test/automation/automation.vcproj193
-rw-r--r--chrome/test/automation/automation.vsprops11
-rw-r--r--chrome/test/automation/automation_constants.h38
-rw-r--r--chrome/test/automation/automation_handle_tracker.cc97
-rw-r--r--chrome/test/automation/automation_handle_tracker.h128
-rw-r--r--chrome/test/automation/automation_messages.h65
-rw-r--r--chrome/test/automation/automation_messages_internal.h723
-rw-r--r--chrome/test/automation/automation_proxy.cc567
-rw-r--r--chrome/test/automation/automation_proxy.h240
-rw-r--r--chrome/test/automation/automation_proxy_uitest.cc831
-rw-r--r--chrome/test/automation/browser_proxy.cc348
-rw-r--r--chrome/test/automation/browser_proxy.h164
-rw-r--r--chrome/test/automation/constrained_window_proxy.cc92
-rw-r--r--chrome/test/automation/constrained_window_proxy.h59
-rw-r--r--chrome/test/automation/tab_proxy.cc920
-rw-r--r--chrome/test/automation/tab_proxy.h266
-rw-r--r--chrome/test/automation/ui_controls.cc0
-rw-r--r--chrome/test/automation/ui_controls.h0
-rw-r--r--chrome/test/automation/window_proxy.cc187
-rw-r--r--chrome/test/automation/window_proxy.h106
23 files changed, 5398 insertions, 0 deletions
diff --git a/chrome/test/automation/SConscript b/chrome/test/automation/SConscript
new file mode 100644
index 0000000..79286f2
--- /dev/null
+++ b/chrome/test/automation/SConscript
@@ -0,0 +1,58 @@
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Import('env')
+
+env = env.Clone()
+
+env.Prepend(
+ CPPPATH = [
+ #'../../..',
+ #'$GTEST_DIR/include',
+ '$SKIA_DIR/include',
+ '$SKIA_DIR/include/corecg',
+ '$SKIA_DIR/platform',
+ '#/..',
+ ],
+)
+
+input_files = [
+ 'autocomplete_edit_proxy.cc',
+ 'automation_handle_tracker.cc',
+ 'automation_proxy.cc',
+ 'browser_proxy.cc',
+ 'constrained_window_proxy.cc',
+ 'tab_proxy.cc',
+ 'window_proxy.cc',
+]
+
+lib = env.StaticLibrary('automation', input_files)
+
+i = env.Install('$TARGET_ROOT', lib)
+env.Alias('chrome', i)
diff --git a/chrome/test/automation/autocomplete_edit_proxy.cc b/chrome/test/automation/autocomplete_edit_proxy.cc
new file mode 100644
index 0000000..33303ad
--- /dev/null
+++ b/chrome/test/automation/autocomplete_edit_proxy.cc
@@ -0,0 +1,136 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/test/automation/autocomplete_edit_proxy.h"
+
+#include <vector>
+
+#include "chrome/test/automation/automation_constants.h"
+#include "chrome/test/automation/automation_messages.h"
+#include "chrome/test/automation/automation_proxy.h"
+
+bool AutocompleteEditProxy::GetText(std::wstring* text) const {
+ if (!is_valid())
+ return false;
+ if (!text) {
+ NOTREACHED();
+ return false;
+ }
+
+ IPC::Message* response = NULL;
+ if (!sender_->SendAndWaitForResponse(
+ new AutomationMsg_AutocompleteEditGetTextRequest(0, handle_), &response,
+ AutomationMsg_AutocompleteEditGetTextResponse::ID))
+ return false;
+ scoped_ptr<IPC::Message> response_deleter(response);
+
+ Tuple2<bool, std::wstring> returned_result;
+ if (!AutomationMsg_AutocompleteEditGetTextResponse::Read(response,
+ &returned_result) || !returned_result.a)
+ return false;
+
+ text->swap(returned_result.b);
+ return true;
+}
+
+bool AutocompleteEditProxy::SetText(const std::wstring& text) {
+ if (!is_valid())
+ return false;
+
+ IPC::Message* response = NULL;
+ if (!sender_->SendAndWaitForResponse(
+ new AutomationMsg_AutocompleteEditSetTextRequest(0, handle_, text),
+ &response, AutomationMsg_AutocompleteEditSetTextResponse::ID))
+ return false;
+
+ delete response;
+ return true;
+}
+
+bool AutocompleteEditProxy::IsQueryInProgress(bool* query_in_progress) const {
+ if (!is_valid())
+ return false;
+ if (!query_in_progress) {
+ NOTREACHED();
+ return false;
+ }
+
+ IPC::Message* response = NULL;
+ if (!sender_->SendAndWaitForResponse(
+ new AutomationMsg_AutocompleteEditIsQueryInProgressRequest(0, handle_),
+ &response, AutomationMsg_AutocompleteEditIsQueryInProgressResponse::ID))
+ return false;
+ scoped_ptr<IPC::Message> response_deleter(response);
+
+ Tuple2<bool, bool> returned_result;
+ if (!AutomationMsg_AutocompleteEditIsQueryInProgressResponse::Read(
+ response, &returned_result) || !returned_result.a)
+ return false;
+
+ *query_in_progress = returned_result.b;
+ return true;
+}
+
+
+bool AutocompleteEditProxy::WaitForQuery(int wait_timeout_ms) const {
+ const TimeTicks start = TimeTicks::Now();
+ const TimeDelta timeout = TimeDelta::FromMilliseconds(wait_timeout_ms);
+ bool query_in_progress;
+ while (TimeTicks::Now() - start < timeout) {
+ if (IsQueryInProgress(&query_in_progress) && !query_in_progress)
+ return true;
+ Sleep(automation::kSleepTime);
+ }
+ // If we get here the query is still in progress.
+ return false;
+}
+
+bool AutocompleteEditProxy::GetAutocompleteMatches(Matches* matches) const {
+ if (!is_valid())
+ return false;
+ if (!matches) {
+ NOTREACHED();
+ return false;
+ }
+
+ IPC::Message* response = NULL;
+ if (!sender_->SendAndWaitForResponse(
+ new AutomationMsg_AutocompleteEditGetMatchesRequest(0, handle_),
+ &response, AutomationMsg_AutocompleteEditGetMatchesResponse::ID))
+ return false;
+ scoped_ptr<IPC::Message> response_deleter(response);
+
+ Tuple2<bool, Matches> returned_result;
+ if (!AutomationMsg_AutocompleteEditGetMatchesResponse::Read(
+ response, &returned_result) || !returned_result.a)
+ return false;
+
+ *matches = returned_result.b;
+ return true;
+}
diff --git a/chrome/test/automation/autocomplete_edit_proxy.h b/chrome/test/automation/autocomplete_edit_proxy.h
new file mode 100644
index 0000000..608d1f1
--- /dev/null
+++ b/chrome/test/automation/autocomplete_edit_proxy.h
@@ -0,0 +1,169 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_TEST_AUTOMATION_AUTOCOMPLETE_EDIT_PROXY_H__
+#define CHROME_TEST_AUTOMATION_AUTOCOMPLETE_EDIT_PROXY_H__
+
+#include <string>
+#include <vector>
+
+#include "chrome/browser/autocomplete/autocomplete.h"
+#include "chrome/common/ipc_message.h"
+#include "chrome/common/ipc_message_utils.h"
+#include "chrome/test/automation/automation_handle_tracker.h"
+
+// The purpose of this class is to act as a searializable version of
+// AutocompleteMatch. The reason for this class is because we don't want to
+// searialize all elements of AutocompleteMatch and we want some data from the
+// autocomplete provider without the hassle of serializing it.
+struct AutocompleteMatchData {
+ public:
+ AutocompleteMatchData() {}
+ explicit AutocompleteMatchData(const AutocompleteMatch& match)
+ : contents(match.contents),
+ deletable(match.deletable),
+ description(match.description),
+ destination_url(match.destination_url),
+ fill_into_edit(match.fill_into_edit),
+ inline_autocomplete_offset(match.inline_autocomplete_offset),
+ is_history_what_you_typed_match(match.is_history_what_you_typed_match),
+ provider_name(match.provider->name()),
+ relevance(match.relevance),
+ starred(match.starred) {
+ switch (match.type) {
+ case AutocompleteMatch::URL:
+ str_type = L"URL";
+ break;
+ case AutocompleteMatch::KEYWORD:
+ str_type = L"KEYWORD";
+ break;
+ case AutocompleteMatch::SEARCH:
+ str_type = L"SEARCH";
+ break;
+ case AutocompleteMatch::HISTORY_SEARCH:
+ str_type = L"HISTORY";
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+ std::wstring contents;
+ bool deletable;
+ std::wstring description;
+ std::wstring destination_url;
+ std::wstring fill_into_edit;
+ size_t inline_autocomplete_offset;
+ bool is_history_what_you_typed_match;
+ std::string provider_name;
+ int relevance;
+ bool starred;
+ std::wstring str_type;
+};
+typedef std::vector<AutocompleteMatchData> Matches;
+
+namespace IPC {
+
+template <>
+struct ParamTraits<AutocompleteMatchData> {
+ typedef AutocompleteMatchData param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteWString(p.contents);
+ m->WriteBool(p.deletable);
+ m->WriteWString(p.description);
+ m->WriteWString(p.destination_url);
+ m->WriteWString(p.fill_into_edit);
+ m->WriteSize(p.inline_autocomplete_offset);
+ m->WriteBool(p.is_history_what_you_typed_match);
+ m->WriteString(p.provider_name);
+ m->WriteInt(p.relevance);
+ m->WriteBool(p.starred);
+ m->WriteWString(p.str_type);
+ }
+
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ return m->ReadWString(iter, &r->contents) &&
+ m->ReadBool(iter, &r->deletable) &&
+ m->ReadWString(iter, &r->description) &&
+ m->ReadWString(iter, &r->destination_url) &&
+ m->ReadWString(iter, &r->fill_into_edit) &&
+ m->ReadSize(iter, &r->inline_autocomplete_offset) &&
+ m->ReadBool(iter, &r->is_history_what_you_typed_match) &&
+ m->ReadString(iter, &r->provider_name) &&
+ m->ReadInt(iter, &r->relevance) &&
+ m->ReadBool(iter, &r->starred) &&
+ m->ReadWString(iter, &r->str_type);
+ }
+
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(StringPrintf(L"[%S %s %S %S %S %d %s %s %d %s %S]",
+ p.contents, p.deletable ? "true" : "false", p.description,
+ p.destination_url, p.fill_into_edit, p.inline_autocomplete_offset,
+ p.is_history_what_you_typed_match ? "true" : "false", p.provider_name,
+ p.relevance, p.starred ? "true" : "false", p.str_type));
+ }
+};
+} // namespace IPC
+
+class AutocompleteEditProxy : public AutomationResourceProxy {
+ public:
+ AutocompleteEditProxy(AutomationMessageSender* sender,
+ AutomationHandleTracker* tracker,
+ int handle)
+ : AutomationResourceProxy(tracker, sender, handle) {}
+ virtual ~AutocompleteEditProxy() {}
+
+ // All these functions return true if the autocomplete edit is valid and
+ // there are no IPC errors.
+
+ // Gets the text visible in the omnibox.
+ bool GetText(std::wstring* text) const;
+
+ // Sets the text visible in the omnibox.
+ bool SetText(const std::wstring& text);
+
+ // Determines if a query to an autocomplete provider is still in progress.
+ // NOTE: No autocomplete queries will be made if the omnibox doesn't have
+ // focus. This can be achieved by sending a IDC_FOCUS_LOCATION accelerator
+ // to the browser.
+ bool IsQueryInProgress(bool* query_in_progress) const;
+
+ // Gets a list of autocomplete matches that have been gathered so far.
+ bool GetAutocompleteMatches(Matches* matches) const;
+
+ // Waits for all queries to autocomplete providers to complete.
+ // |wait_timeout_ms| gives the number of milliseconds to wait for the query
+ // to finish. Returns false if IPC call failed or if the function times out.
+ bool WaitForQuery(int wait_timeout_ms) const;
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(AutocompleteEditProxy);
+};
+
+#endif // #define CHROME_TEST_AUTOMATION_AUTOCOMPLETE_EDIT_PROXY_H__
+
diff --git a/chrome/test/automation/automation.vcproj b/chrome/test/automation/automation.vcproj
new file mode 100644
index 0000000..38781fc
--- /dev/null
+++ b/chrome/test/automation/automation.vcproj
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="automation"
+ ProjectGUID="{1556EF78-C7E6-43C8-951F-F6B43AC0DD12}"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;.\automation.vsprops"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;.\automation.vsprops"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath=".\autocomplete_edit_proxy.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\autocomplete_edit_proxy.h"
+ >
+ </File>
+ <File
+ RelativePath=".\automation_constants.h"
+ >
+ </File>
+ <File
+ RelativePath=".\automation_handle_tracker.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\automation_handle_tracker.h"
+ >
+ </File>
+ <File
+ RelativePath=".\automation_messages.h"
+ >
+ </File>
+ <File
+ RelativePath=".\automation_messages_internal.h"
+ >
+ </File>
+ <File
+ RelativePath=".\automation_proxy.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\automation_proxy.h"
+ >
+ </File>
+ <File
+ RelativePath=".\browser_proxy.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\browser_proxy.h"
+ >
+ </File>
+ <File
+ RelativePath=".\constrained_window_proxy.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\constrained_window_proxy.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tab_proxy.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\tab_proxy.h"
+ >
+ </File>
+ <File
+ RelativePath=".\window_proxy.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\window_proxy.h"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/chrome/test/automation/automation.vsprops b/chrome/test/automation/automation.vsprops
new file mode 100644
index 0000000..4cc3b79
--- /dev/null
+++ b/chrome/test/automation/automation.vsprops
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="automation"
+ InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\skia\using_skia.vsprops"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+</VisualStudioPropertySheet>
diff --git a/chrome/test/automation/automation_constants.h b/chrome/test/automation/automation_constants.h
new file mode 100644
index 0000000..994d233
--- /dev/null
+++ b/chrome/test/automation/automation_constants.h
@@ -0,0 +1,38 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_TEST_AUTOMATION_AUTOMATION_CONSTANTS_H__
+#define CHROME_TEST_AUTOMATION_AUTOMATION_CONSTANTS_H__
+
+namespace automation {
+ // Amount of time to wait before querying the browser.
+ static const int kSleepTime = 250;
+}
+
+#endif // CHROME_TEST_AUTOMATION_AUTOMATION_CONSTANTS_H__ \ No newline at end of file
diff --git a/chrome/test/automation/automation_handle_tracker.cc b/chrome/test/automation/automation_handle_tracker.cc
new file mode 100644
index 0000000..a31d125
--- /dev/null
+++ b/chrome/test/automation/automation_handle_tracker.cc
@@ -0,0 +1,97 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/test/automation/automation_handle_tracker.h"
+
+#include "chrome/test/automation/automation_messages.h"
+#include "chrome/test/automation/automation_proxy.h"
+
+AutomationResourceProxy::AutomationResourceProxy(
+ AutomationHandleTracker* tracker, AutomationMessageSender* sender,
+ AutomationHandle handle)
+ : tracker_(tracker),
+ sender_(sender),
+ handle_(handle),
+ is_valid_(true) {
+ tracker_->Add(this);
+}
+
+AutomationResourceProxy::~AutomationResourceProxy() {
+ if (tracker_)
+ tracker_->Remove(this);
+}
+
+AutomationHandleTracker::~AutomationHandleTracker() {
+ // Tell any live objects that the tracker is going away so they don't try to
+ // call us when they are being destroyed.
+ for (HandleToObjectMap::iterator iter = handle_to_object_.begin();
+ iter != handle_to_object_.end(); ++iter) {
+ iter->second->Invalidate();
+ iter->second->TrackerGone();
+ }
+}
+
+void AutomationHandleTracker::Add(AutomationResourceProxy* proxy) {
+ handle_to_object_.insert(MapEntry(proxy->handle(), proxy));
+}
+
+void AutomationHandleTracker::Remove(AutomationResourceProxy* proxy) {
+ HandleToObjectMap::iterator iter = handle_to_object_.find(proxy->handle());
+ if (iter == handle_to_object_.end())
+ return;
+
+ HandleToObjectMap::iterator end_of_matching_objects =
+ handle_to_object_.upper_bound(proxy->handle());
+
+ while(iter != end_of_matching_objects) {
+ if (iter->second == proxy) {
+ handle_to_object_.erase(iter);
+
+ // If we have no more proxy objects using this handle, tell the
+ // app that it can clean up that handle. If the proxy isn't valid,
+ // that means that the app has already discarded this handle, and
+ // thus doesn't need to be notified that the handle is unused.
+ if (proxy->is_valid() && handle_to_object_.count(proxy->handle()) == 0) {
+ sender_->Send(new AutomationMsg_HandleUnused(0, proxy->handle()));
+ }
+ return;
+ }
+ ++iter;
+ }
+}
+
+void AutomationHandleTracker::InvalidateHandle(AutomationHandle handle) {
+ HandleToObjectMap::iterator iter = handle_to_object_.lower_bound(handle);
+ HandleToObjectMap::const_iterator end_of_matching_objects =
+ handle_to_object_.upper_bound(handle);
+
+ for (; iter != end_of_matching_objects; ++iter) {
+ iter->second->Invalidate();
+ }
+}
diff --git a/chrome/test/automation/automation_handle_tracker.h b/chrome/test/automation/automation_handle_tracker.h
new file mode 100644
index 0000000..8f064e3
--- /dev/null
+++ b/chrome/test/automation/automation_handle_tracker.h
@@ -0,0 +1,128 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file defines a mapping between Automation Proxy objects and
+// their associated app-side handles.
+
+#ifndef CHROME_TEST_AUTOMATION_AUTOMATION_HANDLE_TRACKER_H__
+#define CHROME_TEST_AUTOMATION_AUTOMATION_HANDLE_TRACKER_H__
+
+#include <map>
+
+#include "base/basictypes.h"
+
+// This represents a value that the app's AutomationProvider returns
+// when asked for a resource (like a window or tab).
+typedef int AutomationHandle;
+
+class AutomationHandleTracker;
+class AutomationMessageSender;
+
+class AutomationResourceProxy {
+ public:
+ AutomationResourceProxy(AutomationHandleTracker* tracker,
+ AutomationMessageSender* sender,
+ AutomationHandle handle);
+ virtual ~AutomationResourceProxy();
+
+ // Marks this proxy object as no longer valid; this generally means
+ // that the corresponding resource on the app side is gone.
+ void Invalidate() { is_valid_ = false; }
+ bool is_valid() const { return is_valid_; }
+
+ // Returns the handle that the app has generated to refer to this resource.
+ AutomationHandle handle() { return handle_; }
+
+ protected:
+ friend class AutomationHandleTracker;
+
+ AutomationHandle handle_;
+
+ // Called by the tracker when it is being destroyed so we know not to call
+ // it back.
+ void TrackerGone() {
+ tracker_ = NULL;
+ }
+
+ // Not owned by us, owned by the AutomationProxy object. May be NULL if the
+ // tracker has been destroyed (and hence the object is invalid).
+ AutomationHandleTracker* tracker_;
+
+ // Not owned by us.
+ AutomationMessageSender* sender_;
+
+ private:
+ // True if the resource that this object is a proxy for on the app side
+ // still exists.
+ bool is_valid_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(AutomationResourceProxy);
+};
+
+// This class keeps track of the mapping between AutomationHandles and
+// AutomationResourceProxy objects. This is important because (1) multiple
+// AutomationResourceProxy objects can be generated for the same handle
+// (2) handles can be invalidated by the app, and all the associated
+// proxy objects then need to be invalidated, and (3) when a handle is no
+// longer being used on this end, we need to tell the app that it can
+// discard the handle.
+class AutomationHandleTracker {
+ public:
+ AutomationHandleTracker(AutomationMessageSender* sender)
+ : sender_(sender) {}
+ ~AutomationHandleTracker();
+
+ // Adds the specified proxy object to the tracker.
+ void Add(AutomationResourceProxy* proxy);
+
+ // Removes a given proxy object from the mapping, and unregisters the
+ // handle on the app side if this was the last proxy object that was using
+ // that handle. This is a no-op if the proxy object is not currently
+ // in the tracker.
+ void Remove(AutomationResourceProxy* proxy);
+
+ // Marks all proxy objects related to a given handle invalid. This is
+ // used when a resource (like a window) on the app side is closed, meaning
+ // that no further operations can be completed using the handle that
+ // identified that resource.
+ void InvalidateHandle(AutomationHandle handle);
+
+ private:
+ typedef
+ std::multimap<AutomationHandle, AutomationResourceProxy*> HandleToObjectMap;
+ typedef std::pair<AutomationHandle, AutomationResourceProxy*> MapEntry;
+
+ HandleToObjectMap handle_to_object_;
+
+ AutomationMessageSender* sender_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(AutomationHandleTracker);
+};
+
+#endif // CHROME_TEST_AUTOMATION_AUTOMATION_HANDLE_TRACKER_H__ \ No newline at end of file
diff --git a/chrome/test/automation/automation_messages.h b/chrome/test/automation/automation_messages.h
new file mode 100644
index 0000000..a106e38
--- /dev/null
+++ b/chrome/test/automation/automation_messages.h
@@ -0,0 +1,65 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_TEST_AUTOMATION_AUTOMATION_MESSAGES_H__
+#define CHROME_TEST_AUTOMATION_AUTOMATION_MESSAGES_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "chrome/common/ipc_message.h"
+#include "chrome/common/ipc_message_utils.h"
+
+enum AutomationMsg_NavigationResponseValues {
+ AUTOMATION_MSG_NAVIGATION_ERROR = 0,
+ AUTOMATION_MSG_NAVIGATION_SUCCESS,
+ AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
+};
+
+// Two-pass include of render_messages_internal. Preprocessor magic allows
+// us to use 1 header to define the enums and classes for our render messages.
+#define IPC_MESSAGE_MACROS_ENUMS
+#include "chrome/test/automation/automation_messages_internal.h"
+
+#ifdef IPC_MESSAGE_MACROS_LOG_ENABLED
+# undef IPC_MESSAGE_MACROS_LOG
+# define IPC_MESSAGE_MACROS_CLASSES
+#include "chrome/test/automation/automation_messages_internal.h"
+
+# undef IPC_MESSAGE_MACROS_CLASSES
+# define IPC_MESSAGE_MACROS_LOG
+#include "chrome/test/automation/automation_messages_internal.h"
+#else
+// No debug strings requested, just define the classes
+# define IPC_MESSAGE_MACROS_CLASSES
+#include "chrome/test/automation/automation_messages_internal.h"
+#endif
+
+
+#endif // CHROME_TEST_AUTOMATION_AUTOMATION_MESSAGES_H__
diff --git a/chrome/test/automation/automation_messages_internal.h b/chrome/test/automation/automation_messages_internal.h
new file mode 100644
index 0000000..64ee503
--- /dev/null
+++ b/chrome/test/automation/automation_messages_internal.h
@@ -0,0 +1,723 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Defines the IPC messages used by the automation interface.
+
+// This header is meant to be included in multiple passes, hence no traditional
+// header guard.
+// See ipc_message_macros.h for explanation of the macros and passes.
+
+#include <string>
+#include <vector>
+
+#include "chrome/common/ipc_message_macros.h"
+#include "chrome/common/navigation_types.h"
+#include "chrome/test/automation/autocomplete_edit_proxy.h"
+
+// NOTE: All IPC messages have either a routing_id of 0 (for asynchronous
+// messages), or one that's been assigned by the proxy (for calls
+// which expect a response). The routing_id shouldn't be used for
+// any other purpose in these message types.
+
+// NOTE: All the new IPC messages should go at the end (before IPC_END_MESSAGES)
+// The IPC message IDs are part of an enum and hence the value
+// assumed to be constant across the builds may change.
+// The messages AutomationMsg_WindowHWND* in particular should not change
+// since the PageCyclerReferenceTest depend on the correctness of the
+// the message IDs across the builds.
+
+// By using a start value of 0 for automation messages, we keep backward
+// compatability with old builds.
+IPC_BEGIN_MESSAGES(Automation, 0)
+
+ // This message is fired when the AutomationProvider is up and running
+ // in the app (the app is not fully up at this point).
+ IPC_MESSAGE_ROUTED0(AutomationMsg_Hello)
+
+ // This message is fired when the initial tab(s) are finished loading.
+ IPC_MESSAGE_ROUTED0(AutomationMsg_InitialLoadsComplete)
+
+ // This message notifies the AutomationProvider to append a new tab the window
+ // with the given handle. The response contains the index of the new tab, or
+ // -1 if the request failed.
+ // The second parameter is the url to be loaded in the new tab.
+ IPC_MESSAGE_ROUTED2(AutomationMsg_AppendTabRequest, int, GURL)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_AppendTabResponse, int)
+
+ // This message requests the (zero-based) index for the currently
+ // active tab in the window with the given handle. The response contains
+ // the index of the active tab, or -1 if the request failed.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_ActiveTabIndexRequest, int)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_ActiveTabIndexResponse, int)
+
+ // This message notifies the AutomationProvider to active the tab.
+ // The first parameter is the handle to window resource.
+ // The second parameter is the (zero-based) index to be activated
+ IPC_MESSAGE_ROUTED2(AutomationMsg_ActivateTabRequest, int, int)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_ActivateTabResponse, int)
+
+ // This message requests the cookie value for given url in the
+ // profile of the tab identified by the second parameter. The first
+ // parameter is the URL string. The response contains the length of the cookie
+ // value string. On failure, this length = -1.
+ IPC_MESSAGE_ROUTED2(AutomationMsg_GetCookiesRequest, GURL, int)
+ IPC_MESSAGE_ROUTED2(AutomationMsg_GetCookiesResponse, int, std::string)
+
+ // This message notifies the AutomationProvider to set and broadcast a cookie
+ // with given name and value for the given url in the profile of the tab
+ // identified by the third parameter. The first parameter is the URL
+ // string, and the second parameter is the cookie name and value to be set.
+ // The response returns a non-negative value on success.
+ IPC_MESSAGE_ROUTED3(AutomationMsg_SetCookieRequest, GURL, std::string, int)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_SetCookieResponse, int)
+
+ // This message notifies the AutomationProvider to navigate to a specified url
+ // in the tab with given handle. The first parameter is the handle to the tab
+ // resource. The second parameter is the target url. The response contains a
+ // status code which is nonnegative on success.
+ IPC_MESSAGE_ROUTED2(AutomationMsg_NavigateToURLRequest, int, GURL)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_NavigateToURLResponse,
+ int) // see AutomationMsg_NavigationResponseValues
+
+ // This message is used to implement the asynchronous version of
+ // NavigateToURL.
+ IPC_MESSAGE_ROUTED2(AutomationMsg_NavigationAsyncRequest,
+ int /* tab handle */,
+ GURL)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_NavigationAsyncResponse,
+ bool /* error value */)
+
+ // This message notifies the AutomationProvider to navigate back in session
+ // history in the tab with given handle. The first parameter is the handle
+ // to the tab resource. The response contains a status code which is
+ // nonnegative on success.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_GoBackRequest, int)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_GoBackResponse,
+ int) // see AutomationMsg_NavigationResponseValues
+
+ // This message notifies the AutomationProvider to navigate forward in session
+ // history in the tab with given handle. The first parameter is the handle
+ // to the tab resource. The response contains a status code which is
+ // nonnegative on success.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_GoForwardRequest, int)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_GoForwardResponse,
+ int) // see AutomationMsg_NavigationResponseValues
+
+ // This message requests the number of browser windows that the app currently
+ // has open. The parameter in the response is the number of windows.
+ IPC_MESSAGE_ROUTED0(AutomationMsg_BrowserWindowCountRequest)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_BrowserWindowCountResponse, int)
+
+ // This message requests the handle (int64 app-unique identifier) of the
+ // window with the given (zero-based) index. On error, the returned handle
+ // value is 0.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_BrowserWindowRequest, int)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_BrowserWindowResponse, int)
+
+ // This message requests the number of tabs in the window with the given
+ // handle. The response contains the number of tabs, or -1 if the request
+ // failed.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_TabCountRequest, int)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_TabCountResponse, int)
+
+ // This message requests the handle of the tab with the given (zero-based)
+ // index in the given app window. First parameter specifies the given window
+ // handle, second specifies the given tab_index. On error, the returned handle
+ // value is 0.
+ IPC_MESSAGE_ROUTED2(AutomationMsg_TabRequest, int, int)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_TabResponse, int)
+
+ // This message requests the the title of the tab with the given handle.
+ // The response contains the size of the title string. On error, this value
+ // should be -1 and empty string. Note that the title can be empty in which
+ // case the size would be 0.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_TabTitleRequest, int)
+ IPC_MESSAGE_ROUTED2(AutomationMsg_TabTitleResponse, int, std::wstring)
+
+ // This message requests the the url of the tab with the given handle.
+ // The response contains a success flag and the URL string. The URL will
+ // be empty on failure, and it still may be empty on success.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_TabURLRequest,
+ int /* tab handle */)
+ IPC_MESSAGE_ROUTED2(AutomationMsg_TabURLResponse,
+ bool /* success flag*/,
+ GURL)
+
+ // This message requests the HWND of the top-level window that corresponds
+ // to the given automation handle.
+ // The response contains the HWND value, which is 0 if the call fails.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_WindowHWNDRequest,
+ int /* automation handle */)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_WindowHWNDResponse,
+ HWND /* Win32 handle */)
+
+ // This message notifies the AutomationProxy that a handle that it has
+ // previously been given is now invalid. (For instance, if the handle
+ // represented a window which has now been closed.) The parameter
+ // value is the handle.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_InvalidateHandle, int)
+
+ // This message notifies the AutomationProvider that a handle is no
+ // longer being used, so it can stop paying attention to the
+ // associated resource. The parameter value is the handle.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_HandleUnused, int)
+
+ // This message requests the HWND of the tab that corresponds
+ // to the given automation handle.
+ // The response contains the HWND value, which is 0 if the call fails.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_TabHWNDRequest,
+ int /* tab_handle */)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_TabHWNDResponse,
+ HWND /* win32 Window Handle*/)
+
+ // This message tells the AutomationProvider to provide the given
+ // authentication data to the specified tab, in response to an HTTP/FTP
+ // authentication challenge.
+ // The response status will be negative on error.
+ IPC_MESSAGE_ROUTED3(AutomationMsg_SetAuthRequest,
+ int, // tab handle
+ std::wstring, // username
+ std::wstring) // password
+ IPC_MESSAGE_ROUTED1(AutomationMsg_SetAuthResponse,
+ int) // status
+
+ // This message tells the AutomationProvider to cancel the login in the
+ // specified tab.
+ // The response status will be negative on error.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_CancelAuthRequest,
+ int) // tab handle
+ IPC_MESSAGE_ROUTED1(AutomationMsg_CancelAuthResponse,
+ int) // status
+
+ // Requests that the automation provider ask history for the most recent
+ // chain of redirects coming from the given URL. The response must be
+ // decoded by the caller manually; it contains an integer indicating the
+ // number of URLs, followed by that many wstrings indicating a chain of
+ // redirects. On failure, the count will be negative.
+ IPC_MESSAGE_ROUTED2(AutomationMsg_RedirectsFromRequest,
+ int, // tab handle
+ GURL) // source URL
+ IPC_MESSAGE_EMPTY(AutomationMsg_RedirectsFromResponse)
+
+ // This message asks the AutomationProvider whether a tab is waiting for
+ // login info.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_NeedsAuthRequest,
+ int) // tab handle
+ IPC_MESSAGE_ROUTED1(AutomationMsg_NeedsAuthResponse,
+ bool) // status
+
+ // This message requests the AutomationProvider to apply a certain
+ // accelerator. It is completely asynchronous with the resulting accelerator
+ // action.
+ IPC_MESSAGE_ROUTED2(AutomationMsg_ApplyAcceleratorRequest,
+ int, // window handle
+ int) // accelerator id like (IDC_BACK, IDC_FORWARD ...)
+ // The list can be found at
+ // chrome/app/chrome_dll_resource.h
+
+ // This message requests that the AutomationProvider executes a JavaScript,
+ // which is sent embedded in a 'javascript:' URL.
+ // The javascript is executed in context of child frame whose xpath
+ // is passed as parameter (context_frame). The execution results in
+ // a serialized JSON string response.
+ IPC_MESSAGE_ROUTED3(AutomationMsg_DomOperationRequest,
+ int, // tab handle
+ std::wstring, // context_frame
+ std::wstring) // the javascript to be executed
+
+ // This message is used to communicate the values received by the
+ // callback binding the JS to Cpp. This message forms the second leg in
+ // the communication channel. The values are originally received in the
+ // renderer which are then sent to the app (wrapped as json) using
+ // corresponding message in render_messages_internal.h
+ // This message simply relays the json string.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_DomOperationResponse,
+ std::string) // the serialized json string containing
+ // the result of a javascript execution
+
+ // Is the Download Shelf visible for the specified tab?
+ IPC_MESSAGE_ROUTED1(AutomationMsg_ShelfVisibilityRequest,
+ int /* tab_handle */)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_ShelfVisibilityResponse,
+ bool /* is_visible */)
+
+ // This message requests the number of constrained windows in the tab with
+ // the given handle. The response contains the number of constrained windows,
+ // or -1 if the request failed.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_ConstrainedWindowCountRequest,
+ int /* tab_handle */)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_ConstrainedWindowCountResponse,
+ int /* constrained_window_count */)
+
+ // This message requests the handle of the constrained window with the given
+ // (zero-based) index in the given tab. First parameter specifies the given
+ // tab handle, second specifies the given child_index. On error, the returned
+ // handle value is 0.
+ IPC_MESSAGE_ROUTED2(AutomationMsg_ConstrainedWindowRequest,
+ int, /* window_handle */
+ int) /* child_index */
+
+ IPC_MESSAGE_ROUTED1(AutomationMsg_ConstrainedWindowResponse,
+ int) /* constrained_handle */
+
+ // This message requests the the title of the constrained window with the
+ // given handle. The response contains the size of the title string and title
+ // string. On error, this value should be -1 and empty string. Note that the
+ // title can be empty in which case the size would be 0.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_ConstrainedTitleRequest, int)
+ IPC_MESSAGE_ROUTED2(AutomationMsg_ConstrainedTitleResponse, int, std::wstring)
+
+ // This message requests the bounds of the specified View element in
+ // window coordinates.
+ // Request:
+ // int - the handle of the window in which the view appears
+ // int - the ID of the view, as specified in chrome/browser/view_ids.h
+ // bool - whether the bounds should be returned in the screen coordinates
+ // (if true) or in the browser coordinates (if false).
+ // Response:
+ // bool - true if the view was found
+ // gfx::Rect - the bounds of the view, in window coordinates
+ IPC_MESSAGE_ROUTED3(AutomationMsg_WindowViewBoundsRequest, int, int, bool)
+ IPC_MESSAGE_ROUTED2(AutomationMsg_WindowViewBoundsResponse, bool, gfx::Rect)
+
+ // This message requests that a drag be performed in window coordinate space
+ // Request:
+ // int - the handle of the window that's the context for this drag
+ // std::vector<POINT> - the path of the drag in window coordinate space;
+ // it should have at least 2 points (start and end)
+ // int - the flags which identify the mouse button(s) for the drag, as
+ // defined in chrome/views/event.h
+ // Response:
+ // bool - true if the drag could be performed
+ IPC_MESSAGE_ROUTED3(AutomationMsg_WindowDragRequest,
+ int, std::vector<POINT>, int)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_WindowDragResponse, bool)
+
+ // Similar to AutomationMsg_InitialLoadsComplete, this indicates that the
+ // new tab ui has completed the initial load of its data.
+ // Time is how many milliseconds the load took.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_InitialNewTabUILoadComplete,
+ int /* time */)
+
+ // This message starts a find within a tab corresponding to the supplied
+ // tab handle. The response contains the number of matches found on the page
+ // within the tab specified. The parameter 'search_string' specifies what
+ // string to search for, 'forward' specifies whether to search in forward
+ // direction (1=forward, 0=back), 'match_case' specifies case sensitivity
+ // (1=case sensitive, 0=case insensitive). If an error occurs, matches_found
+ // will be -1.
+ IPC_MESSAGE_ROUTED4(AutomationMsg_FindInPageRequest,
+ int, /* tab_handle */
+ std::wstring, /* find_request */
+ int, /* forward */
+ int /* match_case */)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_FindInPageResponse,
+ int /* matches_found */)
+
+ // This message sends a inspect element request for a given tab. The response
+ // contains the number of resources loaded by the inspector controller.
+ IPC_MESSAGE_ROUTED3(AutomationMsg_InspectElementRequest,
+ int, /* tab_handle */
+ int, /* x */
+ int /* y */)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_InspectElementResponse, int)
+
+ // This message requests the process ID of the tab that corresponds
+ // to the given automation handle.
+ // The response has an integer corresponding to the PID of the tab's
+ // renderer, 0 if the tab currently has no renderer process, or -1 on error.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_TabProcessIDRequest,
+ int /* tab_handle */)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_TabProcessIDResponse,
+ int /* process ID */)
+
+ // This tells the browser to enable or disable the filtered network layer.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_SetFilteredInet,
+ bool /* enabled */)
+
+ // Gets the directory that downloads will occur in for the active profile.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_DownloadDirectoryRequest,
+ int /* tab_handle */)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_DownloadDirectoryResponse,
+ std::wstring /* directory */)
+
+ // This message requests the id of the view that has the focus in the
+ // specified window. If no view is focused, -1 is returned. Note that the
+ // window should either be a ViewWindow or a Browser.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_GetFocusedViewIDRequest,
+ int /* view_handle */)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_GetFocusedViewIDResponse,
+ int /* focused_view_id */)
+
+ // This message shows/hides the window.
+ IPC_MESSAGE_ROUTED2(AutomationMsg_SetWindowVisibleRequest,
+ int /* view_handle */, bool /* visible */)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_SetWindowVisibleResponse,
+ bool /* success */)
+
+ // Gets the active status of a window.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_IsWindowActiveRequest,
+ int /* view_handle */)
+ IPC_MESSAGE_ROUTED2(AutomationMsg_IsWindowActiveResponse,
+ bool /* success */, bool /* active */)
+
+ // Makes the specified window the active window.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_ActivateWindow, int /* view_handle */)
+
+ // Opens a new browser window.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_OpenNewBrowserWindow,
+ int /* show_command*/ )
+
+ // This message requests the handle (int64 app-unique identifier) of the
+ // current active top window. On error, the returned handle value is 0.
+ IPC_MESSAGE_ROUTED0(AutomationMsg_ActiveWindowRequest)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_ActiveWindowResponse, int)
+
+ // This message requests the browser associated with the specified window
+ // handle.
+ // The response contains a success flag and the handle of the browser.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_BrowserForWindowRequest,
+ int /* window handle */)
+ IPC_MESSAGE_ROUTED2(AutomationMsg_BrowserForWindowResponse,
+ bool /* success flag */,
+ int /* browser handle */)
+
+ // This message requests the window associated with the specified browser
+ // handle.
+ // The response contains a success flag and the handle of the window.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_WindowForBrowserRequest,
+ int /* browser handle */)
+ IPC_MESSAGE_ROUTED2(AutomationMsg_WindowForBrowserResponse,
+ bool /* success flag */,
+ int /* window handle */)
+
+ // This message requests the AutocompleteEdit associated with the specified
+ // browser handle.
+ // The response contains a success flag and the handle of the omnibox.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_AutocompleteEditForBrowserRequest,
+ int /* browser handle */)
+ IPC_MESSAGE_ROUTED2(AutomationMsg_AutocompleteEditForBrowserResponse,
+ bool /* success flag */,
+ int /* AutocompleteEdit handle */)
+
+ // This message requests that a mouse click be performed in window coordinate
+ // space.
+ // Request:
+ // int - the handle of the window that's the context for this click
+ // POINT - the point to click
+ // int - the flags which identify the mouse button(s) for the click, as
+ // defined in chrome/views/event.h
+ IPC_MESSAGE_ROUTED3(AutomationMsg_WindowClickRequest, int, POINT, int)
+
+ // This message requests that a key press be performed.
+ // Request:
+ // int - the handle of the window that's the context for this click
+ // wchar_t - char of the key that was pressed.
+ // int - the flags which identify the modifiers (shift, ctrl, alt)
+ // associated for, as defined in chrome/views/event.h
+ IPC_MESSAGE_ROUTED3(AutomationMsg_WindowKeyPressRequest, int, wchar_t, int)
+
+ // This message notifies the AutomationProvider to create a tab which is
+ // hosted by an external process. The response contains the HWND of the
+ // window that contains the external tab and the handle to the newly
+ // created tab
+ // The second parameter is the url to be loaded in the new tab.
+ IPC_MESSAGE_ROUTED0(AutomationMsg_CreateExternalTab)
+ IPC_MESSAGE_ROUTED2(AutomationMsg_CreateExternalTabResponse, HWND, int)
+
+ // This message notifies the AutomationProvider to navigate to a specified
+ // url in the external tab with given handle. The first parameter is the
+ // handle to the tab resource. The second parameter is the target url.
+ // The response contains a status code which is nonnegative on success.
+ IPC_MESSAGE_ROUTED2(AutomationMsg_NavigateInExternalTabRequest, int, GURL)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_NavigateInExternalTabResponse,
+ int) // see AutomationMsg_NavigationResponseValues
+
+ // This message is an outgoing message from Chrome to an external host.
+ // It is a notification that the NavigationState was changed
+ // Request:
+ // -int: The flags specifying what changed
+ // (see TabContents::InvalidateTypes)
+ // Response:
+ // None expected
+ IPC_MESSAGE_ROUTED1(AutomationMsg_NavigationStateChanged, int)
+
+ // This message is an outgoing message from Chrome to an external host.
+ // It is a notification that the target URL has changed (the target URL
+ // is the URL of the link that the user is hovering on)
+ // Request:
+ // -std::wstring: The new target URL
+ // Response:
+ // None expected
+ IPC_MESSAGE_ROUTED1(AutomationMsg_UpdateTargetUrl, std::wstring)
+
+ // This message notifies the AutomationProvider to show the specified html
+ // text in an interstitial page in the tab with given handle. The first
+ // parameter is the handle to the tab resource. The second parameter is the
+ // html text to be displayed.
+ // The response contains a success flag.
+ IPC_MESSAGE_ROUTED2(AutomationMsg_ShowInterstitialPageRequest,
+ int,
+ std::string)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_ShowInterstitialPageResponse, bool)
+
+ // This message notifies the AutomationProvider to hide the current
+ // interstitial page in the tab with given handle. The parameter is the handle
+ // to the tab resource.
+ // The response contains a success flag.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_HideInterstitialPageRequest, int)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_HideInterstitialPageResponse, bool)
+
+ // This message requests that a tab be closed.
+ // Request:
+ // - int: handle of the tab to close
+ // - bool: if true the proxy blocks until the tab has completely closed,
+ // otherwise the proxy only blocks until it initiates the close.
+ IPC_MESSAGE_ROUTED2(AutomationMsg_CloseTabRequest, int, bool)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_CloseTabResponse, bool)
+
+ // This message requests that the browser be closed.
+ // Request:
+ // - int: handle of the browser which contains the tab
+ // Response:
+ // - bool: whether the operation was successfull.
+ // - bool: whether the browser process will be terminated as a result (if
+ // this was the last closed browser window).
+ IPC_MESSAGE_ROUTED1(AutomationMsg_CloseBrowserRequest, int)
+ IPC_MESSAGE_ROUTED2(AutomationMsg_CloseBrowserResponse, bool, bool)
+
+ // This message sets the keyboard accelarators to be used by an externally
+ // hosted tab. This call is not valid on a regular tab hosted within
+ // Chrome.
+ // Request:
+ // - int: handle of the tab
+ // - HACCEL: The accelerator table to be set
+ // - int: The number of entries in the accelerator table
+ // Response:
+ // -bool: whether the operation was successful.
+ IPC_MESSAGE_ROUTED3(AutomationMsg_SetAcceleratorsForTab, int, HACCEL, int)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_SetAcceleratorsForTabResponse, bool)
+
+ // This message is an outgoing message from Chrome to an external host.
+ // It is a request to process a keyboard accelerator.
+ // Request:
+ // -MSG: The keyboard message
+ // Response:
+ // None expected
+ // TODO(sanjeevr): Ideally we need to add a response from the external
+ // host saying whether it processed the accelerator
+ IPC_MESSAGE_ROUTED1(AutomationMsg_HandleAccelerator, MSG)
+
+ // This message is an outgoing message from Chrome to an external host.
+ // It is a request to open a url
+ // Request:
+ // -GURL: The URL to open
+ // -int: The WindowOpenDisposition that specifies where the URL should
+ // be opened (new tab, new window etc).
+ // Response:
+ // None expected
+ IPC_MESSAGE_ROUTED2(AutomationMsg_OpenURL, GURL, int)
+
+ // This message is sent by the container of an externally hosted tab to
+ // reflect any accelerator keys that it did not process. This gives the
+ // tab a chance to handle the keys
+ // Request:
+ // - int: handle of the tab
+ // -MSG: The keyboard message that the container did not handle
+ // Response:
+ // None expected
+ IPC_MESSAGE_ROUTED2(AutomationMsg_ProcessUnhandledAccelerator, int, MSG)
+
+ // This message requests the provider to wait until the specified tab has
+ // finished restoring after session restore.
+ // Request:
+ // - int: handle of the tab
+ // Response:
+ // - bool: whether the operation was successful.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_WaitForTabToBeRestored, int)
+
+ // Sent in response to AutomationMsg_WaitForTabToBeRestored once the tab has
+ // finished loading.
+ IPC_MESSAGE_ROUTED0(AutomationMsg_TabFinishedRestoring)
+
+ // This message is an outgoing message from Chrome to an external host.
+ // It is a notification that a navigation happened
+ // Request:
+ // -int : Indicates the type of navigation (see the NavigationType enum)
+ // -int: If this was not a new navigation, then this value indicates the
+ // relative offset of the navigation. A positive offset means a
+ // forward navigation, a negative value means a backward navigation
+ // and 0 means this was a redirect
+ // Response:
+ // None expected
+ IPC_MESSAGE_ROUTED2(AutomationMsg_DidNavigate, int, int)
+
+ // This message requests the different security states of the page displayed
+ // in the specified tab.
+ // Request:
+ // - int: handle of the tab
+ // Response:
+ // - bool: whether the operation was successful.
+ // - int: the security style of the tab (enum SecurityStyle see
+ // security_style.h)).
+ // - int: the status of the server's ssl cert (0 means no errors or no ssl
+ // was used).
+ // - int: the mixed content state, 0 means no mixed/unsafe contents.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_GetSecurityState, int)
+ IPC_MESSAGE_ROUTED4(AutomationMsg_GetSecurityStateResponse,
+ bool,
+ int,
+ int,
+ int)
+
+ // This message requests the page type of the page displayed in the specified
+ // tab (normal, error or interstitial).
+ // Request:
+ // - int: handle of the tab
+ // Response:
+ // - bool: whether the operation was successful.
+ // - int: the type of the page currently displayed (enum PageType see
+ // entry_navigation.h).
+ IPC_MESSAGE_ROUTED1(AutomationMsg_GetPageType, int)
+ IPC_MESSAGE_ROUTED2(AutomationMsg_GetPageTypeResponse, bool, int)
+
+ // This message simulates the user action on the SSL blocking page showing in
+ // the specified tab. This message is only effective if an interstitial page
+ // is showing in the tab.
+ // Request:
+ // - int: handle of the tab
+ // - bool: whether to proceed or abort the navigation
+ // Response:
+ // - bool: whether the operation was successful.
+ IPC_MESSAGE_ROUTED2(AutomationMsg_ActionOnSSLBlockingPage, int, bool)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_ActionOnSSLBlockingPageResponse, bool)
+
+ // Message to request that a browser window is brought to the front and activated.
+ // Request:
+ // - int: handle of the browser window.
+ // Response:
+ // - bool: True if the browser is brought to the front.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_BringBrowserToFront, int)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_BringBrowserToFrontResponse, bool)
+
+ // Message to request whether a certain item is enabled of disabled in the "Page"
+ // menu in the browser window
+ //
+ // Request:
+ // - int: handle of the browser window.
+ // - int: IDC message identifier to query if enabled
+ // Response:
+ // - bool: True if the command is enabled on the Page menu
+ IPC_MESSAGE_ROUTED2(AutomationMsg_IsPageMenuCommandEnabled, int, int)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_IsPageMenuCommandEnabledResponse, bool)
+
+ // This message notifies the AutomationProvider to print the tab with given
+ // handle. The first parameter is the handle to the tab resource. The
+ // response contains a bool which is true on success.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_PrintNowRequest, int)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_PrintNowResponse, bool)
+
+ // This message notifies the AutomationProvider to reload the current page in
+ // the tab with given handle. The first parameter is the handle to the tab
+ // resource. The response contains a status code which is nonnegative on
+ // success.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_ReloadRequest, int)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_ReloadResponse,
+ int) // see AutomationMsg_NavigationResponseValues
+
+ // This message requests the handle (int64 app-unique identifier) of the
+ // last active browser window, or the browser at index 0 if there is no last
+ // active browser, or it no longer exists. Returns 0 if no browser windows
+ // exist.
+ IPC_MESSAGE_ROUTED0(AutomationMsg_LastActiveBrowserWindowRequest)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_LastActiveBrowserWindowResponse, int)
+
+ // This message requests the bounds of a constrained window (relative to its
+ // containing TabContents). On an internal error, the boolean in the result will
+ // be set to false.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_ConstrainedWindowBoundsRequest,
+ int /* tab_handle */)
+ IPC_MESSAGE_ROUTED2(AutomationMsg_ConstrainedWindowBoundsResponse,
+ bool /* the requested window exists */,
+ gfx::Rect /* constrained_window_count */)
+
+ // This message notifies the AutomationProvider to save the page with given
+ // handle. The first parameter is the handle to the tab resource. The second
+ // parameter is the main HTML file name. The third parameter is the directory
+ // for saving resources. The fourth parameter is the saving type: 0 for HTML
+ // only; 1 for complete web page.
+ // The response contains a bool which is true on success.
+ IPC_MESSAGE_ROUTED4(AutomationMsg_SavePageRequest, int, std::wstring,
+ std::wstring, int)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_SavePageResponse, bool)
+
+
+ // This message requests the text currently being displayed in the
+ // AutocompleteEdit. The parameter is the handle to the AutocompleteEdit.
+ // The response is a string indicating the text in the AutocompleteEdit.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_AutocompleteEditGetTextRequest,
+ int /* autocomplete edit handle */)
+ IPC_MESSAGE_ROUTED2(AutomationMsg_AutocompleteEditGetTextResponse,
+ bool /* the requested autocomplete edit exists */,
+ std::wstring /* omnibox text */)
+
+ // This message sets the text being displayed in the AutocompleteEdit. The
+ // first parameter is the handle to the omnibox and the second parameter is
+ // the text to be displayed in the AutocompleteEdit.
+ // The response has no parameters and is returned when the operation has
+ // completed.
+ IPC_MESSAGE_ROUTED2(AutomationMsg_AutocompleteEditSetTextRequest,
+ int /* autocomplete edit handle */,
+ std::wstring /* text to set */)
+ IPC_MESSAGE_ROUTED1(AutomationMsg_AutocompleteEditSetTextResponse,
+ bool /* the requested autocomplete edit exists */)
+
+ // This message requests if a query to a autocomplete provider is still in
+ // progress. The first parameter in the request is the handle to the
+ // autocomplete edit.
+ // The first parameter in the response indicates if the request succeeded.
+ // The second parameter in indicates if a query is still in progress.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_AutocompleteEditIsQueryInProgressRequest,
+ int /* autocomplete edit handle*/)
+ IPC_MESSAGE_ROUTED2(AutomationMsg_AutocompleteEditIsQueryInProgressResponse,
+ bool /* the requested autocomplete edit exists */,
+ bool /* indicates if a query is in progress */)
+
+ // This message requests a list of the autocomplete messages currently being
+ // displayed by the popup. The parameter in the request is a handle to the
+ // autocomplete edit.
+ // The first parameter in the response indicates if the request was
+ // successful while the second parameter is the actual list of matches.
+ IPC_MESSAGE_ROUTED1(AutomationMsg_AutocompleteEditGetMatchesRequest,
+ int /* autocomplete edit handle*/)
+ IPC_MESSAGE_ROUTED2(AutomationMsg_AutocompleteEditGetMatchesResponse,
+ bool /* the requested autocomplete edit exists */,
+ std::vector<AutocompleteMatchData> /* matches */)
+
+IPC_END_MESSAGES(Automation)
diff --git a/chrome/test/automation/automation_proxy.cc b/chrome/test/automation/automation_proxy.cc
new file mode 100644
index 0000000..07e5387
--- /dev/null
+++ b/chrome/test/automation/automation_proxy.cc
@@ -0,0 +1,567 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <sstream>
+
+#include "chrome/test/automation/automation_proxy.h"
+
+#include "base/logging.h"
+#include "base/ref_counted.h"
+#include "chrome/common/ipc_message_macros.h"
+#include "chrome/test/automation/autocomplete_edit_proxy.h"
+#include "chrome/test/automation/automation_constants.h"
+#include "chrome/test/automation/automation_messages.h"
+#include "chrome/test/automation/browser_proxy.h"
+#include "chrome/test/automation/tab_proxy.h"
+#include "chrome/test/automation/window_proxy.h"
+
+// This class exists to group together the data and functionality used for
+// synchronous automation requests.
+class AutomationRequest :
+ public base::RefCountedThreadSafe<AutomationRequest> {
+public:
+ AutomationRequest() {
+ static int32 routing_id = 0;
+ routing_id_ = ++routing_id;
+ received_response_ = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+ DCHECK(received_response_);
+ }
+ ~AutomationRequest() {
+ DCHECK(received_response_);
+ ::CloseHandle(received_response_);
+ }
+
+ // This is called on the foreground thread to block while waiting for a
+ // response from the app.
+ // The function returns true if response is received, and returns false
+ // if there is a failure or timeout.
+ bool WaitForResponse(uint32 timeout_ms, bool* is_timeout) {
+ uint32 result = ::WaitForSingleObject(received_response_, timeout_ms);
+ if (is_timeout)
+ *is_timeout = (result == WAIT_TIMEOUT);
+
+ return result != WAIT_FAILED && result != WAIT_TIMEOUT;
+ }
+
+ // This is called on the background thread once the response has been
+ // received and the foreground thread can resume execution.
+ bool SignalResponseReady(const IPC::Message& response) {
+ response_.reset(new IPC::Message(response));
+
+ DCHECK(received_response_);
+ return !!::SetEvent(received_response_);
+ }
+
+ // This can be used to take ownership of the response object that
+ // we've received, reducing the need to copy the message.
+ void GrabResponse(IPC::Message** response) {
+ DCHECK(response);
+ *response = response_.get();
+ response_.release();
+ }
+
+ int32 routing_id() { return routing_id_; }
+
+ const IPC::Message& response() {
+ DCHECK(response_.get());
+ return *(response_.get());
+ }
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(AutomationRequest);
+
+ int32 routing_id_;
+ scoped_ptr<IPC::Message> response_;
+ HANDLE received_response_;
+};
+
+namespace {
+
+// This object allows messages received on the background thread to be
+// properly triaged.
+class AutomationMessageFilter : public IPC::ChannelProxy::MessageFilter {
+ public:
+ AutomationMessageFilter(AutomationProxy* server) : server_(server) {}
+
+ // Return true to indicate that the message was handled, or false to let
+ // the message be handled in the default way.
+ virtual bool OnMessageReceived(const IPC::Message& message) {
+ {
+ // Here we're checking to see if it matches the (because there should
+ // be at most one) synchronous request. If the received message is
+ // the response to the synchronous request, we clear the server's
+ // "current_request" pointer and signal to the request object that
+ // the response is ready for processing. We're clearing current_request
+ // here rather than on the foreground thread so that we can assert
+ // that both threads perceive it as cleared at the time that the
+ // foreground thread wakes up.
+ scoped_refptr<AutomationRequest> request = server_->current_request();
+ if (request.get() && (message.routing_id() == request->routing_id())) {
+ server_->clear_current_request();
+ request->SignalResponseReady(message);
+ return true;
+ }
+ if (message.routing_id() > 0) {
+ // The message is either the previous async response or arrived
+ // after timeout.
+ return true;
+ }
+ }
+
+ bool handled = true;
+
+ IPC_BEGIN_MESSAGE_MAP(AutomationMessageFilter, message)
+ IPC_MESSAGE_HANDLER_GENERIC(
+ AutomationMsg_Hello, server_->SignalAppLaunch());
+ IPC_MESSAGE_HANDLER_GENERIC(
+ AutomationMsg_InitialLoadsComplete, server_->SignalInitialLoads());
+ IPC_MESSAGE_HANDLER(AutomationMsg_InitialNewTabUILoadComplete,
+ NewTabLoaded);
+ IPC_MESSAGE_HANDLER_GENERIC(
+ AutomationMsg_InvalidateHandle, server_->InvalidateHandle(message));
+ IPC_MESSAGE_UNHANDLED(handled = false);
+ IPC_END_MESSAGE_MAP()
+
+ return handled;
+ }
+
+ void NewTabLoaded(int load_time) {
+ server_->SignalNewTabUITab(load_time);
+ }
+
+ private:
+ AutomationProxy* server_;
+};
+
+} // anonymous namespace
+
+
+const int AutomationProxy::kMaxCommandExecutionTime = 30000;
+
+AutomationProxy::AutomationProxy() : current_request_(NULL) {
+ InitializeEvents();
+ InitializeChannelID();
+ InitializeThread();
+ InitializeChannel();
+ InitializeHandleTracker();
+}
+
+AutomationProxy::~AutomationProxy() {
+}
+
+void AutomationProxy::InitializeEvents() {
+ app_launched_ =
+ CreateEvent(NULL, // Handle cannot be inherited by child processes.
+ TRUE, // No automatic reset after a waiting thread released.
+ FALSE, // Initially not signalled.
+ NULL); // No name.
+ DCHECK(app_launched_);
+
+ // See the above call to CreateEvent to understand these parameters.
+ initial_loads_complete_ = CreateEvent(NULL, TRUE, FALSE, NULL);
+ DCHECK(initial_loads_complete_);
+
+ // See the above call to CreateEvent to understand these parameters.
+ new_tab_ui_load_complete_ = CreateEvent(NULL, TRUE, FALSE, NULL);
+ DCHECK(new_tab_ui_load_complete_);
+}
+
+void AutomationProxy::InitializeChannelID() {
+ // The channel counter keeps us out of trouble if we create and destroy
+ // several AutomationProxies sequentially over the course of a test run.
+ // (Creating the channel sometimes failed before when running a lot of
+ // tests in sequence, and our theory is that sometimes the channel ID
+ // wasn't getting freed up in time for the next test.)
+ static int channel_counter = 0;
+
+ std::wostringstream buf;
+ buf << L"ChromeTestingInterface:" << GetCurrentProcessId() <<
+ L"." << ++channel_counter;
+ channel_id_ = buf.str();
+}
+
+void AutomationProxy::InitializeThread() {
+ scoped_ptr<Thread> thread(new Thread("AutomationProxy_BackgroundThread"));
+ bool thread_result = thread->Start();
+ DCHECK(thread_result);
+ thread_.swap(thread);
+}
+
+void AutomationProxy::InitializeChannel() {
+ channel_.reset(new IPC::ChannelProxy(
+ channel_id_,
+ IPC::Channel::MODE_SERVER,
+ this, // we are the listener
+ new AutomationMessageFilter(this),
+ thread_->message_loop()));
+}
+
+void AutomationProxy::InitializeHandleTracker() {
+ tracker_.reset(new AutomationHandleTracker(this));
+}
+
+bool AutomationProxy::WaitForAppLaunch() {
+ return ::WaitForSingleObject(app_launched_,
+ kMaxCommandExecutionTime) == WAIT_OBJECT_0;
+}
+
+void AutomationProxy::SignalAppLaunch() {
+ ::SetEvent(app_launched_);
+}
+
+bool AutomationProxy::WaitForInitialLoads() {
+ return ::WaitForSingleObject(initial_loads_complete_,
+ kMaxCommandExecutionTime) == WAIT_OBJECT_0;
+}
+
+bool AutomationProxy::WaitForInitialNewTabUILoad(int* load_time) {
+ if (::WaitForSingleObject(new_tab_ui_load_complete_,
+ kMaxCommandExecutionTime) == WAIT_OBJECT_0) {
+ *load_time = new_tab_ui_load_time_;
+ ::ResetEvent(new_tab_ui_load_complete_);
+ return true;
+ }
+ return false;
+}
+
+void AutomationProxy::SignalInitialLoads() {
+ ::SetEvent(initial_loads_complete_);
+}
+
+void AutomationProxy::SignalNewTabUITab(int load_time) {
+ new_tab_ui_load_time_ = load_time;
+ ::SetEvent(new_tab_ui_load_complete_);
+}
+
+bool AutomationProxy::GetBrowserWindowCount(int* num_windows) {
+ if (!num_windows) {
+ NOTREACHED();
+ return false;
+ }
+
+ IPC::Message* response = NULL;
+ bool is_timeout = true;
+ bool succeeded = SendAndWaitForResponseWithTimeout(
+ new AutomationMsg_BrowserWindowCountRequest(0), &response,
+ AutomationMsg_BrowserWindowCountResponse::ID,
+ kMaxCommandExecutionTime, &is_timeout);
+ if (!succeeded)
+ return false;
+
+ if (is_timeout) {
+ DLOG(ERROR) << "GetWindowCount did not complete in a timely fashion";
+ return false;
+ }
+
+ void* iter = NULL;
+ if (!response->ReadInt(&iter, num_windows)) {
+ succeeded = false;
+ }
+
+ delete response;
+ return succeeded;
+}
+
+bool AutomationProxy::WaitForWindowCountToChange(int count, int* new_count,
+ int wait_timeout) {
+ const TimeTicks start = TimeTicks::Now();
+ const TimeDelta timeout = TimeDelta::FromMilliseconds(wait_timeout);
+ while (TimeTicks::Now() - start < timeout) {
+ bool succeeded = GetBrowserWindowCount(new_count);
+ if (!succeeded) return false;
+ if (count != *new_count) return true;
+ Sleep(automation::kSleepTime);
+ }
+ // Window count never changed.
+ return false;
+}
+
+bool AutomationProxy::WaitForWindowCountToBecome(int count,
+ int wait_timeout) {
+ const TimeTicks start = TimeTicks::Now();
+ const TimeDelta timeout = TimeDelta::FromMilliseconds(wait_timeout);
+ while (TimeTicks::Now() - start < timeout) {
+ int new_count;
+ bool succeeded = GetBrowserWindowCount(&new_count);
+ if (!succeeded) {
+ // Try again next round, but log it.
+ DLOG(ERROR) << "GetBrowserWindowCount returned false";
+ } else if (count == new_count) {
+ return true;
+ }
+ Sleep(automation::kSleepTime);
+ }
+ // Window count never reached the value we sought.
+ return false;
+}
+
+bool AutomationProxy::SetFilteredInet(bool enabled) {
+ return Send(new AutomationMsg_SetFilteredInet(0, enabled));
+}
+
+void AutomationProxy::OnMessageReceived(const IPC::Message& msg) {
+ // This won't get called unless AutomationProxy is run from
+ // inside a message loop.
+ NOTREACHED();
+}
+
+void AutomationProxy::OnChannelError() {
+ DLOG(ERROR) << "Channel error in AutomationProxy.";
+}
+
+WindowProxy* AutomationProxy::GetActiveWindow() {
+ IPC::Message* response = NULL;
+ bool is_timeout = true;
+ bool succeeded = SendAndWaitForResponseWithTimeout(
+ new AutomationMsg_ActiveWindowRequest(0), &response,
+ AutomationMsg_ActiveWindowResponse::ID,
+ kMaxCommandExecutionTime, &is_timeout);
+ if (!succeeded)
+ return NULL;
+
+ scoped_ptr<IPC::Message> response_deleter(response); // Delete on exit.
+ if (is_timeout) {
+ DLOG(ERROR) << "GetActiveWindow did not complete in a timely fashion";
+ return NULL;
+ }
+
+ void* iter = NULL;
+ int handle;
+ if (response->ReadInt(&iter, &handle) && (handle != 0))
+ return new WindowProxy(this, tracker_.get(), handle);
+
+ return NULL;
+}
+
+
+BrowserProxy* AutomationProxy::GetBrowserWindow(int window_index) {
+ IPC::Message* response;
+ bool is_timeout = true;
+ bool succeeded = SendAndWaitForResponseWithTimeout(
+ new AutomationMsg_BrowserWindowRequest(0, window_index), &response,
+ AutomationMsg_BrowserWindowResponse::ID,
+ kMaxCommandExecutionTime, &is_timeout);
+ if (!succeeded)
+ return NULL;
+
+ scoped_ptr<IPC::Message> response_deleter(response); // Delete on exit.
+ if (is_timeout) {
+ DLOG(ERROR) << "GetBrowserWindow did not complete in a timely fashion";
+ return NULL;
+ }
+
+ void* iter = NULL;
+ int handle;
+ if (!response->ReadInt(&iter, &handle) || (handle == 0)) {
+ DLOG(ERROR) << "Bad response from the window getter.";
+ return NULL;
+ }
+ return new BrowserProxy(this, tracker_.get(), handle);
+}
+
+BrowserProxy* AutomationProxy::GetLastActiveBrowserWindow() {
+ IPC::Message* response;
+ bool is_timeout = true;
+ bool succeeded = SendAndWaitForResponseWithTimeout(
+ new AutomationMsg_LastActiveBrowserWindowRequest(0),
+ &response, AutomationMsg_LastActiveBrowserWindowResponse::ID,
+ kMaxCommandExecutionTime, &is_timeout);
+ if (!succeeded)
+ return NULL;
+
+ scoped_ptr<IPC::Message> response_deleter(response); // Delete on exit.
+ if (is_timeout) {
+ DLOG(ERROR) << "GetLastActiveBrowserWindow did not complete in a timely fashion";
+ return NULL;
+ }
+
+ void* iter = NULL;
+ int handle;
+ if (!response->ReadInt(&iter, &handle) || (handle == 0)) {
+ DLOG(ERROR) << "Bad response from the window getter.";
+ return NULL;
+ }
+ return new BrowserProxy(this, tracker_.get(), handle);
+}
+
+BrowserProxy* AutomationProxy::GetBrowserForWindow(WindowProxy* window) {
+ return GetBrowserForWindowWithTimeout(window, INFINITE, NULL);
+}
+
+BrowserProxy* AutomationProxy::GetBrowserForWindowWithTimeout(
+ WindowProxy* window, uint32 timeout_ms, bool* is_timeout) {
+ DCHECK(window);
+ if (!window->is_valid() || !window->handle())
+ return false;
+
+ IPC::Message* response = NULL;
+ bool succeeded = SendAndWaitForResponseWithTimeout(
+ new AutomationMsg_BrowserForWindowRequest(0, window->handle()), &response,
+ AutomationMsg_BrowserForWindowResponse::ID, timeout_ms, is_timeout);
+ if (!succeeded)
+ return NULL;
+
+ scoped_ptr<IPC::Message> response_deleter(response); // Delete on exit.
+ int browser_handle = 0;
+ void* iter = NULL;
+ bool handle_ok;
+ succeeded = response->ReadBool(&iter, &handle_ok);
+ if (succeeded)
+ succeeded = response->ReadInt(&iter, &browser_handle);
+
+ if (succeeded) {
+ return new BrowserProxy(this, tracker_.get(), browser_handle);
+ } else {
+ return NULL;
+ }
+}
+
+WindowProxy* AutomationProxy::GetWindowForBrowser(BrowserProxy* browser) {
+ if (!browser->is_valid() || !browser->handle())
+ return false;
+
+ IPC::Message* response = NULL;
+ bool succeeded = SendAndWaitForResponse(
+ new AutomationMsg_WindowForBrowserRequest(0, browser->handle()), &response,
+ AutomationMsg_WindowForBrowserResponse::ID);
+ if (!succeeded)
+ return NULL;
+
+ scoped_ptr<IPC::Message> response_deleter(response); // Delete on exit.
+ int window_handle;
+ void* iter = NULL;
+ bool handle_ok;
+ succeeded = response->ReadBool(&iter, &handle_ok);
+ if (succeeded)
+ succeeded = response->ReadInt(&iter, &window_handle);
+
+ if (succeeded) {
+ return new WindowProxy(this, tracker_.get(), window_handle);
+ } else {
+ return NULL;
+ }
+}
+
+AutocompleteEditProxy* AutomationProxy::GetAutocompleteEditForBrowser(
+ BrowserProxy* browser) {
+ if (!browser->is_valid() || !browser->handle())
+ return NULL;
+
+ IPC::Message* response = NULL;
+ if (!SendAndWaitForResponse(
+ new AutomationMsg_AutocompleteEditForBrowserRequest(0, browser->handle()),
+ &response, AutomationMsg_AutocompleteEditForBrowserResponse::ID))
+ return NULL;
+ scoped_ptr<IPC::Message> response_deleter(response);
+
+ int autocomplete_edit_handle;
+ void* iter = NULL;
+ bool handle_ok;
+ if (!response->ReadBool(&iter, &handle_ok) ||
+ !response->ReadInt(&iter, &autocomplete_edit_handle))
+ return NULL;
+
+ return new AutocompleteEditProxy(this, tracker_.get(),
+ autocomplete_edit_handle);
+}
+
+bool AutomationProxy::SendAndWaitForResponse(IPC::Message* request,
+ IPC::Message** response,
+ int response_type) {
+ return SendAndWaitForResponseWithTimeout(request, response, response_type,
+ INFINITE, NULL);
+}
+
+bool AutomationProxy::SendAndWaitForResponseWithTimeout(
+ IPC::Message* request,
+ IPC::Message** response,
+ int response_type,
+ uint32 timeout_ms,
+ bool* is_timeout) {
+
+ DCHECK(request);
+ DCHECK(response);
+ DCHECK(!current_request_) <<
+ "Only one synchronous request should exist at any given time.";
+
+ scoped_refptr<AutomationRequest> req = new AutomationRequest;
+ current_request_ = req;
+
+ // Rewrite the message's routing ID so that we'll recognize the response
+ // to it when it comes back.
+ request->set_routing_id(req->routing_id());
+ bool result = Send(request) && req->WaitForResponse(timeout_ms, is_timeout);
+ if (!result || req->response().type() != response_type) {
+ // If Send() or WaitForResponse() failed, current_request_ may not have
+ // gotten cleared by the background thread, so we'll clear it here.
+ current_request_ = NULL;
+ return false;
+ }
+ req->GrabResponse(response);
+
+ return true;
+}
+
+void AutomationProxy::InvalidateHandle(const IPC::Message& message) {
+ void* iter = NULL;
+ int handle;
+
+ if (message.ReadInt(&iter, &handle)) {
+ tracker_->InvalidateHandle(handle);
+ }
+}
+
+bool AutomationProxy::OpenNewBrowserWindow(int show_command) {
+ return Send(new AutomationMsg_OpenNewBrowserWindow(0, show_command));
+}
+
+TabProxy* AutomationProxy::CreateExternalTab(HWND* external_tab_container) {
+ IPC::Message* response = NULL;
+ bool succeeded = SendAndWaitForResponse(
+ new AutomationMsg_CreateExternalTab(0), &response,
+ AutomationMsg_CreateExternalTabResponse::ID);
+ if (!succeeded) {
+ return NULL;
+ }
+ void* iter = NULL;
+ int handle = 0;
+ TabProxy* tab_proxy = NULL;
+ if (IPC::ReadParam(response, &iter, external_tab_container) &&
+ IsWindow(*external_tab_container)) {
+ if (response->ReadInt(&iter, &handle) &&
+ (handle >= 0)) {
+ succeeded = true;
+ tab_proxy = new TabProxy(this, tracker_.get(), handle);
+ }
+ } else {
+ succeeded = false;
+ }
+ delete response;
+ return tab_proxy;
+}
diff --git a/chrome/test/automation/automation_proxy.h b/chrome/test/automation/automation_proxy.h
new file mode 100644
index 0000000..e8d63b5
--- /dev/null
+++ b/chrome/test/automation/automation_proxy.h
@@ -0,0 +1,240 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_TEST_AUTOMATION_AUTOMATION_PROXY_H__
+#define CHROME_TEST_AUTOMATION_AUTOMATION_PROXY_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "base/thread.h"
+#include "chrome/common/ipc_channel_proxy.h"
+#include "chrome/common/ipc_message.h"
+#include "chrome/test/automation/automation_handle_tracker.h"
+#include "chrome/test/automation/automation_messages.h"
+
+class AutomationRequest;
+class BrowserProxy;
+class WindowProxy;
+class TabProxy;
+class AutocompleteEditProxy;
+
+// This is an interface that AutomationProxy-related objects can use to
+// access the message-sending abilities of the Proxy.
+class AutomationMessageSender : public IPC::Message::Sender {
+ public:
+ // Sends a message synchronously (from the perspective of the caller's
+ // thread, at least); it doesn't return until a response has been received.
+ // This method takes ownership of the request object passed in. The caller
+ // is responsible for deleting the response object when they're done with it.
+ // response_type should be set to the message type of the expected response.
+ // A response object will only be available if the method returns true.
+ // NOTE: This method will overwrite any routing_id on the request message,
+ // since it uses this field to match the response up with the request.
+ virtual bool SendAndWaitForResponse(IPC::Message* request,
+ IPC::Message** response,
+ int response_type) = 0;
+
+ // Sends a message synchronously; it doesn't return until a response has been
+ // received or a timeout has expired.
+ // The function returns true if a response is received, and returns false if
+ // there is a failure or timeout (in milliseconds). If return after timeout,
+ // is_timeout is set to true.
+ // See the comments in SendAndWaitForResponse for other details on usage.
+ // NOTE: When timeout occurs, the connection between proxy provider may be
+ // in transit state. Specifically, there might be pending IPC messages,
+ // and the proxy provider might be still working on the previous
+ // request.
+ virtual bool SendAndWaitForResponseWithTimeout(IPC::Message* request,
+ IPC::Message** response,
+ int response_type,
+ uint32 timeout_ms,
+ bool* is_timeout) = 0;
+};
+
+// This is the interface that external processes can use to interact with
+// a running instance of the app.
+class AutomationProxy : public IPC::Channel::Listener,
+ public AutomationMessageSender {
+ public:
+ AutomationProxy();
+ virtual ~AutomationProxy();
+
+ // IPC callback
+ virtual void OnMessageReceived(const IPC::Message& msg);
+ virtual void OnChannelError();
+
+ // Waits for the app to launch and the automation provider to say hello
+ // (the app isn't fully done loading by this point).
+ // Returns true if the launch is successful
+ bool WaitForAppLaunch();
+
+ // Waits for any initial page loads to complete.
+ // NOTE: this only fires once for a run of the application.
+ // Returns true if the load is successful
+ bool WaitForInitialLoads();
+
+ // Waits for the initial destinations tab to report that it has finished
+ // querying. |load_time| is filled in with how long it took, in milliseconds.
+ // NOTE: this only fires once for a run of the application.
+ // Returns true if the load is successful.
+ bool WaitForInitialNewTabUILoad(int* load_time);
+
+ // Open a new browser window, returning true on success. |show_command|
+ // identifies how the window should be shown.
+ // False likely indicates an IPC error.
+ bool OpenNewBrowserWindow(int show_command);
+
+ // Fills the number of open browser windows into the given variable, returning
+ // true on success. False likely indicates an IPC error.
+ bool GetBrowserWindowCount(int* num_windows);
+
+ // Block the thread until the window count changes.
+ // First parameter is the original window count.
+ // The second parameter is updated with the number of window tabs.
+ // The third parameter specifies the timeout length for the wait loop.
+ // Returns false if the window count does not change before time out.
+ // TODO(evanm): this function has a confusing name and semantics; it should
+ // be deprecated for WaitForWindowCountToBecome.
+ bool WaitForWindowCountToChange(int count, int* new_counter,
+ int wait_timeout);
+
+ // Block the thread until the window count becomes the provided value.
+ // Returns true on success.
+ bool WaitForWindowCountToBecome(int target_count, int wait_timeout);
+
+ // Returns the BrowserProxy for the browser window at the given index,
+ // transferring ownership of the pointer to the caller.
+ // On failure, returns NULL.
+ //
+ // Use GetBrowserWindowCount to see how many browser windows you can ask for.
+ // Window numbers are 0-based.
+ BrowserProxy* GetBrowserWindow(int window_index);
+
+ // Returns the BrowserProxy for the browser window which was last active,
+ // transferring ownership of the pointer to the caller.
+ // If there was no last active browser window, or the last active browser
+ // window no longer exists (for example, if it was closed), returns
+ // GetBrowserWindow(0).
+ BrowserProxy* GetLastActiveBrowserWindow();
+
+ // Returns the WindowProxy for the currently active window, transferring
+ // ownership of the pointer to the caller.
+ // On failure, returns NULL.
+ WindowProxy* GetActiveWindow();
+
+ // Returns the browser this window corresponds to, or NULL if this window
+ // is not a browser. The caller owns the returned BrowserProxy.
+ BrowserProxy* GetBrowserForWindow(WindowProxy* window);
+
+ // Same as GetBrowserForWindow except return NULL if response isn't received
+ // before the specified timeout.
+ BrowserProxy* GetBrowserForWindowWithTimeout(WindowProxy* window,
+ uint32 timeout_ms,
+ bool* is_timeout);
+
+ // Returns the WindowProxy for this browser's window. It can be used to
+ // retreive view bounds, simulate clicks and key press events. The caller
+ // owns the returned WindowProxy.
+ // On failure, returns NULL.
+ WindowProxy* GetWindowForBrowser(BrowserProxy* browser);
+
+ // Returns an AutocompleteEdit for this browser's window. It can be used to
+ // manipulate the omnibox. The caller owns the returned pointer.
+ // On failure, returns NULL.
+ AutocompleteEditProxy* GetAutocompleteEditForBrowser(BrowserProxy* browser);
+
+ // Tells the browser to enable or disable network request filtering. Returns
+ // false if the message fails to send to the browser.
+ bool SetFilteredInet(bool enabled);
+
+ // These methods are intended to be called by the background thread
+ // to signal that the given event has occurred, and that any corresponding
+ // Wait... function can return.
+ void SignalAppLaunch();
+ void SignalInitialLoads();
+ // load_time is how long, in ms, the tab contents took to load.
+ void SignalNewTabUITab(int load_time);
+
+ // Returns the ID of the automation IPC channel, so that it can be
+ // passed to the app as a launch parameter.
+ const std::wstring& channel_id() const { return channel_id_; }
+
+ // AutomationMessageSender implementations.
+ virtual bool Send(IPC::Message* message) { return channel_->Send(message); }
+ virtual bool SendAndWaitForResponse(IPC::Message* request,
+ IPC::Message** response,
+ int response_type);
+ virtual bool SendAndWaitForResponseWithTimeout(IPC::Message* request,
+ IPC::Message** response,
+ int response_type,
+ uint32 timeout_ms,
+ bool* is_timeout);
+
+ // Returns the current AutomationRequest object.
+ AutomationRequest* current_request() { return current_request_; }
+ // Clears the current AutomationRequest object.
+ void clear_current_request() { current_request_ = NULL; }
+
+ // Wrapper over AutomationHandleTracker::InvalidateHandle. Receives the message
+ // from AutomationProxy, unpacks the messages and routes that call to the
+ // tracker.
+ void InvalidateHandle(const IPC::Message& message);
+
+ // Creates a tab that can hosted in an external process. The function
+ // returns a TabProxy representing the tab as well as a window handle
+ // that can be reparented in another process.
+ TabProxy* AutomationProxy::CreateExternalTab(HWND* external_tab_container);
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(AutomationProxy);
+
+ void InitializeEvents();
+ void InitializeChannelID();
+ void InitializeThread();
+ void InitializeChannel();
+ void InitializeHandleTracker();
+
+ std::wstring channel_id_;
+ scoped_ptr<Thread> thread_;
+ scoped_ptr<IPC::ChannelProxy> channel_;
+ scoped_ptr<AutomationHandleTracker> tracker_;
+
+ HANDLE app_launched_;
+ HANDLE initial_loads_complete_;
+ HANDLE new_tab_ui_load_complete_;
+ int new_tab_ui_load_time_;
+
+ AutomationRequest* current_request_;
+
+ static const int kMaxCommandExecutionTime; // Delay to let the browser
+ // execute the command.;
+};
+
+#endif // CHROME_TEST_AUTOMATION_AUTOMATION_PROXY_H__
diff --git a/chrome/test/automation/automation_proxy_uitest.cc b/chrome/test/automation/automation_proxy_uitest.cc
new file mode 100644
index 0000000..b639007
--- /dev/null
+++ b/chrome/test/automation/automation_proxy_uitest.cc
@@ -0,0 +1,831 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <string>
+
+#include "base/file_util.h"
+#include "base/string_util.h"
+#include "chrome/app/chrome_dll_resource.h"
+#include "chrome/browser/view_ids.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/json_value_serializer.h"
+#include "chrome/test/automation/constrained_window_proxy.h"
+#include "chrome/test/automation/browser_proxy.h"
+#include "chrome/test/automation/tab_proxy.h"
+#include "chrome/test/automation/window_proxy.h"
+#include "chrome/test/ui/ui_test.h"
+#include "chrome/views/event.h"
+#include "net/base/net_util.h"
+
+typedef UITest AutomationProxyTest;
+
+class AutomationProxyVisibleTest : public UITest {
+ protected:
+ AutomationProxyVisibleTest() {
+ show_window_ = true;
+ }
+};
+
+TEST_F(AutomationProxyTest, GetBrowserWindowCount) {
+ int window_count = 0;
+ EXPECT_TRUE(automation()->GetBrowserWindowCount(&window_count));
+ EXPECT_EQ(1, window_count);
+#ifdef NDEBUG
+ ASSERT_FALSE(automation()->GetBrowserWindowCount(NULL));
+#endif
+}
+
+TEST_F(AutomationProxyTest, GetBrowserWindow) {
+ {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+ }
+
+ {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(-1));
+ ASSERT_FALSE(window.get());
+ }
+
+ {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(1));
+ ASSERT_FALSE(window.get());
+ }
+};
+
+TEST_F(AutomationProxyVisibleTest, WindowGetViewBounds) {
+ {
+ scoped_ptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(browser.get());
+ scoped_ptr<WindowProxy> window(
+ automation()->GetWindowForBrowser(browser.get()));
+ ASSERT_TRUE(window.get());
+
+ scoped_ptr<TabProxy> tab1(browser->GetTab(0));
+ ASSERT_TRUE(tab1.get());
+ GURL tab1_url;
+ ASSERT_TRUE(tab1->GetCurrentURL(&tab1_url));
+
+ // Add another tab so we can simulate dragging.
+ ASSERT_TRUE(browser->AppendTab(GURL("about:")));
+
+ scoped_ptr<TabProxy> tab2(browser->GetTab(1));
+ ASSERT_TRUE(tab2.get());
+ GURL tab2_url;
+ ASSERT_TRUE(tab2->GetCurrentURL(&tab2_url));
+
+ EXPECT_NE(tab1_url.spec(), tab2_url.spec());
+
+ gfx::Rect bounds;
+ ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_0, &bounds, false));
+ EXPECT_GT(bounds.x(), 0);
+ EXPECT_GT(bounds.width(), 0);
+ EXPECT_GT(bounds.height(), 0);
+
+ gfx::Rect bounds2;
+ ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_LAST, &bounds2, false));
+ EXPECT_GT(bounds2.width(), 0);
+ EXPECT_GT(bounds2.height(), 0);
+ EXPECT_GT(bounds2.x(), bounds.x());
+ EXPECT_EQ(bounds2.y(), bounds.y());
+
+ gfx::Rect urlbar_bounds;
+ ASSERT_TRUE(window->GetViewBounds(VIEW_ID_LOCATION_BAR, &urlbar_bounds,
+ false));
+ EXPECT_GT(urlbar_bounds.x(), 0);
+ EXPECT_GT(urlbar_bounds.y(), 0);
+ EXPECT_GT(urlbar_bounds.width(), 0);
+ EXPECT_GT(urlbar_bounds.height(), 0);
+
+ /*
+
+ TODO(beng): uncomment this section or move to interactive_ui_tests post
+ haste!
+
+ // Now that we know where the tabs are, let's try dragging one.
+ POINT start;
+ POINT end;
+ start.x = bounds.x() + bounds.width() / 2;
+ start.y = bounds.y() + bounds.height() / 2;
+ end.x = start.x + 2 * bounds.width() / 3;
+ end.y = start.y;
+ ASSERT_TRUE(browser->SimulateDrag(start, end,
+ ChromeViews::Event::EF_LEFT_BUTTON_DOWN));
+
+ // Check to see that the drag event successfully swapped the two tabs.
+ tab1.reset(browser->GetTab(0));
+ ASSERT_TRUE(tab1.get());
+ GURL tab1_new_url;
+ ASSERT_TRUE(tab1->GetCurrentURL(&tab1_new_url));
+
+ tab2.reset(browser->GetTab(1));
+ ASSERT_TRUE(tab2.get());
+ GURL tab2_new_url;
+ ASSERT_TRUE(tab2->GetCurrentURL(&tab2_new_url));
+
+ EXPECT_EQ(tab1_url.spec(), tab2_new_url.spec());
+ EXPECT_EQ(tab2_url.spec(), tab1_new_url.spec());
+
+ */
+ }
+}
+
+TEST_F(AutomationProxyTest, GetTabCount) {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+
+ int tab_count = 0;
+ ASSERT_TRUE(window->GetTabCount(&tab_count));
+ ASSERT_EQ(1, tab_count);
+}
+
+TEST_F(AutomationProxyTest, GetActiveTabIndex) {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+
+ int active_tab_index = -1;
+ ASSERT_TRUE(window->GetActiveTabIndex(&active_tab_index));
+ ASSERT_EQ(0, active_tab_index);
+}
+
+TEST_F(AutomationProxyVisibleTest, AppendTab) {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+
+ int original_tab_count;
+ ASSERT_TRUE(window->GetTabCount(&original_tab_count));
+ ASSERT_EQ(1, original_tab_count); // By default there are 2 tabs opened.
+
+ int original_active_tab_index;
+ ASSERT_TRUE(window->GetActiveTabIndex(&original_active_tab_index));
+ ASSERT_EQ(0, original_active_tab_index); // By default 0-th tab is active
+
+ ASSERT_TRUE(window->AppendTab(GURL("about:blank")));
+ int tab_count;
+ ASSERT_TRUE(window->GetTabCount(&tab_count));
+ ASSERT_EQ(original_tab_count + 1, tab_count);
+
+ int active_tab_index = -1;
+ ASSERT_TRUE(window->GetActiveTabIndex(&active_tab_index));
+ ASSERT_EQ(tab_count - 1, active_tab_index);
+ ASSERT_NE(original_active_tab_index, active_tab_index);
+
+ std::wstring filename(test_data_directory_);
+ file_util::AppendToPath(&filename, L"title2.html");
+ ASSERT_TRUE(window->AppendTab(net_util::FilePathToFileURL(filename)));
+
+ int appended_tab_index;
+ // Append tab will also be active tab
+ ASSERT_TRUE(window->GetActiveTabIndex(&appended_tab_index));
+
+ scoped_ptr<TabProxy> tab(window->GetTab(appended_tab_index));
+ ASSERT_TRUE(tab.get());
+ std::wstring title;
+ ASSERT_TRUE(tab->GetTabTitle(&title));
+ ASSERT_STREQ(L"Title Of Awesomeness", title.c_str());
+}
+
+TEST_F(AutomationProxyTest, ActivateTab) {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+
+ ASSERT_TRUE(window->AppendTab(GURL("about:blank")));
+
+ int at_index = 1;
+ ASSERT_TRUE(window->ActivateTab(at_index));
+ int active_tab_index = -1;
+ ASSERT_TRUE(window->GetActiveTabIndex(&active_tab_index));
+ ASSERT_EQ(at_index, active_tab_index);
+
+ at_index = 0;
+ ASSERT_TRUE(window->ActivateTab(at_index));
+ ASSERT_TRUE(window->GetActiveTabIndex(&active_tab_index));
+ ASSERT_EQ(at_index, active_tab_index);
+}
+
+
+TEST_F(AutomationProxyTest, GetTab) {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+ {
+ scoped_ptr<TabProxy> tab(window->GetTab(0));
+ ASSERT_TRUE(tab.get());
+ std::wstring title;
+ ASSERT_TRUE(tab->GetTabTitle(&title));
+ // BUG [634097] : expected title should be "about:blank"
+ ASSERT_STREQ(L"", title.c_str());
+ }
+
+ {
+ ASSERT_FALSE(window->GetTab(-1));
+ }
+
+ {
+ scoped_ptr<TabProxy> tab;
+ tab.reset(window->GetTab(1));
+ ASSERT_FALSE(tab.get());
+ }
+};
+
+TEST_F(AutomationProxyTest, NavigateToURL) {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+ scoped_ptr<TabProxy> tab(window->GetTab(0));
+ ASSERT_TRUE(tab.get());
+
+ std::wstring title;
+ ASSERT_TRUE(tab->GetTabTitle(&title));
+ // BUG [634097] : expected title should be "about:blank"
+ ASSERT_STREQ(L"", title.c_str());
+
+ std::wstring filename(test_data_directory_);
+ file_util::AppendToPath(&filename, L"title2.html");
+
+ tab->NavigateToURL(net_util::FilePathToFileURL(filename));
+ ASSERT_TRUE(tab->GetTabTitle(&title));
+ ASSERT_STREQ(L"Title Of Awesomeness", title.c_str());
+
+ // TODO(vibhor) : Add a test using testserver.
+}
+
+// This test is disabled. See bug 794412
+TEST_F(AutomationProxyTest, DISABLED_NavigateToURLWithTimeout1) {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+ scoped_ptr<TabProxy> tab(window->GetTab(0));
+ ASSERT_TRUE(tab.get());
+
+ std::wstring filename(test_data_directory_);
+ file_util::AppendToPath(&filename, L"title2.html");
+
+ bool is_timeout;
+ tab->NavigateToURLWithTimeout(net_util::FilePathToFileURL(filename),
+ 10000, &is_timeout);
+ ASSERT_FALSE(is_timeout);
+
+ std::wstring title;
+ ASSERT_TRUE(tab->GetTabTitle(&title));
+ ASSERT_STREQ(L"Title Of Awesomeness", title.c_str());
+
+ tab->NavigateToURLWithTimeout(net_util::FilePathToFileURL(filename),
+ 1, &is_timeout);
+ ASSERT_TRUE(is_timeout);
+
+ Sleep(10);
+}
+
+// This test is disabled. See bug 794412.
+TEST_F(AutomationProxyTest, DISABLED_NavigateToURLWithTimeout2) {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+ scoped_ptr<TabProxy> tab(window->GetTab(0));
+ tab.reset(window->GetTab(0));
+ ASSERT_TRUE(tab.get());
+
+ std::wstring filename1(test_data_directory_);
+ file_util::AppendToPath(&filename1, L"title1.html");
+
+ bool is_timeout;
+ tab->NavigateToURLWithTimeout(net_util::FilePathToFileURL(filename1),
+ 1, &is_timeout);
+ ASSERT_TRUE(is_timeout);
+
+ std::wstring filename2(test_data_directory_);
+ file_util::AppendToPath(&filename2, L"title2.html");
+ tab->NavigateToURLWithTimeout(net_util::FilePathToFileURL(filename2),
+ 10000, &is_timeout);
+ ASSERT_FALSE(is_timeout);
+
+ Sleep(10);
+}
+
+TEST_F(AutomationProxyTest, GoBackForward) {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+ scoped_ptr<TabProxy> tab(window->GetTab(0));
+ ASSERT_TRUE(tab.get());
+
+ std::wstring title;
+ ASSERT_TRUE(tab->GetTabTitle(&title));
+ // BUG [634097] : expected title should be "about:blank"
+ ASSERT_STREQ(L"", title.c_str());
+
+ ASSERT_FALSE(tab->GoBack());
+ ASSERT_TRUE(tab->GetTabTitle(&title));
+ ASSERT_STREQ(L"", title.c_str());
+
+ std::wstring filename(test_data_directory_);
+ file_util::AppendToPath(&filename, L"title2.html");
+ ASSERT_TRUE(tab->NavigateToURL(net_util::FilePathToFileURL(filename)));
+ ASSERT_TRUE(tab->GetTabTitle(&title));
+ ASSERT_STREQ(L"Title Of Awesomeness", title.c_str());
+
+ ASSERT_TRUE(tab->GoBack());
+ ASSERT_TRUE(tab->GetTabTitle(&title));
+ // BUG [634097] : expected title should be "about:blank"
+ ASSERT_STREQ(L"", title.c_str());
+
+ ASSERT_TRUE(tab->GoForward());
+ ASSERT_TRUE(tab->GetTabTitle(&title));
+ ASSERT_STREQ(L"Title Of Awesomeness", title.c_str());
+
+ ASSERT_FALSE(tab->GoForward());
+ ASSERT_TRUE(tab->GetTabTitle(&title));
+ ASSERT_STREQ(L"Title Of Awesomeness", title.c_str());
+}
+
+TEST_F(AutomationProxyTest, GetCurrentURL) {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+ scoped_ptr<TabProxy> tab(window->GetTab(0));
+ ASSERT_TRUE(tab.get());
+ GURL url;
+ ASSERT_TRUE(tab->GetCurrentURL(&url));
+ ASSERT_STREQ("about:blank", url.spec().c_str());
+
+ std::wstring filename(test_data_directory_);
+ file_util::AppendToPath(&filename, L"cookie1.html");
+ GURL newurl = net_util::FilePathToFileURL(filename);
+ ASSERT_TRUE(tab->NavigateToURL(newurl));
+ ASSERT_TRUE(tab->GetCurrentURL(&url));
+ // compare canonical urls...
+ ASSERT_STREQ(newurl.spec().c_str(), url.spec().c_str());
+}
+
+class AutomationProxyTest2 : public AutomationProxyVisibleTest {
+ protected:
+ AutomationProxyTest2() {
+ document1_ = test_data_directory_;
+ file_util::AppendToPath(&document1_, L"title1.html");
+
+ document2_ = test_data_directory_;
+ file_util::AppendToPath(&document2_, L"title2.html");
+ launch_arguments_ = document1_ + L" " + document2_;
+ }
+
+ std::wstring document1_;
+ std::wstring document2_;
+};
+
+TEST_F(AutomationProxyTest2, GetActiveTabIndex) {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+
+ int active_tab_index = -1;
+ ASSERT_TRUE(window->GetActiveTabIndex(&active_tab_index));
+ int tab_count;
+ ASSERT_TRUE(window->GetTabCount(&tab_count));
+ ASSERT_EQ(0, active_tab_index);
+ int at_index = 1;
+ ASSERT_TRUE(window->ActivateTab(at_index));
+ ASSERT_TRUE(window->GetActiveTabIndex(&active_tab_index));
+ ASSERT_EQ(at_index, active_tab_index);
+}
+
+TEST_F(AutomationProxyTest2, GetTabTitle) {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+ scoped_ptr<TabProxy> tab(window->GetTab(0));
+ ASSERT_TRUE(tab.get());
+ std::wstring title;
+ ASSERT_TRUE(tab->GetTabTitle(&title));
+ ASSERT_STREQ(L"title1.html", title.c_str());
+
+ tab.reset(window->GetTab(1));
+ ASSERT_TRUE(tab.get());
+ ASSERT_TRUE(tab->GetTabTitle(&title));
+ ASSERT_STREQ(L"Title Of Awesomeness", title.c_str());
+}
+
+TEST_F(AutomationProxyTest, Cookies) {
+ GURL url(L"http://mojo.jojo.google.com");
+ std::string value_result;
+
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+
+ scoped_ptr<TabProxy> tab(window->GetTab(0));
+ ASSERT_TRUE(tab.get());
+
+ // test setting the cookie:
+ ASSERT_TRUE(tab->SetCookie(url, "foo=baz"));
+
+ ASSERT_TRUE(tab->GetCookieByName(url, "foo", &value_result));
+ ASSERT_FALSE(value_result.empty());
+ ASSERT_STREQ("baz", value_result.c_str());
+
+ // test clearing the cookie:
+ ASSERT_TRUE(tab->SetCookie(url, "foo="));
+
+ ASSERT_TRUE(tab->GetCookieByName(url, "foo", &value_result));
+ ASSERT_TRUE(value_result.empty());
+
+ // now, test that we can get multiple cookies:
+ ASSERT_TRUE(tab->SetCookie(url, "foo1=baz1"));
+ ASSERT_TRUE(tab->SetCookie(url, "foo2=baz2"));
+
+ ASSERT_TRUE(tab->GetCookies(url, &value_result));
+ ASSERT_FALSE(value_result.empty());
+ EXPECT_TRUE(value_result.find("foo1=baz1") != std::string::npos);
+ EXPECT_TRUE(value_result.find("foo2=baz2") != std::string::npos);
+}
+
+TEST_F(AutomationProxyTest, GetHWND) {
+ scoped_ptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(browser.get());
+ scoped_ptr<WindowProxy> window(
+ automation()->GetWindowForBrowser(browser.get()));
+ ASSERT_TRUE(window.get());
+
+ HWND handle;
+ ASSERT_TRUE(window->GetHWND(&handle));
+ ASSERT_TRUE(handle);
+}
+
+TEST_F(AutomationProxyTest, NavigateToURLAsync) {
+ AutomationProxy* automation_object = automation();
+ scoped_ptr<BrowserProxy> window(automation_object->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+ scoped_ptr<TabProxy> tab(window->GetTab(0));
+ ASSERT_TRUE(tab.get());
+
+ std::wstring filename(test_data_directory_);
+ file_util::AppendToPath(&filename, L"cookie1.html");
+ GURL newurl = net_util::FilePathToFileURL(filename);
+
+ ASSERT_TRUE(tab->NavigateToURLAsync(newurl));
+ std::string value = WaitUntilCookieNonEmpty(tab.get(), newurl,
+ "foo", 250, 5*1000);
+ ASSERT_STREQ("baz", value.c_str());
+}
+
+TEST_F(AutomationProxyTest, AcceleratorNewTab) {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+
+ int old_tab_count = -1;
+ ASSERT_TRUE(window->GetTabCount(&old_tab_count));
+
+ ASSERT_TRUE(window->ApplyAccelerator(IDC_NEWTAB));
+ int new_tab_count;
+ ASSERT_TRUE(window->WaitForTabCountToChange(old_tab_count, &new_tab_count,
+ 5000));
+ if (new_tab_count == -1)
+ FAIL();
+ ASSERT_EQ(old_tab_count + 1, new_tab_count);
+ scoped_ptr<TabProxy> tab(window->GetTab(new_tab_count - 1));
+ ASSERT_TRUE(tab.get());
+
+ std::wstring title;
+ int i;
+ for (i = 0; i < 10; ++i) {
+ Sleep(kWaitForActionMaxMsec / 10);
+ ASSERT_TRUE(tab->GetTabTitle(&title));
+ if (title == L"Destinations" || title == L"New Tab")
+ break;
+ }
+ // If we got to 10, the new tab failed to open.
+ ASSERT_NE(10, i);
+}
+
+class AutomationProxyTest4 : public UITest {
+ protected:
+ AutomationProxyTest4() : UITest() {
+ dom_automation_enabled_ = true;
+ }
+};
+
+std::wstring SynthesizeJSURL(const std::wstring& value) {
+ std::wstring jscript;
+ SStringPrintf(&jscript,
+ L"javascript:void(window.domAutomationController.send(%s));", value.c_str());
+ return jscript;
+}
+
+TEST_F(AutomationProxyTest4, StringValueIsEchoedByDomAutomationController) {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+
+ scoped_ptr<TabProxy> tab(window->GetTab(0));
+ ASSERT_TRUE(tab.get());
+
+ std::wstring expected(L"string");
+ std::wstring jscript = SynthesizeJSURL(L"\"" + expected + L"\"");
+ std::wstring actual;
+ ASSERT_TRUE(tab->ExecuteAndExtractString(L"", jscript, &actual));
+ ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+std::wstring BooleanToString(bool bool_value) {
+ Value* value = Value::CreateBooleanValue(bool_value);
+ std::string json_string;
+ JSONStringValueSerializer serializer(&json_string);
+ serializer.Serialize(*value);
+ return UTF8ToWide(json_string);
+}
+
+TEST_F(AutomationProxyTest4, BooleanValueIsEchoedByDomAutomationController) {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+
+ scoped_ptr<TabProxy> tab(window->GetTab(0));
+ ASSERT_TRUE(tab.get());
+
+ bool expected = true;
+ std::wstring jscript = SynthesizeJSURL(BooleanToString(expected));
+ bool actual = false;
+ ASSERT_TRUE(tab->ExecuteAndExtractBool(L"", jscript, &actual));
+ ASSERT_EQ(expected, actual);
+}
+
+TEST_F(AutomationProxyTest4, NumberValueIsEchoedByDomAutomationController) {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+
+ scoped_ptr<TabProxy> tab(window->GetTab(0));
+ ASSERT_TRUE(tab.get());
+
+ int expected = 1;
+ int actual = 0;
+ std::wstring expected_string;
+ SStringPrintf(&expected_string, L"%d", expected);
+ std::wstring jscript = SynthesizeJSURL(expected_string);
+ ASSERT_TRUE(tab->ExecuteAndExtractInt(L"", jscript, &actual));
+ ASSERT_EQ(expected, actual);
+}
+
+// TODO(vibhor): Add a test for ExecuteAndExtractValue() for JSON Dictionary
+// type value
+
+class AutomationProxyTest3 : public UITest {
+ protected:
+ AutomationProxyTest3() : UITest() {
+ document1_ = test_data_directory_;
+ file_util::AppendToPath(&document1_, L"frame_dom_access");
+ file_util::AppendToPath(&document1_, L"frame_dom_access.html");
+
+ dom_automation_enabled_ = true;
+ launch_arguments_ = document1_;
+ }
+
+ std::wstring document1_;
+};
+
+std::wstring SynthesizeJSURLForDOMQuery(const std::wstring& id) {
+ std::wstring jscript;
+ SStringPrintf(&jscript,
+ L"javascript:void(window.domAutomationController)");
+ StringAppendF(&jscript, L".send(document.getElementById('%s').nodeName);",
+ id.c_str());
+ return jscript;
+}
+
+TEST_F(AutomationProxyTest3, FrameDocumentCanBeAccessed) {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+
+ scoped_ptr<TabProxy> tab(window->GetTab(0));
+ ASSERT_TRUE(tab.get());
+
+ std::wstring actual;
+ std::wstring xpath1 = L""; // top level frame
+ std::wstring jscript1 = SynthesizeJSURLForDOMQuery(L"myinput");
+ ASSERT_TRUE(tab->ExecuteAndExtractString(xpath1, jscript1, &actual));
+ ASSERT_EQ(L"INPUT", actual);
+
+ std::wstring xpath2 = L"/html/body/iframe";
+ std::wstring jscript2 = SynthesizeJSURLForDOMQuery(L"myspan");
+ ASSERT_TRUE(tab->ExecuteAndExtractString(xpath2, jscript2, &actual));
+ ASSERT_EQ(L"SPAN", actual);
+
+ std::wstring xpath3 = L"/html/body/iframe\n/html/body/iframe";
+ std::wstring jscript3 = SynthesizeJSURLForDOMQuery(L"mydiv");
+ ASSERT_TRUE(tab->ExecuteAndExtractString(xpath3, jscript3, &actual));
+ ASSERT_EQ(L"DIV", actual);
+
+ // TODO(evanm): fix or remove this.
+ // This part of the test appears to verify that executing JS fails
+ // non-HTML pages, but the new tab is now HTML so this test isn't
+ // correct.
+#if 0
+ // Open a new Destinations tab to execute script inside.
+ window->ApplyAccelerator(IDC_NEWTAB);
+ tab.reset(window->GetTab(1));
+ ASSERT_TRUE(tab.get());
+ ASSERT_TRUE(window->ActivateTab(1));
+
+ std::wstring title;
+ int i;
+ for (i = 0; i < 10; ++i) {
+ Sleep(kWaitForActionMaxMsec / 10);
+ ASSERT_TRUE(tab->GetTabTitle(&title));
+ if (title == L"Destinations")
+ break;
+ }
+ // If we got to 10, the new tab failed to open.
+ ASSERT_NE(10, i);
+ ASSERT_FALSE(tab->ExecuteAndExtractString(xpath1, jscript1, &actual));
+#endif
+}
+
+TEST_F(AutomationProxyTest, ConstrainedWindowTest) {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+
+ scoped_ptr<TabProxy> tab(window->GetTab(0));
+ tab.reset(window->GetTab(0));
+ ASSERT_TRUE(tab.get());
+
+ std::wstring filename(test_data_directory_);
+ file_util::AppendToPath(&filename, L"constrained_files");
+ file_util::AppendToPath(&filename, L"constrained_window.html");
+
+ ASSERT_TRUE(tab->NavigateToURL(net_util::FilePathToFileURL(filename)));
+
+ int count;
+ ASSERT_TRUE(tab->WaitForChildWindowCountToChange(0, &count, 5000));
+
+ ASSERT_EQ(2, count);
+
+ ConstrainedWindowProxy* cwindow = tab->GetConstrainedWindow(0);
+ ASSERT_TRUE(cwindow);
+
+ std::wstring title;
+ ASSERT_TRUE(cwindow->GetTitle(&title));
+ ASSERT_STREQ(L"Constrained Window 0 - Google Chrome", title.c_str());
+ delete cwindow;
+
+ cwindow = tab->GetConstrainedWindow(1);
+ ASSERT_TRUE(cwindow);
+ ASSERT_TRUE(cwindow->GetTitle(&title));
+ ASSERT_STREQ(L"Constrained Window 1 - Google Chrome", title.c_str());
+ delete cwindow;
+}
+
+TEST_F(AutomationProxyTest, CantEscapeByOnloadMoveto) {
+ scoped_ptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(window.get());
+
+ scoped_ptr<TabProxy> tab(window->GetTab(0));
+ tab.reset(window->GetTab(0));
+ ASSERT_TRUE(tab.get());
+
+ std::wstring filename(test_data_directory_);
+ file_util::AppendToPath(&filename, L"constrained_files");
+ file_util::AppendToPath(&filename, L"constrained_window_onload_moveto.html");
+
+ ASSERT_TRUE(tab->NavigateToURL(net_util::FilePathToFileURL(filename)));
+
+ int count;
+ ASSERT_TRUE(tab->WaitForChildWindowCountToChange(0, &count, 5000));
+
+ ASSERT_EQ(1, count);
+
+ ConstrainedWindowProxy* cwindow = tab->GetConstrainedWindow(0);
+ ASSERT_TRUE(cwindow);
+
+ gfx::Rect rect;
+ bool is_timeout = false;
+ ASSERT_TRUE(cwindow->GetBoundsWithTimeout(&rect, 1000, &is_timeout));
+ ASSERT_FALSE(is_timeout);
+ ASSERT_NE(20, rect.x());
+ ASSERT_NE(20, rect.y());
+}
+
+bool ExternalTabHandler(HWND external_tab_window) {
+ static const wchar_t class_name[] = L"External_Tab_UI_Test_Class";
+ static const wchar_t window_title[] = L"External Tab Tester";
+
+ WNDCLASSEX wnd_class = {0};
+ wnd_class.cbSize = sizeof(wnd_class);
+ wnd_class.style = CS_HREDRAW | CS_VREDRAW;
+ wnd_class.lpfnWndProc = DefWindowProc;
+ wnd_class.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ wnd_class.lpszClassName = class_name;
+ ATOM result = RegisterClassEx(&wnd_class);
+ if (0 == result) {
+ return false;
+ }
+
+ unsigned long style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
+ HWND external_tab_ui_parent = CreateWindow(class_name, window_title,
+ style, CW_USEDEFAULT, 0,
+ CW_USEDEFAULT, 0, NULL, NULL,
+ NULL, NULL);
+ style = GetWindowLong(external_tab_window, GWL_STYLE);
+ style |= WS_CHILD;
+ style &= ~WS_POPUP;
+ SetWindowLong(external_tab_window, GWL_STYLE, style);
+ SetParent(external_tab_window, external_tab_ui_parent);
+ RECT client_rect = {0};
+ GetClientRect(external_tab_ui_parent, &client_rect);
+ SetWindowPos(external_tab_window, NULL, 0, 0, client_rect.right,
+ client_rect.bottom, SWP_NOZORDER);
+ ShowWindow(external_tab_window, SW_SHOW);
+ ShowWindow(external_tab_ui_parent, SW_SHOW);
+
+ // Allow the renderers to connect.
+ Sleep(1000);
+ DestroyWindow(external_tab_ui_parent);
+ return true;
+}
+
+TEST_F(AutomationProxyVisibleTest, CreateExternalTab) {
+ HWND external_tab_container = NULL;
+ scoped_ptr<TabProxy> tab(automation()->CreateExternalTab(
+ &external_tab_container));
+ EXPECT_TRUE(tab != NULL);
+ EXPECT_NE(FALSE, ::IsWindow(external_tab_container));
+ if (tab != NULL) {
+ tab->NavigateInExternalTab(GURL(L"http://www.google.com"));
+ EXPECT_EQ(true, ExternalTabHandler(external_tab_container));
+ // Since the tab goes away lazily, wait a bit
+ Sleep(1000);
+ EXPECT_FALSE(tab->is_valid());
+ }
+}
+
+TEST_F(AutomationProxyTest, AutocompleteGetSetText) {
+ scoped_ptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(browser.get());
+ scoped_ptr<AutocompleteEditProxy> edit(
+ automation()->GetAutocompleteEditForBrowser(browser.get()));
+ ASSERT_TRUE(edit.get());
+ EXPECT_TRUE(edit->is_valid());
+ const std::wstring text_to_set = L"Lollerskates";
+ std::wstring actual_text;
+ EXPECT_TRUE(edit->SetText(text_to_set));
+ EXPECT_TRUE(edit->GetText(&actual_text));
+ EXPECT_EQ(text_to_set, actual_text);
+ scoped_ptr<AutocompleteEditProxy> edit2(
+ automation()->GetAutocompleteEditForBrowser(browser.get()));
+ EXPECT_TRUE(edit2->GetText(&actual_text));
+ EXPECT_EQ(text_to_set, actual_text);
+}
+
+TEST_F(AutomationProxyTest, AutocompleteParallelProxy)
+{
+ scoped_ptr<BrowserProxy> browser1(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(browser1.get());
+ scoped_ptr<AutocompleteEditProxy> edit1(
+ automation()->GetAutocompleteEditForBrowser(browser1.get()));
+ ASSERT_TRUE(edit1.get());
+ EXPECT_TRUE(browser1->ApplyAccelerator(IDC_DUPLICATE));
+ scoped_ptr<BrowserProxy> browser2(automation()->GetBrowserWindow(1));
+ ASSERT_TRUE(browser2.get());
+ scoped_ptr<AutocompleteEditProxy> edit2(
+ automation()->GetAutocompleteEditForBrowser(browser2.get()));
+ ASSERT_TRUE(edit2.get());
+ EXPECT_TRUE(browser2->GetTab(0)->WaitForTabToBeRestored());
+ const std::wstring text_to_set1 = L"Lollerskates";
+ const std::wstring text_to_set2 = L"Roflcopter";
+ std::wstring actual_text1, actual_text2;
+ EXPECT_TRUE(edit1->SetText(text_to_set1));
+ EXPECT_TRUE(edit2->SetText(text_to_set2));
+ EXPECT_TRUE(edit1->GetText(&actual_text1));
+ EXPECT_TRUE(edit2->GetText(&actual_text2));
+ EXPECT_EQ(text_to_set1, actual_text1);
+ EXPECT_EQ(text_to_set2, actual_text2);
+}
+
+TEST_F(AutomationProxyVisibleTest, AutocompleteMatchesTest) {
+ scoped_ptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(browser.get());
+ scoped_ptr<AutocompleteEditProxy> edit(
+ automation()->GetAutocompleteEditForBrowser(browser.get()));
+ ASSERT_TRUE(edit.get());
+ EXPECT_TRUE(browser->ApplyAccelerator(IDC_FOCUS_LOCATION));
+ EXPECT_TRUE(edit->is_valid());
+ EXPECT_TRUE(edit->SetText(L"Roflcopter"));
+ EXPECT_TRUE(edit->WaitForQuery(30000));
+ bool query_in_progress;
+ EXPECT_TRUE(edit->IsQueryInProgress(&query_in_progress));
+ EXPECT_FALSE(query_in_progress);
+ std::vector<AutocompleteMatchData> matches;
+ EXPECT_TRUE(edit->GetAutocompleteMatches(&matches));
+ EXPECT_FALSE(matches.empty());
+}
diff --git a/chrome/test/automation/browser_proxy.cc b/chrome/test/automation/browser_proxy.cc
new file mode 100644
index 0000000..81b8900
--- /dev/null
+++ b/chrome/test/automation/browser_proxy.cc
@@ -0,0 +1,348 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/test/automation/browser_proxy.h"
+
+#include <vector>
+
+#include "base/logging.h"
+#include "base/time.h"
+#include "chrome/test/automation/automation_constants.h"
+#include "chrome/test/automation/automation_messages.h"
+#include "chrome/test/automation/automation_proxy.h"
+#include "chrome/test/automation/tab_proxy.h"
+
+bool BrowserProxy::ActivateTab(int tab_index) {
+ return ActivateTabWithTimeout(tab_index, INFINITE, NULL);
+}
+
+bool BrowserProxy::ActivateTabWithTimeout(int tab_index, uint32 timeout_ms,
+ bool* is_timeout) {
+ if (!is_valid())
+ return false;
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponseWithTimeout(
+ new AutomationMsg_ActivateTabRequest(0, handle_, tab_index), &response,
+ AutomationMsg_ActivateTabResponse::ID, timeout_ms, is_timeout);
+
+ scoped_ptr<IPC::Message> response_deleter(response); // Delete on return.
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ int activate_tab_response = -1;
+ if (response->ReadInt(&iter, &activate_tab_response) &&
+ (activate_tab_response >= 0)) {
+ succeeded = true;
+ } else {
+ succeeded = false;
+ }
+
+ return succeeded;
+}
+
+bool BrowserProxy::BringToFront() {
+ return BringToFrontWithTimeout(INFINITE, NULL);
+}
+
+bool BrowserProxy::BringToFrontWithTimeout(uint32 timeout_ms,
+ bool* is_timeout) {
+ if (!is_valid())
+ return false;
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponseWithTimeout(
+ new AutomationMsg_BringBrowserToFront(0, handle_), &response,
+ AutomationMsg_BringBrowserToFrontResponse::ID, timeout_ms, is_timeout);
+
+ scoped_ptr<IPC::Message> response_deleter(response); // Delete on return.
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ if (!response->ReadBool(&iter, &succeeded))
+ succeeded = false;
+
+ return succeeded;
+}
+
+bool BrowserProxy::IsPageMenuCommandEnabledWithTimeout(int id,
+ uint32 timeout_ms,
+ bool* is_timeout) {
+ if (!is_valid())
+ return false;
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponseWithTimeout(
+ new AutomationMsg_IsPageMenuCommandEnabled(0, handle_, id), &response,
+ AutomationMsg_IsPageMenuCommandEnabledResponse::ID, timeout_ms, is_timeout);
+
+ scoped_ptr<IPC::Message> response_deleter(response); // Delete on return.
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ if (!response->ReadBool(&iter, &succeeded))
+ succeeded = false;
+
+ return succeeded;
+}
+
+bool BrowserProxy::AppendTab(const GURL& tab_url) {
+ if (!is_valid())
+ return false;
+
+ IPC::Message* response = NULL;
+
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_AppendTabRequest(0, handle_, tab_url), &response,
+ AutomationMsg_AppendTabResponse::ID);
+
+ scoped_ptr<IPC::Message> response_deleter(response); // Delete on return.
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ int append_tab_response = -1;
+ if (response->ReadInt(&iter, &append_tab_response) &&
+ (append_tab_response >= 0)) {
+ succeeded = true;
+ } else {
+ succeeded = false;
+ }
+
+ return succeeded;
+}
+
+bool BrowserProxy::GetActiveTabIndex(int* active_tab_index) const {
+ return GetActiveTabIndexWithTimeout(active_tab_index, INFINITE, NULL);
+}
+
+bool BrowserProxy::GetActiveTabIndexWithTimeout(int* active_tab_index,
+ uint32 timeout_ms,
+ bool* is_timeout) const {
+ if (!is_valid())
+ return false;
+
+ if (!active_tab_index) {
+ NOTREACHED();
+ return false;
+ }
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponseWithTimeout(
+ new AutomationMsg_ActiveTabIndexRequest(0, handle_), &response,
+ AutomationMsg_ActiveTabIndexResponse::ID, timeout_ms, is_timeout);
+
+ scoped_ptr<IPC::Message> response_deleter(response); // Delete on return.
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ int active_tab_index_response = -1;
+ if (response->ReadInt(&iter, &active_tab_index_response) &&
+ (active_tab_index_response >= 0)) {
+ *active_tab_index = active_tab_index_response;
+ } else {
+ succeeded = false;
+ }
+
+ return succeeded;
+}
+
+TabProxy* BrowserProxy::GetTab(int tab_index) const {
+ if (!is_valid())
+ return NULL;
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_TabRequest(0, handle_, tab_index), &response,
+ AutomationMsg_TabResponse::ID);
+ scoped_ptr<IPC::Message> response_deleter(response); // Delete on return.
+ if (!succeeded)
+ return NULL;
+
+ void* iter = NULL;
+ int handle;
+
+ if (!response->ReadInt(&iter, &handle) || (handle == 0))
+ return NULL;
+ return new TabProxy(sender_, tracker_, handle);
+}
+
+TabProxy* BrowserProxy::GetActiveTab() const {
+ return GetActiveTabWithTimeout(INFINITE, NULL);
+}
+
+TabProxy* BrowserProxy::GetActiveTabWithTimeout(uint32 timeout_ms,
+ bool* is_timeout) const {
+ int active_tab_index;
+ if (!GetActiveTabIndexWithTimeout(&active_tab_index, timeout_ms, is_timeout))
+ return NULL;
+ return GetTab(active_tab_index);
+}
+
+bool BrowserProxy::GetTabCount(int* num_tabs) const {
+ return GetTabCountWithTimeout(num_tabs, INFINITE, NULL);
+}
+
+bool BrowserProxy::GetTabCountWithTimeout(int* num_tabs, uint32 timeout_ms,
+ bool* is_timeout) const {
+ if (!is_valid())
+ return false;
+
+ if (!num_tabs) {
+ NOTREACHED();
+ return false;
+ }
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponseWithTimeout(
+ new AutomationMsg_TabCountRequest(0, handle_), &response,
+ AutomationMsg_TabCountResponse::ID, timeout_ms, is_timeout);
+
+ scoped_ptr<IPC::Message> response_deleter(response); // Delete on return.
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ int tab_count_response = -1;
+ if (response->ReadInt(&iter, &tab_count_response) &&
+ (tab_count_response >= 0)) {
+ *num_tabs = tab_count_response;
+ } else {
+ succeeded = false;
+ }
+
+ return succeeded;
+}
+
+bool BrowserProxy::ApplyAccelerator(int id) {
+ if (!is_valid())
+ return false;
+
+ return sender_->Send(
+ new AutomationMsg_ApplyAcceleratorRequest(0, handle_, id));
+}
+
+bool BrowserProxy::SimulateDrag(const POINT& start,
+ const POINT& end,
+ int flags) {
+ return SimulateDragWithTimeout(start, end, flags, INFINITE, NULL);
+}
+
+bool BrowserProxy::SimulateDragWithTimeout(const POINT& start,
+ const POINT& end,
+ int flags,
+ uint32 timeout_ms,
+ bool* is_timeout) {
+ if (!is_valid())
+ return false;
+
+ std::vector<POINT> drag_path;
+ drag_path.push_back(start);
+ drag_path.push_back(end);
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponseWithTimeout(
+ new AutomationMsg_WindowDragRequest(0, handle_, drag_path, flags),
+ &response, AutomationMsg_WindowDragResponse::ID, timeout_ms, is_timeout);
+
+ scoped_ptr<IPC::Message> response_deleter(response); // Delete on return.
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ if (!response->ReadBool(&iter, &succeeded))
+ succeeded = false;
+
+ return succeeded;
+}
+
+bool BrowserProxy::WaitForTabCountToChange(int count, int* new_count,
+ int wait_timeout) {
+ const TimeTicks start = TimeTicks::Now();
+ const TimeDelta timeout = TimeDelta::FromMilliseconds(wait_timeout);
+ while (TimeTicks::Now() - start < timeout) {
+ Sleep(automation::kSleepTime);
+ bool is_timeout;
+ bool succeeded = GetTabCountWithTimeout(new_count, wait_timeout,
+ &is_timeout);
+ if (!succeeded)
+ return false;
+ if (count != *new_count)
+ return true;
+ }
+ // If we get here, the tab count hasn't changed.
+ return false;
+}
+
+bool BrowserProxy::WaitForTabToBecomeActive(int tab,
+ int wait_timeout) {
+ const TimeTicks start = TimeTicks::Now();
+ const TimeDelta timeout = TimeDelta::FromMilliseconds(wait_timeout);
+ while (TimeTicks::Now() - start < timeout) {
+ Sleep(automation::kSleepTime);
+ int active_tab;
+ if (GetActiveTabIndex(&active_tab) && active_tab == tab)
+ return true;
+ }
+ // If we get here, the active tab hasn't changed.
+ return false;
+}
+
+bool BrowserProxy::GetHWND(HWND* handle) const {
+ if (!is_valid())
+ return false;
+
+ if (!handle) {
+ NOTREACHED();
+ return false;
+ }
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_WindowHWNDRequest(0, handle_), &response,
+ AutomationMsg_WindowHWNDResponse::ID);
+
+ scoped_ptr<IPC::Message> response_deleter(response); // Delete on return.
+ if (!succeeded)
+ return false;
+
+ HWND hwnd_response;
+ if (AutomationMsg_WindowHWNDResponse::Read(response, &hwnd_response) &&
+ hwnd_response) {
+ *handle = hwnd_response;
+ } else {
+ succeeded = false;
+ }
+
+ return succeeded;
+}
diff --git a/chrome/test/automation/browser_proxy.h b/chrome/test/automation/browser_proxy.h
new file mode 100644
index 0000000..469b377
--- /dev/null
+++ b/chrome/test/automation/browser_proxy.h
@@ -0,0 +1,164 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_TEST_AUTOMATION_BROWSER_PROXY_H__
+#define CHROME_TEST_AUTOMATION_BROWSER_PROXY_H__
+
+#include <string>
+#include <windows.h>
+#include "chrome/test/automation/automation_handle_tracker.h"
+
+class GURL;
+class TabProxy;
+
+namespace gfx {
+ class Rect;
+}
+
+// This class presents the interface to actions that can be performed on
+// a given browser window. Note that this object can be invalidated at any
+// time if the corresponding browser window in the app is closed. In that case,
+// any subsequent calls will return false immediately.
+class BrowserProxy : public AutomationResourceProxy {
+ public:
+ BrowserProxy(AutomationMessageSender* sender,
+ AutomationHandleTracker* tracker,
+ int handle)
+ : AutomationResourceProxy(tracker, sender, handle) {}
+ virtual ~BrowserProxy() {}
+
+ // Activates the tab corresponding to (zero-based) tab_index. Returns true if
+ // successful.
+ bool ActivateTab(int tab_index);
+
+ // Like ActivateTab, but returns false if response is not received before
+ // the specified timeout.
+ bool ActivateTabWithTimeout(int tab_index, uint32 timeout_ms,
+ bool* is_timeout);
+
+ // Bring the browser window to the front, activating it. Returns true on
+ // success.
+ bool BringToFront();
+
+ // Like BringToFront, but returns false if action is not completed before
+ // the specified timeout.
+ bool BringToFrontWithTimeout(uint32 timeout_ms, bool* is_timeout);
+
+ // Checks to see if a navigation command is active or not. Can also
+ // return false if action is not completed before the specified
+ // timeout; is_timeout will be set in those cases.
+ bool IsPageMenuCommandEnabledWithTimeout(int id, uint32 timeout_ms,
+ bool* is_timeout);
+
+ // Append a new tab to the TabStrip. The new tab is selected.
+ // The new tab navigates to the given tab_url.
+ // Returns true if successful.
+ // TODO(mpcomplete): If the navigation results in an auth challenge, the
+ // TabProxy we attach won't know about it. See bug 666730.
+ bool AppendTab(const GURL& tab_url);
+
+ // Gets the (zero-based) index of the currently active tab. Returns true if
+ // successful.
+ bool GetActiveTabIndex(int* active_tab_index) const;
+
+ // Like GetActiveTabIndex, but returns false if active tab is not received
+ // before the specified timeout.
+ bool GetActiveTabIndexWithTimeout(int* active_tab_index, uint32 timeout_ms,
+ bool* is_timeout) const;
+
+ // Returns the number of tabs in the given window. Returns true if
+ // the call was successful.
+ bool GetTabCount(int* num_tabs) const;
+
+ // Like GetTabCount, but returns false if tab count is not received within the
+ // before timeout.
+ bool GetTabCountWithTimeout(int* num_tabs, uint32 timeout_ms,
+ bool* is_timeout) const;
+
+ // Returns the TabProxy for the tab at the given index, transferring
+ // ownership of the pointer to the caller. On failure, returns NULL.
+ //
+ // Use GetTabCount to see how many windows you can ask for. Tab numbers
+ // are 0-based.
+ TabProxy* GetTab(int tab_index) const;
+
+ // Returns the TabProxy for the currently active tab, transferring
+ // ownership of the pointer to the caller. On failure, returns NULL.
+ TabProxy* GetActiveTab() const;
+
+ // Like GetActiveTab, but returns NULL if no response is received before
+ // the specified timout.
+ TabProxy* GetActiveTabWithTimeout(uint32 timeout_ms, bool* is_timeout) const;
+
+ // Apply the accelerator with given id (IDC_BACK, IDC_NEWTAB ...)
+ // Returns true if the call was successful.
+ //
+ // The alternate way to test the accelerators is to use the Windows messaging
+ // system to send the actual keyboard events (ui_controls.h) A precondition
+ // to using this system is that the target window should have the keyboard
+ // focus. This leads to a flaky test behavior in circumstances when the
+ // desktop screen is locked or the test is being executed over a remote
+ // desktop.
+ bool ApplyAccelerator(int id);
+
+ // Performs a drag operation between the start and end points (both defined
+ // in window coordinates). |flags| specifies which buttons are pressed for
+ // the drag, as defined in chrome/views/event.h.
+ virtual bool SimulateDrag(const POINT& start, const POINT& end, int flags);
+
+ // Like SimulateDrag, but returns false if response is not received before
+ // the specified timeout.
+ virtual bool SimulateDragWithTimeout(const POINT& start, const POINT& end,
+ int flags, uint32 timeout_ms,
+ bool* is_timeout);
+
+ // Block the thread until the tab count changes.
+ // |count| is the original tab count.
+ // |new_count| is updated with the number of new tabs.
+ // |wait_timeout| is the timeout, in milliseconds, for waiting.
+ // Returns false if the tab count does not change.
+ bool WaitForTabCountToChange(int count, int* new_count, int wait_timeout);
+
+ // Block the thread until the specified tab is the active tab.
+ // |wait_timeout| is the timeout, in milliseconds, for waiting.
+ // Returns false if the tab does not become active.
+ bool WaitForTabToBecomeActive(int tab, int wait_timeout);
+
+ // Gets the outermost HWND that corresponds to the given browser.
+ // Returns true if the call was successful.
+ // Note that ideally this should go and the version of WindowProxy should be
+ // used instead. We have to keep it for start_up_tests that test against a
+ // reference build.
+ bool GetHWND(HWND* handle) const;
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(BrowserProxy);
+};
+
+#endif // #define CHROME_TEST_AUTOMATION_BROWSER_PROXY_H__
diff --git a/chrome/test/automation/constrained_window_proxy.cc b/chrome/test/automation/constrained_window_proxy.cc
new file mode 100644
index 0000000..03fae09
--- /dev/null
+++ b/chrome/test/automation/constrained_window_proxy.cc
@@ -0,0 +1,92 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "constrained_window_proxy.h"
+
+#include "chrome/test/automation/automation_messages.h"
+#include "chrome/test/automation/automation_proxy.h"
+
+bool ConstrainedWindowProxy::GetTitle(std::wstring* title) const {
+ if (!is_valid())
+ return false;
+
+ if (!title) {
+ NOTREACHED();
+ return false;
+ }
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_ConstrainedTitleRequest(0, handle_), &response,
+ AutomationMsg_ConstrainedTitleResponse::ID);
+
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ int title_size_response = -1;
+ if (response->ReadInt(&iter, &title_size_response) &&
+ (title_size_response >= 0)) {
+ response->ReadWString(&iter, title);
+ } else {
+ succeeded = false;
+ }
+
+ delete response;
+ return succeeded;
+}
+
+bool ConstrainedWindowProxy::GetBoundsWithTimeout(gfx::Rect* bounds,
+ uint32 timeout_ms,
+ bool* is_timeout) {
+ if (!is_valid())
+ return false;
+
+ if (!bounds) {
+ NOTREACHED();
+ return false;
+ }
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponseWithTimeout(
+ new AutomationMsg_ConstrainedWindowBoundsRequest(0, handle_),
+ &response,
+ AutomationMsg_ConstrainedWindowBoundsResponse::ID,
+ timeout_ms,
+ is_timeout);
+ scoped_ptr<IPC::Message> responseDeleter(response);
+ if (!succeeded)
+ return false;
+
+ Tuple2<bool, gfx::Rect> result;
+ AutomationMsg_WindowViewBoundsResponse::Read(response, &result);
+
+ *bounds = result.b;
+ return result.a;
+}
diff --git a/chrome/test/automation/constrained_window_proxy.h b/chrome/test/automation/constrained_window_proxy.h
new file mode 100644
index 0000000..f3dcb6c
--- /dev/null
+++ b/chrome/test/automation/constrained_window_proxy.h
@@ -0,0 +1,59 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_TEST_AUTOMATION_CONSTRAINED_WINDOW_PROXY_H__
+#define CHROME_TEST_AUTOMATION_CONSTRAINED_WINDOW_PROXY_H__
+
+#include <string>
+
+#include "chrome/test/automation/automation_handle_tracker.h"
+
+namespace gfx {
+class Rect;
+}
+
+class ConstrainedWindowProxy : public AutomationResourceProxy {
+public:
+ ConstrainedWindowProxy(AutomationMessageSender* sender,
+ AutomationHandleTracker* tracker,
+ int handle)
+ : AutomationResourceProxy(tracker, sender, handle) {}
+
+ virtual ~ConstrainedWindowProxy() {}
+
+ bool GetTitle(std::wstring* title) const;
+ bool GetBoundsWithTimeout(gfx::Rect* bounds,
+ uint32 timeout_ms,
+ bool* is_timeout);
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(ConstrainedWindowProxy);
+};
+
+#endif // CHROME_TEST_AUTOMATION_CONSTRAINED_WINDOW_PROXY_H__ \ No newline at end of file
diff --git a/chrome/test/automation/tab_proxy.cc b/chrome/test/automation/tab_proxy.cc
new file mode 100644
index 0000000..4fb4432
--- /dev/null
+++ b/chrome/test/automation/tab_proxy.cc
@@ -0,0 +1,920 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/test/automation/tab_proxy.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "chrome/common/json_value_serializer.h"
+#include "chrome/test/automation/automation_constants.h"
+#include "chrome/test/automation/automation_messages.h"
+#include "chrome/test/automation/automation_proxy.h"
+#include "chrome/test/automation/constrained_window_proxy.h"
+#include "googleurl/src/gurl.h"
+
+bool TabProxy::GetTabTitle(std::wstring* title) const {
+ if (!is_valid())
+ return false;
+
+ if (!title) {
+ NOTREACHED();
+ return false;
+ }
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_TabTitleRequest(0, handle_), &response,
+ AutomationMsg_TabTitleResponse::ID);
+
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ int tab_title_size_response = -1;
+ if (response->ReadInt(&iter, &tab_title_size_response) &&
+ (tab_title_size_response >= 0)) {
+ response->ReadWString(&iter, title);
+ } else {
+ succeeded = false;
+ }
+
+ delete response;
+ return succeeded;
+}
+
+bool TabProxy::IsShelfVisible(bool* is_visible) {
+ if (!is_valid())
+ return false;
+
+ if (!is_visible) {
+ NOTREACHED();
+ return false;
+ }
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_ShelfVisibilityRequest(0, handle_),
+ &response,
+ AutomationMsg_ShelfVisibilityResponse::ID);
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ response->ReadBool(&iter, is_visible);
+ delete response;
+ return true;
+}
+
+int TabProxy::FindInPage(const std::wstring& search_string,
+ FindInPageDirection forward,
+ FindInPageCase match_case) {
+ if (!is_valid())
+ return -1;
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_FindInPageRequest(0, handle_, search_string,
+ forward, match_case),
+ &response,
+ AutomationMsg_FindInPageResponse::ID);
+ if (!succeeded)
+ return -1;
+
+ void* iter = NULL;
+ int matches_found;
+ AutomationMsg_FindInPageResponse::Read(response, &matches_found);
+
+ return matches_found;
+}
+
+int TabProxy::NavigateToURL(const GURL& url) {
+ return NavigateToURLWithTimeout(url, INFINITE, NULL);
+}
+
+int TabProxy::NavigateToURLWithTimeout(const GURL& url,
+ uint32 timeout_ms,
+ bool* is_timeout) {
+ if (!is_valid())
+ return AUTOMATION_MSG_NAVIGATION_ERROR;
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponseWithTimeout(
+ new AutomationMsg_NavigateToURLRequest(0, handle_, url), &response,
+ AutomationMsg_NavigateToURLResponse::ID, timeout_ms, is_timeout);
+
+ if (!succeeded)
+ return AUTOMATION_MSG_NAVIGATION_ERROR;
+
+ void* iter = NULL;
+ int navigate_response = AUTOMATION_MSG_NAVIGATION_ERROR;
+ response->ReadInt(&iter, &navigate_response);
+
+ delete response;
+ return navigate_response;
+}
+
+int TabProxy::NavigateInExternalTab(const GURL& url) {
+ if (!is_valid())
+ return AUTOMATION_MSG_NAVIGATION_ERROR;
+
+ IPC::Message* response = NULL;
+ bool is_timeout = false;
+ bool succeeded = sender_->SendAndWaitForResponseWithTimeout(
+ new AutomationMsg_NavigateInExternalTabRequest(0, handle_, url), &response,
+ AutomationMsg_NavigateInExternalTabResponse::ID, INFINITE, &is_timeout);
+
+ if (!succeeded)
+ return AUTOMATION_MSG_NAVIGATION_ERROR;
+
+ void* iter = NULL;
+ int navigate_response = AUTOMATION_MSG_NAVIGATION_ERROR;
+ response->ReadInt(&iter, &navigate_response);
+
+ delete response;
+ return navigate_response;
+}
+
+bool TabProxy::SetAuth(const std::wstring& username,
+ const std::wstring& password) {
+ if (!is_valid())
+ return false;
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_SetAuthRequest(0, handle_, username, password), &response,
+ AutomationMsg_SetAuthResponse::ID);
+
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ int navigate_response = -1;
+ succeeded = (response->ReadInt(&iter, &navigate_response) &&
+ navigate_response >= 0);
+
+ delete response;
+ return succeeded;
+}
+
+bool TabProxy::CancelAuth() {
+ if (!is_valid())
+ return false;
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_CancelAuthRequest(0, handle_), &response,
+ AutomationMsg_CancelAuthResponse::ID);
+
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ int navigate_response = -1;
+ succeeded = (response->ReadInt(&iter, &navigate_response) &&
+ navigate_response >= 0);
+
+ delete response;
+ return succeeded;
+}
+
+bool TabProxy::NeedsAuth() const {
+ if (!is_valid())
+ return false;
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_NeedsAuthRequest(0, handle_), &response,
+ AutomationMsg_NeedsAuthResponse::ID);
+
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ bool needs_auth = false;
+ response->ReadBool(&iter, &needs_auth);
+
+ delete response;
+ return needs_auth;
+}
+
+int TabProxy::GoBack() {
+ if (!is_valid())
+ return AUTOMATION_MSG_NAVIGATION_ERROR;
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_GoBackRequest(0, handle_), &response,
+ AutomationMsg_GoBackResponse::ID);
+
+ if (!succeeded)
+ return AUTOMATION_MSG_NAVIGATION_ERROR;
+
+ void* iter = NULL;
+ int navigate_response = AUTOMATION_MSG_NAVIGATION_ERROR;
+ response->ReadInt(&iter, &navigate_response);
+
+ delete response;
+ return navigate_response;
+}
+
+int TabProxy::GoForward() {
+ if (!is_valid())
+ return AUTOMATION_MSG_NAVIGATION_ERROR;
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_GoForwardRequest(0, handle_), &response,
+ AutomationMsg_GoForwardResponse::ID);
+
+ if (!succeeded)
+ return AUTOMATION_MSG_NAVIGATION_ERROR;
+
+ void* iter = NULL;
+ int navigate_response = AUTOMATION_MSG_NAVIGATION_ERROR;
+ response->ReadInt(&iter, &navigate_response);
+
+ delete response;
+ return navigate_response;
+}
+
+int TabProxy::Reload() {
+ if (!is_valid())
+ return AUTOMATION_MSG_NAVIGATION_ERROR;
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_ReloadRequest(0, handle_), &response,
+ AutomationMsg_ReloadResponse::ID);
+
+ if (!succeeded)
+ return AUTOMATION_MSG_NAVIGATION_ERROR;
+
+ void* iter = NULL;
+ int navigate_response = AUTOMATION_MSG_NAVIGATION_ERROR;
+ response->ReadInt(&iter, &navigate_response);
+
+ delete response;
+ return navigate_response;
+}
+
+bool TabProxy::GetRedirectsFrom(const GURL& source_url,
+ std::vector<GURL>* redirects) {
+ std::vector<GURL> output;
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_RedirectsFromRequest(0, handle_, source_url), &response,
+ AutomationMsg_RedirectsFromResponse::ID);
+ if (!succeeded)
+ return false;
+ scoped_ptr<IPC::Message> auto_deleter(response);
+
+ void* iter = NULL;
+ int num_redirects;
+ if (!response->ReadInt(&iter, &num_redirects))
+ return false;
+ if (num_redirects < 0)
+ return false; // Negative redirect counts indicate failure.
+
+ for (int i = 0; i < num_redirects; i++) {
+ GURL cur;
+ if (!IPC::ParamTraits<GURL>::Read(response, &iter, &cur))
+ return false;
+ output.push_back(cur);
+ }
+ redirects->swap(output);
+ return true;
+}
+
+bool TabProxy::GetCurrentURL(GURL* url) const {
+ if (!is_valid())
+ return false;
+
+ if (!url) {
+ NOTREACHED();
+ return false;
+ }
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_TabURLRequest(0, handle_), &response,
+ AutomationMsg_TabURLResponse::ID);
+
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ bool tab_url_success = false;
+ if (response->ReadBool(&iter, &tab_url_success) && tab_url_success) {
+ if (!IPC::ParamTraits<GURL>::Read(response, &iter, url))
+ succeeded = false;
+ } else {
+ succeeded = false;
+ }
+
+ delete response;
+ return succeeded;
+}
+
+bool TabProxy::NavigateToURLAsync(const GURL& url) {
+ if (!is_valid())
+ return false;
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_NavigationAsyncRequest(0, handle_, url), &response,
+ AutomationMsg_NavigationAsyncResponse::ID);
+
+ if (!succeeded)
+ return false;
+
+ bool status;
+ if (AutomationMsg_NavigationAsyncResponse::Read(response, &status) &&
+ status) {
+ succeeded = true;
+ }
+
+ delete response;
+ return succeeded;
+}
+
+bool TabProxy::GetHWND(HWND* hwnd) const {
+ if (!is_valid())
+ return false;
+ if (!hwnd) {
+ NOTREACHED();
+ return false;
+ }
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_TabHWNDRequest(0, handle_), &response,
+ AutomationMsg_TabHWNDResponse::ID);
+ if (!succeeded)
+ return false;
+ void* iter = NULL;
+ HWND tab_hwnd = NULL;
+ if (AutomationMsg_TabHWNDResponse::Read(response, &tab_hwnd) && tab_hwnd) {
+ *hwnd = tab_hwnd;
+ } else {
+ succeeded = false;
+ }
+
+ delete response;
+ return succeeded;
+}
+
+bool TabProxy::GetProcessID(int* process_id) const {
+ if (!is_valid())
+ return false;
+
+ if (!process_id) {
+ NOTREACHED();
+ return false;
+ }
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_TabProcessIDRequest(0, handle_), &response,
+ AutomationMsg_TabProcessIDResponse::ID);
+
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ int pid;
+ if (AutomationMsg_TabProcessIDResponse::Read(response, &pid) && (pid >= 0)) {
+ *process_id = pid;
+ } else {
+ succeeded = false;
+ }
+
+ delete response;
+ return succeeded;
+}
+
+bool TabProxy::ExecuteAndExtractString(const std::wstring& frame_xpath,
+ const std::wstring& jscript,
+ std::wstring* string_value) {
+ Value* root = NULL;
+ bool succeeded = ExecuteAndExtractValue(frame_xpath, jscript, &root);
+ if (!succeeded)
+ return false;
+
+ std::wstring read_value;
+ DCHECK(root->IsType(Value::TYPE_LIST));
+ Value* value = NULL;
+ succeeded = static_cast<ListValue*>(root)->Get(0, &value);
+ if (succeeded) {
+ succeeded = value->GetAsString(&read_value);
+ if (succeeded) {
+ string_value->swap(read_value);
+ }
+ }
+
+ delete root;
+ return succeeded;
+}
+
+bool TabProxy::ExecuteAndExtractBool(const std::wstring& frame_xpath,
+ const std::wstring& jscript,
+ bool* bool_value) {
+ Value* root = NULL;
+ bool succeeded = ExecuteAndExtractValue(frame_xpath, jscript, &root);
+ if (!succeeded)
+ return false;
+
+ bool read_value = false;
+ DCHECK(root->IsType(Value::TYPE_LIST));
+ Value* value = NULL;
+ succeeded = static_cast<ListValue*>(root)->Get(0, &value);
+ if (succeeded) {
+ succeeded = value->GetAsBoolean(&read_value);
+ if (succeeded) {
+ *bool_value = read_value;
+ }
+ }
+
+ delete value;
+ return succeeded;
+}
+
+bool TabProxy::ExecuteAndExtractInt(const std::wstring& frame_xpath,
+ const std::wstring& jscript,
+ int* int_value) {
+ Value* root = NULL;
+ bool succeeded = ExecuteAndExtractValue(frame_xpath, jscript, &root);
+ if (!succeeded)
+ return false;
+
+ int read_value = 0;
+ DCHECK(root->IsType(Value::TYPE_LIST));
+ Value* value = NULL;
+ succeeded = static_cast<ListValue*>(root)->Get(0, &value);
+ if (succeeded) {
+ succeeded = value->GetAsInteger(&read_value);
+ if (succeeded) {
+ *int_value = read_value;
+ }
+ }
+
+ delete value;
+ return succeeded;
+}
+
+bool TabProxy::ExecuteAndExtractValue(const std::wstring& frame_xpath,
+ const std::wstring& jscript,
+ Value** value) {
+ if (!is_valid())
+ return false;
+
+ if (!value) {
+ NOTREACHED();
+ return false;
+ }
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_DomOperationRequest(0, handle_, frame_xpath, jscript),
+ &response, AutomationMsg_DomOperationResponse::ID);
+
+ void* iter = NULL;
+ std::string json;
+ succeeded = response->ReadString(&iter, &json);
+ if (!succeeded) {
+ delete response;
+ return false;
+ }
+ // Wrap |json| in an array before deserializing because valid JSON has an
+ // array or an object as the root.
+ json.insert(0, "[");
+ json.append("]");
+
+ JSONStringValueSerializer deserializer(json);
+ succeeded = deserializer.Deserialize(value);
+
+ delete response;
+ return succeeded;
+}
+
+bool TabProxy::GetConstrainedWindowCount(int* count) const {
+ if (!is_valid())
+ return false;
+
+ if (!count) {
+ NOTREACHED();
+ return false;
+ }
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_ConstrainedWindowCountRequest(0, handle_),
+ &response, AutomationMsg_ConstrainedWindowCountResponse::ID);
+
+ void* iter = NULL;
+ int count_response = -1;
+ if (response->ReadInt(&iter, &count_response) &&
+ (count_response >= 0)) {
+ *count = count_response;
+ } else {
+ succeeded = false;
+ }
+
+ delete response;
+ return succeeded;
+}
+
+ConstrainedWindowProxy* TabProxy::GetConstrainedWindow(
+ int window_index) const {
+ if (!is_valid())
+ return NULL;
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_ConstrainedWindowRequest(0, handle_, window_index),
+ &response, AutomationMsg_ConstrainedWindowResponse::ID);
+ if (!succeeded)
+ return NULL;
+
+ void* iter = NULL;
+ int handle;
+
+ scoped_ptr<IPC::Message> response_deleter(response); // Ensure deleted.
+ if (response->ReadInt(&iter, &handle) && (handle != 0))
+ return new ConstrainedWindowProxy(sender_, tracker_, handle);
+ return NULL;
+}
+
+bool TabProxy::WaitForChildWindowCountToChange(int count, int* new_count,
+ int wait_timeout) {
+ int intervals = std::min(wait_timeout/automation::kSleepTime, 1);
+ for (int i = 0; i < intervals; ++i) {
+ Sleep(automation::kSleepTime);
+ bool succeeded = GetConstrainedWindowCount(new_count);
+ if (!succeeded) return false;
+ if (count != *new_count) return true;
+ }
+ // Constrained Window count did not change, return false.
+ return false;
+}
+
+bool TabProxy::GetCookies(const GURL& url, std::string* cookies) {
+ if (!is_valid())
+ return false;
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_GetCookiesRequest(0, url, handle_), &response,
+ AutomationMsg_GetCookiesResponse::ID);
+
+ if (succeeded) {
+ void* iter = NULL;
+ int size;
+ std::string local_value;
+
+ if (response->ReadInt(&iter, &size) && size >=0) {
+ if (!response->ReadString(&iter, cookies)) {
+ succeeded = false;
+ }
+ } else {
+ succeeded = false;
+ }
+ }
+
+ delete response;
+ return succeeded;
+}
+
+bool TabProxy::GetCookieByName(const GURL& url,
+ const std::string& name,
+ std::string* cookie) {
+ std::string cookies;
+ if (!GetCookies(url, &cookies))
+ return false;
+
+ std::string namestr = name + "=";
+ std::string::size_type idx = cookies.find(namestr);
+ if (idx != std::string::npos) {
+ cookies.erase(0, idx + namestr.length());
+ *cookie = cookies.substr(0, cookies.find(";"));
+ } else {
+ cookie->clear();
+ }
+
+ return true;
+}
+
+bool TabProxy::SetCookie(const GURL& url, const std::string& value) {
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_SetCookieRequest(0, url, value, handle_), &response,
+ AutomationMsg_SetCookieResponse::ID);
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ int response_value;
+
+ if (!response->ReadInt(&iter, &response_value) || response_value < 0) {
+ succeeded = false;
+ }
+
+ delete response;
+ return succeeded;
+}
+
+int TabProxy::InspectElement(int x, int y) {
+ if (!is_valid())
+ return -1;
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_InspectElementRequest(0, handle_, x, y),
+ &response, AutomationMsg_InspectElementResponse::ID);
+ if (!succeeded)
+ return -1;
+
+ int ret;
+ AutomationMsg_InspectElementResponse::Read(response, &ret);
+ return ret;
+}
+
+bool TabProxy::GetDownloadDirectory(std::wstring* download_directory) {
+ DCHECK(download_directory);
+ if (!is_valid())
+ return false;
+
+ IPC::Message* response = NULL;
+ bool succeeded =
+ sender_->SendAndWaitForResponse(
+ new AutomationMsg_DownloadDirectoryRequest(0, handle_),
+ &response,
+ AutomationMsg_DownloadDirectoryResponse::ID);
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ response->ReadWString(&iter, download_directory);
+ delete response;
+ return true;
+}
+
+bool TabProxy::ShowInterstitialPage(const std::string& html_text) {
+ if (!is_valid())
+ return false;
+
+ const int kTimeout = 2000;
+ bool is_timeout = false;
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponseWithTimeout(
+ new AutomationMsg_ShowInterstitialPageRequest(0, handle_, html_text),
+ &response,
+ AutomationMsg_ShowInterstitialPageResponse::ID, kTimeout, &is_timeout);
+
+ if (!succeeded || !is_timeout)
+ return false;
+
+ void* iter = NULL;
+ bool result = true;
+ response->ReadBool(&iter, &result);
+
+ delete response;
+ return result;
+}
+
+bool TabProxy::HideInterstitialPage() {
+ if (!is_valid())
+ return false;
+
+ IPC::Message* response = NULL;
+ bool succeeded =
+ sender_->SendAndWaitForResponse(
+ new AutomationMsg_HideInterstitialPageRequest(0, handle_),
+ &response,
+ AutomationMsg_HideInterstitialPageResponse::ID);
+
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ bool result = true;
+ response->ReadBool(&iter, &result);
+
+ delete response;
+ return result;
+}
+
+bool TabProxy::Close() {
+ return Close(false);
+}
+
+bool TabProxy::Close(bool wait_until_closed) {
+ if (!is_valid())
+ return false;
+
+ IPC::Message* response = NULL;
+ bool succeeded =
+ sender_->SendAndWaitForResponse(
+ new AutomationMsg_CloseTabRequest(0, handle_, wait_until_closed),
+ &response,
+ AutomationMsg_CloseTabResponse::ID);
+
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ bool result = true;
+ response->ReadBool(&iter, &result);
+
+ delete response;
+ return result;
+}
+
+bool TabProxy::SetAccelerators(HACCEL accel_table,
+ int accel_table_entry_count) {
+ if (!is_valid())
+ return false;
+
+ IPC::Message* response = NULL;
+ bool is_timeout = false;
+ bool succeeded = sender_->SendAndWaitForResponseWithTimeout(
+ new AutomationMsg_SetAcceleratorsForTab(0, handle_, accel_table,
+ accel_table_entry_count),
+ &response,
+ AutomationMsg_SetAcceleratorsForTabResponse::ID, INFINITE, &is_timeout);
+
+ if (!succeeded)
+ return AUTOMATION_MSG_NAVIGATION_ERROR;
+
+ void* iter = NULL;
+ bool set_accel_response = false;
+ response->ReadBool(&iter, &set_accel_response);
+
+ delete response;
+ return set_accel_response;
+}
+
+bool TabProxy::ProcessUnhandledAccelerator(const MSG& msg) {
+ if (!is_valid())
+ return false;
+ return sender_->Send(
+ new AutomationMsg_ProcessUnhandledAccelerator(0, handle_, msg));
+ // This message expects no response
+}
+
+bool TabProxy::WaitForTabToBeRestored() {
+ if (!is_valid())
+ return false;
+ IPC::Message* response = NULL;
+ return sender_->SendAndWaitForResponse(
+ new AutomationMsg_WaitForTabToBeRestored(0, handle_), &response,
+ AutomationMsg_TabFinishedRestoring::ID);
+}
+
+bool TabProxy::GetSecurityState(SecurityStyle* security_style,
+ int* ssl_cert_status,
+ int* mixed_content_state) {
+ DCHECK(security_style && ssl_cert_status && mixed_content_state);
+
+ if (!is_valid())
+ return false;
+
+ IPC::Message* response = NULL;
+ bool is_timeout = false;
+ bool succeeded = sender_->SendAndWaitForResponseWithTimeout(
+ new AutomationMsg_GetSecurityState(0, handle_),
+ &response,
+ AutomationMsg_GetSecurityStateResponse::ID, INFINITE, &is_timeout);
+ scoped_ptr<IPC::Message> auto_deleter(response);
+
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ int value;
+
+ response->ReadBool(&iter, &succeeded);
+ if (!succeeded)
+ return false;
+ response->ReadInt(&iter, &value);
+ *security_style = static_cast<SecurityStyle>(value);
+ response->ReadInt(&iter, ssl_cert_status);
+ response->ReadInt(&iter, mixed_content_state);
+
+ return true;
+}
+
+bool TabProxy::GetPageType(NavigationEntry::PageType* page_type) {
+ DCHECK(page_type);
+
+ if (!is_valid())
+ return false;
+
+ IPC::Message* response = NULL;
+ bool is_timeout = false;
+ bool succeeded = sender_->SendAndWaitForResponseWithTimeout(
+ new AutomationMsg_GetPageType(0, handle_),
+ &response,
+ AutomationMsg_GetPageTypeResponse::ID, INFINITE, &is_timeout);
+ scoped_ptr<IPC::Message> auto_deleter(response);
+
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ int value;
+ response->ReadBool(&iter, &succeeded);
+ if (!succeeded)
+ return false;
+ response->ReadInt(&iter, &value);
+ *page_type = static_cast<NavigationEntry::PageType>(value);
+ return true;
+}
+
+bool TabProxy::TakeActionOnSSLBlockingPage(bool proceed) {
+ if (!is_valid())
+ return false;
+
+ IPC::Message* response = NULL;
+ bool is_timeout = false;
+ bool succeeded = sender_->SendAndWaitForResponseWithTimeout(
+ new AutomationMsg_ActionOnSSLBlockingPage(0, handle_, proceed),
+ &response,
+ AutomationMsg_ActionOnSSLBlockingPageResponse::ID, INFINITE, &is_timeout);
+ scoped_ptr<IPC::Message> auto_deleter(response);
+
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ bool status = false;
+ response->ReadBool(&iter, &status);
+
+ return status;
+}
+
+bool TabProxy::PrintNow() {
+ if (!is_valid())
+ return false;
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_PrintNowRequest(0, handle_), &response,
+ AutomationMsg_PrintNowResponse::ID);
+ scoped_ptr<IPC::Message> auto_deleter(response);
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ succeeded = false;
+ return response->ReadBool(&iter, &succeeded) && succeeded;
+}
+
+bool TabProxy::SavePage(const std::wstring& file_name,
+ const std::wstring& dir_path,
+ SavePackage::SavePackageType type) {
+ if (!is_valid())
+ return false;
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_SavePageRequest(0, handle_, file_name,
+ dir_path, static_cast<int>(type)),
+ &response,
+ AutomationMsg_SavePageResponse::ID);
+
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ response->ReadBool(&iter, &succeeded);
+ delete response;
+
+ return succeeded;
+}
diff --git a/chrome/test/automation/tab_proxy.h b/chrome/test/automation/tab_proxy.h
new file mode 100644
index 0000000..712ab9c
--- /dev/null
+++ b/chrome/test/automation/tab_proxy.h
@@ -0,0 +1,266 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_TEST_AUTOMATION_TAB_PROXY_H__
+#define CHROME_TEST_AUTOMATION_TAB_PROXY_H__
+
+#include <wtypes.h>
+#include <string>
+#include <vector>
+
+#include "chrome/browser/security_style.h"
+#include "chrome/browser/navigation_entry.h"
+#include "chrome/browser/save_package.h"
+#include "chrome/test/automation/automation_handle_tracker.h"
+
+class ConstrainedWindowProxy;
+class GURL;
+class Value;
+
+typedef enum FindInPageDirection { BACK = 0, FWD = 1 };
+typedef enum FindInPageCase { IGNORE_CASE = 0, CASE_SENSITIVE = 1 };
+
+class TabProxy : public AutomationResourceProxy {
+ public:
+ TabProxy(AutomationMessageSender* sender,
+ AutomationHandleTracker* tracker,
+ int handle)
+ : AutomationResourceProxy(tracker, sender, handle) {}
+
+ virtual ~TabProxy() {}
+
+ // Gets the current url of the tab.
+ bool GetCurrentURL(GURL* url) const;
+
+ // Gets the title of the tab.
+ bool GetTabTitle(std::wstring* title) const;
+
+ // Gets the number of constrained window for this tab.
+ bool GetConstrainedWindowCount(int* count) const;
+
+ // Gets the proxy object for constrained window within this tab. Ownership
+ // for the returned object is transfered to the caller. Returns NULL on
+ // failure.
+ ConstrainedWindowProxy* GetConstrainedWindow(int window_index) const;
+
+ // Execute a javascript in a frame's context whose xpath
+ // is provided as the first parameter and extract
+ // the values from the resulting json string.
+ // Example:
+ // jscript = "window.domAutomationController.send('string');"
+ // will result in value = "string"
+ // jscript = "window.domAutomationController.send(24);"
+ // will result in value = 24
+ bool ExecuteAndExtractString(const std::wstring& frame_xpath,
+ const std::wstring& jscript,
+ std::wstring* value);
+ bool ExecuteAndExtractBool(const std::wstring& frame_xpath,
+ const std::wstring& jscript,
+ bool* value);
+ bool ExecuteAndExtractInt(const std::wstring& frame_xpath,
+ const std::wstring& jscript,
+ int* value);
+ bool ExecuteAndExtractValue(const std::wstring& frame_xpath,
+ const std::wstring& jscript,
+ Value** value);
+
+ // Navigates to a url. This method accepts the same kinds of URL input that
+ // can be passed to Chrome on the command line. This is a synchronous call and
+ // hence blocks until the navigation completes.
+ // Returns a status from AutomationMsg_NavigationResponseValues.
+ int NavigateToURL(const GURL& url);
+
+ // Navigates to a url. This is same as NavigateToURL with a timeout option.
+ // The function returns until the navigation completes or timeout (in
+ // milliseconds) occurs. If return after timeout, is_timeout is set to true.
+ int NavigateToURLWithTimeout(const GURL& url, uint32 timeout_ms,
+ bool* is_timeout);
+
+ // Navigates to a url in an externally hosted tab.
+ // This method accepts the same kinds of URL input that
+ // can be passed to Chrome on the command line. This is a synchronous call and
+ // hence blocks until the navigation completes.
+ // Returns a status from AutomationMsg_NavigationResponseValues.
+ int NavigateInExternalTab(const GURL& url);
+
+ // Navigates to a url. This is an asynchronous version of NavigateToURL.
+ // The function returns immediately after sending the LoadURL notification
+ // to the browser.
+ // TODO(vibhor): Add a callback if needed in future.
+ // TODO(mpcomplete): If the navigation results in an auth challenge, the
+ // TabProxy we attach won't know about it. See bug 666730.
+ bool NavigateToURLAsync(const GURL& url);
+
+ // Replaces a vector contents with the redirect chain out of the given URL.
+ // Returns true on success. Failure may be due to being unable to send the
+ // message, parse the response, or a failure of the history system in the
+ // browser.
+ bool GetRedirectsFrom(const GURL& source_url, std::vector<GURL>* redirects);
+
+ // Equivalent to hitting the Back button. This is a synchronous call and
+ // hence blocks until the navigation completes.
+ int GoBack();
+
+ // Equivalent to hitting the Forward button. This is a synchronous call and
+ // hence blocks until the navigation completes.
+ // Returns a status from AutomationMsg_NavigationResponseValues.
+ int GoForward();
+
+ // Equivalent to hitting the Reload button. This is a synchronous call and
+ // hence blocks until the navigation completes.
+ int Reload();
+
+ // Closes the tab. This is synchronous, but does NOT block until the tab has
+ // closed, rather it blocks until the browser has initiated the close. Use
+ // Close(true) if you need to block until tab completely closes.
+ //
+ // Note that this proxy is invalid after this call.
+ bool Close();
+
+ // Variant of close that allows you to specify whether you want to block
+ // until the tab has completely closed (wait_until_closed == true) or block
+ // until the browser has initiated the close (wait_until_closed = false).
+ //
+ // When a tab is closed the browser does additional work via invoke later
+ // and may wait for messages from the renderer. Supplying a value of true to
+ // this method waits until all processing is done. Be careful with this,
+ // when closing the last tab it is possible for the browser to shutdown BEFORE
+ // the tab has completely closed. In other words, this may NOT be sent for
+ // the last tab.
+ bool Close(bool wait_until_closed);
+
+ // Gets the HWND that corresponds to the content area of this tab.
+ // Returns true if the call was successful.
+ // Returns a status from AutomationMsg_NavigationResponseValues.
+ bool GetHWND(HWND* hwnd) const;
+
+ // Gets the process ID that corresponds to the content area of this tab.
+ // Returns true if the call was successful. If the specified tab has no
+ // separate process for rendering its content, the return value is true but
+ // the process_id is 0.
+ bool GetProcessID(int* process_id) const;
+
+ // Supply or cancel authentication to a login prompt. These are synchronous
+ // calls and hence block until the load finishes (or another login prompt
+ // appears, in the case of invalid login info).
+ bool SetAuth(const std::wstring& username, const std::wstring& password);
+ bool CancelAuth();
+
+ // Checks if this tab has a login prompt waiting for auth. This will be
+ // true if a navigation results in a login prompt, and if an attempted login
+ // fails.
+ // Note that this is only valid if you've done a navigation on this same
+ // object; different TabProxy objects can refer to the same Tab. Calls
+ // that can set this are NavigateToURL, GoBack, and GoForward.
+ // TODO(mpcomplete): we have no way of knowing if auth is needed after either
+ // NavigateToURLAsync, or after appending a tab with an URL that triggers
+ // auth.
+ bool NeedsAuth() const;
+
+ // Fills |*is_visible| with whether the tab's download shelf is currently
+ // visible. The return value indicates success. On failure, |*is_visible| is
+ // unchanged.
+ bool IsShelfVisible(bool* is_visible);
+
+ // Starts a search within the current tab. The parameter 'search_string'
+ // specifies what string to search for, 'forward' specifies whether to search
+ // in forward direction, and 'match_case' specifies case sensitivity
+ // (true=case sensitive). A return value of -1 indicates failure.
+ int FindInPage(const std::wstring& search_string, FindInPageDirection forward,
+ FindInPageCase match_case);
+
+ bool GetCookies(const GURL& url, std::string* cookies);
+ bool GetCookieByName(const GURL& url,
+ const std::string& name,
+ std::string* cookies);
+ bool SetCookie(const GURL& url, const std::string& value);
+
+ // Sends a InspectElement message for the current tab. |x| and |y| are the
+ // coordinates that we want to simulate that the user is trying to inspect.
+ int InspectElement(int x, int y);
+
+ // Block the thread until the constrained(child) window count changes.
+ // First parameter is the original child window count
+ // The second parameter is updated with the number of new child windows.
+ // The third parameter specifies the timeout length for the wait loop.
+ // Returns false if the count does not change.
+ bool WaitForChildWindowCountToChange(int count, int* new_count,
+ int wait_timeout);
+
+ bool GetDownloadDirectory(std::wstring* download_directory);
+
+ // Shows an interstitial page. Blocks until the interstitial page
+ // has been loaded. Return false if a failure happens.3
+ bool ShowInterstitialPage(const std::string& html_text);
+
+ // Hides the currently shown interstitial page. Blocks until the interstitial
+ // page has been hidden. Return false if a failure happens.
+ bool HideInterstitialPage();
+
+ // This sets the keyboard accelerators to be used by an externally
+ // hosted tab. This call is not valid on a regular tab hosted within
+ // Chrome.
+ bool SetAccelerators(HACCEL accel_table, int accel_table_entry_count);
+
+ // The container of an externally hosted tab calls this to reflect any
+ // accelerator keys that it did not process. This gives the tab a chance
+ // to handle the keys
+ bool ProcessUnhandledAccelerator(const MSG& msg);
+
+ bool WaitForTabToBeRestored();
+
+ // Retrieves the different security states for the current tab.
+ bool GetSecurityState(SecurityStyle* security_style,
+ int* ssl_cert_status,
+ int* mixed_content_state);
+
+ // Returns the type of the page currently showing (normal, interstitial,
+ // error).
+ bool GetPageType(NavigationEntry::PageType* page_type);
+
+ // Simulates the user action on the SSL blocking page. if |proceed| is true,
+ // this is equivalent to clicking the 'Proceed' button, if false to 'Take me
+ // out of there' button.
+ bool TakeActionOnSSLBlockingPage(bool proceed);
+
+ // Prints the current page without user intervention.
+ bool PrintNow();
+
+ // Save the current web page. |file_name| is the HTML file name, and
+ // |dir_path| is the directory for saving resource files. |type| indicates
+ // which type we're saving as: HTML only or the complete web page.
+ bool SavePage(const std::wstring& file_name,
+ const std::wstring& dir_path,
+ SavePackage::SavePackageType type);
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(TabProxy);
+};
+
+#endif // CHROME_TEST_AUTOMATION_TAB_PROXY_H__
diff --git a/chrome/test/automation/ui_controls.cc b/chrome/test/automation/ui_controls.cc
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chrome/test/automation/ui_controls.cc
diff --git a/chrome/test/automation/ui_controls.h b/chrome/test/automation/ui_controls.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chrome/test/automation/ui_controls.h
diff --git a/chrome/test/automation/window_proxy.cc b/chrome/test/automation/window_proxy.cc
new file mode 100644
index 0000000..5f647d2
--- /dev/null
+++ b/chrome/test/automation/window_proxy.cc
@@ -0,0 +1,187 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/test/automation/window_proxy.h"
+
+#include <vector>
+#include <algorithm>
+
+#include "base/gfx/rect.h"
+#include "base/logging.h"
+#include "chrome/test/automation/automation_constants.h"
+#include "chrome/test/automation/automation_messages.h"
+#include "chrome/test/automation/automation_proxy.h"
+#include "chrome/test/automation/browser_proxy.h"
+#include "chrome/test/automation/tab_proxy.h"
+#include "googleurl/src/gurl.h"
+
+bool WindowProxy::GetHWND(HWND* handle) const {
+ if (!is_valid()) return false;
+
+ if (!handle) {
+ NOTREACHED();
+ return false;
+ }
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_WindowHWNDRequest(0, handle_), &response,
+ AutomationMsg_WindowHWNDResponse::ID);
+ if (!succeeded)
+ return false;
+
+ HWND hwnd_response;
+ if (AutomationMsg_WindowHWNDResponse::Read(response, &hwnd_response) &&
+ hwnd_response) {
+ *handle = hwnd_response;
+ } else {
+ succeeded = false;
+ }
+
+ delete response;
+ return succeeded;
+}
+
+bool WindowProxy::SimulateOSClick(const POINT& click, int flags) {
+ if (!is_valid()) return false;
+
+ return sender_->Send(
+ new AutomationMsg_WindowClickRequest(0, handle_, click, flags));
+}
+
+bool WindowProxy::SimulateOSKeyPress(wchar_t key, int flags) {
+ if (!is_valid()) return false;
+
+ return sender_->Send(
+ new AutomationMsg_WindowKeyPressRequest(0, handle_, key, flags));
+}
+
+bool WindowProxy::SetVisible(bool visible) {
+ if (!is_valid()) return false;
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_SetWindowVisibleRequest(0, handle_, visible),
+ &response, AutomationMsg_SetWindowVisibleResponse::ID);
+
+ scoped_ptr<IPC::Message> response_deleter(response); // Ensure deleted.
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ if (!response->ReadBool(&iter, &succeeded))
+ succeeded = false;
+
+ return succeeded;
+}
+
+bool WindowProxy::IsActive(bool* active) {
+ if (!is_valid()) return false;
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_IsWindowActiveRequest(0, handle_),
+ &response, AutomationMsg_IsWindowActiveResponse::ID);
+
+ scoped_ptr<IPC::Message> response_deleter(response); // Ensure deleted.
+ if (!succeeded)
+ return false;
+
+ void* iter = NULL;
+ if (!response->ReadBool(&iter, &succeeded) || !succeeded)
+ return false;
+
+ if (!response->ReadBool(&iter, active))
+ return false;
+
+ return true;
+}
+
+bool WindowProxy::Activate() {
+ if (!is_valid()) return false;
+
+ return sender_->Send(new AutomationMsg_ActivateWindow(0, handle_));
+}
+
+bool WindowProxy::GetViewBounds(int view_id, gfx::Rect* bounds,
+ bool screen_coordinates) {
+ return GetViewBoundsWithTimeout(view_id, bounds, screen_coordinates,
+ INFINITE, NULL);
+}
+
+bool WindowProxy::GetViewBoundsWithTimeout(int view_id, gfx::Rect* bounds,
+ bool screen_coordinates,
+ uint32 timeout_ms,
+ bool* is_timeout) {
+ if (!is_valid()) return false;
+
+ if (!bounds) {
+ NOTREACHED();
+ return false;
+ }
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponseWithTimeout(
+ new AutomationMsg_WindowViewBoundsRequest(0, handle_, view_id,
+ screen_coordinates),
+ &response,
+ AutomationMsg_WindowViewBoundsResponse::ID,
+ timeout_ms,
+ is_timeout);
+ if (!succeeded)
+ return false;
+
+ Tuple2<bool, gfx::Rect> result;
+ AutomationMsg_WindowViewBoundsResponse::Read(response, &result);
+
+ *bounds = result.b;
+ return result.a;
+}
+
+bool WindowProxy::GetFocusedViewID(int* view_id) {
+ if (!is_valid()) return false;
+
+ if (!view_id) {
+ NOTREACHED();
+ return false;
+ }
+
+ IPC::Message* response = NULL;
+ bool succeeded = sender_->SendAndWaitForResponse(
+ new AutomationMsg_GetFocusedViewIDRequest(0, handle_),
+ &response,
+ AutomationMsg_GetFocusedViewIDResponse::ID);
+
+ *view_id = -1;
+ if (succeeded &&
+ AutomationMsg_GetFocusedViewIDResponse::Read(response, view_id))
+ return true;
+
+ return false;
+} \ No newline at end of file
diff --git a/chrome/test/automation/window_proxy.h b/chrome/test/automation/window_proxy.h
new file mode 100644
index 0000000..9fe7740
--- /dev/null
+++ b/chrome/test/automation/window_proxy.h
@@ -0,0 +1,106 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_TEST_AUTOMATION_WINDOW_PROXY_H__
+#define CHROME_TEST_AUTOMATION_WINDOW_PROXY_H__
+
+#include <string>
+#include "base/thread.h"
+#include "chrome/test/automation/automation_handle_tracker.h"
+
+class GURL;
+class BrowserProxy;
+class TabProxy;
+class WindowProxy;
+
+namespace gfx {
+ class Rect;
+}
+
+// This class presents the interface to actions that can be performed on a given
+// window. Note that this object can be invalidated at any time if the
+// corresponding window in the app is closed. In that case, any subsequent
+// calls will return false immediately.
+class WindowProxy : public AutomationResourceProxy {
+ public:
+ WindowProxy(AutomationMessageSender* sender,
+ AutomationHandleTracker* tracker,
+ int handle)
+ : AutomationResourceProxy(tracker, sender, handle) {}
+ virtual ~WindowProxy() {}
+
+ // Gets the outermost HWND that corresponds to the given window.
+ // Returns true if the call was successful.
+ bool GetHWND(HWND* handle) const;
+
+ // Simulates a click at the OS level. |click| is in the window's coordinates
+ // and |flags| specifies which buttons are pressed (as defined in
+ // chrome/views/event.h). Note that this is equivalent to the user moving
+ // the mouse and pressing the button. So if there is a window on top of this
+ // window, the top window is clicked.
+ bool SimulateOSClick(const POINT& click, int flags);
+
+ // Simulates a key press at the OS level. |key| is the key pressed and
+ // |flags| specifies which modifiers keys are also pressed (as defined in
+ // chrome/views/event.h). Note that this actually sends the event to the
+ // window that has focus.
+ bool SimulateOSKeyPress(wchar_t key, int flags);
+
+ // Shows/hides the window and as a result makes it active/inactive.
+ // Returns true if the call was successful.
+ bool SetVisible(bool visible);
+
+ // Sets |active| to true if this view is currently the active window.
+ // Returns true if the call was successful.
+ bool IsActive(bool* active);
+
+ // Make this window the active window.
+ // Returns true if the call was successful.
+ bool Activate();
+
+ // Gets the bounds (in window coordinates) that correspond to the view with
+ // the given ID in this window. Returns true if bounds could be obtained.
+ // If |screen_coordinates| is true, the bounds are returned in the coordinates
+ // of the screen, if false in the coordinates of the browser.
+ bool GetViewBounds(int view_id, gfx::Rect* bounds, bool screen_coordinates);
+
+ // Like GetViewBounds except returns false if timeout occurs before view
+ // bounds are obtained, and sets is_timeout accordingly.
+ bool GetViewBoundsWithTimeout(int view_id, gfx::Rect* bounds,
+ bool screen_coordinates, uint32 timeout_ms,
+ bool* is_timeout);
+ // Gets the id of the view that currently has focus. Returns true if the id
+ // was retrieved.
+ bool GetFocusedViewID(int* view_id);
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(WindowProxy);
+};
+
+#endif // CHROME_TEST_AUTOMATION_WINDOW_PROXY_H__