1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "fuchsia/base/test_navigation_listener.h"
6
7 #include <string>
8 #include <utility>
9
10 #include "base/auto_reset.h"
11 #include "base/bind.h"
12 #include "base/fuchsia/fuchsia_logging.h"
13 #include "base/run_loop.h"
14 #include "base/strings/stringprintf.h"
15 #include "fuchsia/base/mem_buffer_util.h"
16
17 namespace cr_fuchsia {
18 namespace {
19
QuitRunLoopAndRunCallback(base::OnceClosure quit_run_loop_closure,TestNavigationListener::BeforeAckCallback before_ack_callback,const fuchsia::web::NavigationState & change,fuchsia::web::NavigationEventListener::OnNavigationStateChangedCallback ack_callback)20 void QuitRunLoopAndRunCallback(
21 base::OnceClosure quit_run_loop_closure,
22 TestNavigationListener::BeforeAckCallback before_ack_callback,
23 const fuchsia::web::NavigationState& change,
24 fuchsia::web::NavigationEventListener::OnNavigationStateChangedCallback
25 ack_callback) {
26 std::move(quit_run_loop_closure).Run();
27 before_ack_callback.Run(change, std::move(ack_callback));
28 }
29
30 } // namespace
31
TestNavigationListener()32 TestNavigationListener::TestNavigationListener() {
33 // Set up the default acknowledgement handling behavior.
34 SetBeforeAckHook({});
35 }
36
37 TestNavigationListener::~TestNavigationListener() = default;
38
RunUntilNavigationStateMatches(const fuchsia::web::NavigationState & expected_state)39 void TestNavigationListener::RunUntilNavigationStateMatches(
40 const fuchsia::web::NavigationState& expected_state) {
41 DCHECK(before_ack_);
42
43 // Spin the runloop until the expected conditions are met.
44 while (!AllFieldsMatch(expected_state)) {
45 base::RunLoop run_loop;
46 base::AutoReset<BeforeAckCallback> callback_setter(
47 &before_ack_, base::BindRepeating(&QuitRunLoopAndRunCallback,
48 run_loop.QuitClosure(), before_ack_));
49 run_loop.Run();
50 }
51 }
52
RunUntilUrlEquals(const GURL & expected_url)53 void TestNavigationListener::RunUntilUrlEquals(const GURL& expected_url) {
54 fuchsia::web::NavigationState state;
55 state.set_url(expected_url.spec());
56 state.set_is_main_document_loaded(true);
57 RunUntilNavigationStateMatches(state);
58 }
59
RunUntilTitleEquals(const base::StringPiece expected_title)60 void TestNavigationListener::RunUntilTitleEquals(
61 const base::StringPiece expected_title) {
62 fuchsia::web::NavigationState state;
63 state.set_title(expected_title.as_string());
64 RunUntilNavigationStateMatches(state);
65 }
66
RunUntilUrlAndTitleEquals(const GURL & expected_url,const base::StringPiece expected_title)67 void TestNavigationListener::RunUntilUrlAndTitleEquals(
68 const GURL& expected_url,
69 const base::StringPiece expected_title) {
70 fuchsia::web::NavigationState state;
71 state.set_url(expected_url.spec());
72 state.set_title(expected_title.as_string());
73 RunUntilNavigationStateMatches(state);
74 }
75
RunUntilUrlTitleBackForwardEquals(const GURL & expected_url,base::StringPiece expected_title,bool expected_can_go_back,bool expected_can_go_forward)76 void TestNavigationListener::RunUntilUrlTitleBackForwardEquals(
77 const GURL& expected_url,
78 base::StringPiece expected_title,
79 bool expected_can_go_back,
80 bool expected_can_go_forward) {
81 fuchsia::web::NavigationState state;
82 state.set_url(expected_url.spec());
83 state.set_title(expected_title.as_string());
84 state.set_can_go_back(expected_can_go_back);
85 state.set_can_go_forward(expected_can_go_forward);
86 RunUntilNavigationStateMatches(state);
87 }
88
OnNavigationStateChanged(fuchsia::web::NavigationState change,OnNavigationStateChangedCallback callback)89 void TestNavigationListener::OnNavigationStateChanged(
90 fuchsia::web::NavigationState change,
91 OnNavigationStateChangedCallback callback) {
92 DCHECK(before_ack_);
93
94 // Update our local cache of the Frame's current state.
95 if (change.has_url())
96 current_state_.set_url(change.url());
97 if (change.has_title())
98 current_state_.set_title(change.title());
99 if (change.has_can_go_back())
100 current_state_.set_can_go_back(change.can_go_back());
101 if (change.has_can_go_forward())
102 current_state_.set_can_go_forward(change.can_go_forward());
103 if (change.has_is_main_document_loaded())
104 current_state_.set_is_main_document_loaded(
105 change.is_main_document_loaded());
106
107 if (VLOG_IS_ON(1)) {
108 std::string state_string;
109 state_string.reserve(100);
110
111 if (current_state_.has_url())
112 state_string.append(
113 base::StringPrintf(" url=%s ", current_state_.url().c_str()));
114
115 if (current_state_.has_title())
116 state_string.append(
117 base::StringPrintf(" title='%s' ", current_state_.title().c_str()));
118
119 if (current_state_.has_can_go_back())
120 state_string.append(
121 base::StringPrintf(" can_go_back=%d ", current_state_.can_go_back()));
122
123 if (current_state_.has_can_go_forward())
124 state_string.append(base::StringPrintf(" can_go_forward=%d ",
125 current_state_.can_go_forward()));
126
127 if (current_state_.has_is_main_document_loaded())
128 state_string.append(
129 base::StringPrintf(" is_main_document_loaded=%d ",
130 current_state_.is_main_document_loaded()));
131 VLOG(1) << "Navigation state changed: " << state_string;
132 }
133
134 // Signal readiness for the next navigation event.
135 before_ack_.Run(change, std::move(callback));
136 }
137
SetBeforeAckHook(BeforeAckCallback send_ack_cb)138 void TestNavigationListener::SetBeforeAckHook(BeforeAckCallback send_ack_cb) {
139 if (send_ack_cb) {
140 before_ack_ = send_ack_cb;
141 } else {
142 before_ack_ = base::BindRepeating(
143 [](const fuchsia::web::NavigationState&,
144 OnNavigationStateChangedCallback callback) { callback(); });
145 }
146 }
147
AllFieldsMatch(const fuchsia::web::NavigationState & expected)148 bool TestNavigationListener::AllFieldsMatch(
149 const fuchsia::web::NavigationState& expected) {
150 if (expected.has_url() &&
151 (!current_state_.has_url() || expected.url() != current_state_.url())) {
152 return false;
153 }
154
155 if (expected.has_title() && (!current_state_.has_title() ||
156 expected.title() != current_state_.title())) {
157 return false;
158 }
159
160 if (expected.has_can_go_forward() &&
161 (!current_state_.has_can_go_forward() ||
162 expected.can_go_forward() != current_state_.can_go_forward())) {
163 return false;
164 }
165
166 if (expected.has_can_go_back() &&
167 (!current_state_.has_can_go_back() ||
168 expected.can_go_back() != current_state_.can_go_back())) {
169 return false;
170 }
171
172 if (expected.has_is_main_document_loaded() &&
173 (!current_state_.has_is_main_document_loaded() ||
174 expected.is_main_document_loaded() !=
175 current_state_.is_main_document_loaded())) {
176 return false;
177 }
178
179 return true;
180 }
181
182 } // namespace cr_fuchsia
183