1 // Copyright (c) 2012 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.
5 #include <gtest/gtest.h>
11 #include "base/bind.h"
12 #include "base/callback.h"
13 #include "base/files/file_util.h"
14 #include "base/location.h"
15 #include "base/posix/eintr_wrapper.h"
16 #include "base/run_loop.h"
17 #include "base/single_thread_task_runner.h"
18 #include "base/strings/string_util.h"
19 #include "base/threading/thread.h"
20 #include "chromeos/process_proxy/process_output_watcher.h"
25 TestCase(const std::string
& input
, bool send_terminating_null
)
27 should_send_terminating_null(send_terminating_null
),
28 expected_output(input
) {}
30 // Conctructor for cases where the output is not expected to be the same as
32 TestCase(const std::string
& input
,
33 bool send_terminating_null
,
34 const std::string
& expected_output
)
36 should_send_terminating_null(send_terminating_null
),
37 expected_output(expected_output
) {}
40 bool should_send_terminating_null
;
41 std::string expected_output
;
44 class ProcessWatcherExpectations
{
46 ProcessWatcherExpectations() {}
48 void SetTestCase(const TestCase
& test_case
) {
49 received_from_out_
= 0;
51 out_expectations_
= test_case
.expected_output
;
52 if (test_case
.should_send_terminating_null
)
53 out_expectations_
.append(std::string("", 1));
56 bool CheckExpectations(const std::string
& data
, ProcessOutputType type
) {
57 EXPECT_EQ(PROCESS_OUTPUT_TYPE_OUT
, type
);
58 if (type
!= PROCESS_OUTPUT_TYPE_OUT
)
61 if (out_expectations_
.length() == 0 && data
.length() == 0)
64 EXPECT_LT(received_from_out_
, out_expectations_
.length());
65 if (received_from_out_
>= out_expectations_
.length())
68 EXPECT_EQ(received_from_out_
,
69 out_expectations_
.find(data
, received_from_out_
));
70 if (received_from_out_
!= out_expectations_
.find(data
, received_from_out_
))
73 received_from_out_
+= data
.length();
78 return received_from_out_
>= out_expectations_
.length();
82 std::string out_expectations_
;
83 size_t received_from_out_
;
86 class ProcessOutputWatcherTest
: public testing::Test
{
88 ProcessOutputWatcherTest() : output_watch_thread_started_(false),
92 ~ProcessOutputWatcherTest() override
{}
94 void TearDown() override
{
95 if (output_watch_thread_started_
)
96 output_watch_thread_
->Stop();
99 void StartWatch(int pt
, int stop
) {
100 // This will delete itself.
101 ProcessOutputWatcher
* crosh_watcher
= new ProcessOutputWatcher(pt
, stop
,
102 base::Bind(&ProcessOutputWatcherTest::OnRead
, base::Unretained(this)));
103 crosh_watcher
->Start();
106 void OnRead(ProcessOutputType type
, const std::string
& output
) {
107 ASSERT_FALSE(failed_
);
108 failed_
= !expectations_
.CheckExpectations(output
, type
);
109 if (failed_
|| expectations_
.IsDone()) {
110 ASSERT_FALSE(test_case_done_callback_
.is_null());
111 message_loop_
.task_runner()->PostTask(FROM_HERE
,
112 test_case_done_callback_
);
113 test_case_done_callback_
.Reset();
118 std::string
VeryLongString() {
119 std::string result
= "0123456789";
120 for (int i
= 0; i
< 8; i
++)
121 result
= result
.append(result
);
125 void RunTest(const std::vector
<TestCase
>& test_cases
) {
126 ASSERT_FALSE(output_watch_thread_started_
);
127 output_watch_thread_
.reset(new base::Thread("ProcessOutpuWatchThread"));
128 output_watch_thread_started_
= output_watch_thread_
->Start();
129 ASSERT_TRUE(output_watch_thread_started_
);
131 int pt_pipe
[2], stop_pipe
[2];
132 ASSERT_FALSE(HANDLE_EINTR(pipe(pt_pipe
)));
133 ASSERT_FALSE(HANDLE_EINTR(pipe(stop_pipe
)));
135 output_watch_thread_
->task_runner()->PostTask(
137 base::Bind(&ProcessOutputWatcherTest::StartWatch
,
138 base::Unretained(this), pt_pipe
[0], stop_pipe
[0]));
140 for (size_t i
= 0; i
< test_cases
.size(); i
++) {
141 expectations_
.SetTestCase(test_cases
[i
]);
143 base::RunLoop run_loop
;
144 ASSERT_TRUE(test_case_done_callback_
.is_null());
145 test_case_done_callback_
= run_loop
.QuitClosure();
147 const std::string
& test_str
= test_cases
[i
].input
;
148 // Let's make inputs not NULL terminated, unless other is specified in
150 ssize_t test_size
= test_str
.length() * sizeof(*test_str
.c_str());
151 if (test_cases
[i
].should_send_terminating_null
)
152 test_size
+= sizeof(*test_str
.c_str());
153 EXPECT_TRUE(base::WriteFileDescriptor(pt_pipe
[1], test_str
.c_str(),
157 EXPECT_TRUE(expectations_
.IsDone());
162 // Send stop signal. It is not important which string we send.
163 EXPECT_TRUE(base::WriteFileDescriptor(stop_pipe
[1], "q", 1));
165 EXPECT_NE(-1, IGNORE_EINTR(close(stop_pipe
[1])));
166 EXPECT_NE(-1, IGNORE_EINTR(close(pt_pipe
[1])));
170 base::Closure test_case_done_callback_
;
171 base::MessageLoop message_loop_
;
172 scoped_ptr
<base::Thread
> output_watch_thread_
;
173 bool output_watch_thread_started_
;
175 ProcessWatcherExpectations expectations_
;
176 std::vector
<TestCase
> exp
;
179 // http://crbug.com/396496
180 TEST_F(ProcessOutputWatcherTest
, DISABLED_OutputWatcher
) {
181 std::vector
<TestCase
> test_cases
;
182 test_cases
.push_back(TestCase("t", false));
183 test_cases
.push_back(TestCase("testing output\n", false));
184 test_cases
.push_back(TestCase("testing error\n", false));
185 test_cases
.push_back(TestCase("testing error1\n", false));
186 test_cases
.push_back(TestCase("testing output1\n", false));
187 test_cases
.push_back(TestCase("testing output2\n", false));
188 test_cases
.push_back(TestCase("testing output3\n", false));
189 test_cases
.push_back(TestCase(VeryLongString(), false));
190 test_cases
.push_back(TestCase("testing error2\n", false));
195 // http://crbug.com/396496
196 TEST_F(ProcessOutputWatcherTest
, DISABLED_SplitUTF8Character
) {
197 std::vector
<TestCase
> test_cases
;
198 test_cases
.push_back(TestCase("test1\xc2", false, "test1"));
199 test_cases
.push_back(TestCase("\xb5test1", false, "\xc2\xb5test1"));
204 // http://crbug.com/396496
205 TEST_F(ProcessOutputWatcherTest
, DISABLED_SplitSoleUTF8Character
) {
206 std::vector
<TestCase
> test_cases
;
207 test_cases
.push_back(TestCase("\xc2", false, ""));
208 test_cases
.push_back(TestCase("\xb5", false, "\xc2\xb5"));
213 // http://crbug.com/396496
214 TEST_F(ProcessOutputWatcherTest
, DISABLED_SplitUTF8CharacterLength3
) {
215 std::vector
<TestCase
> test_cases
;
216 test_cases
.push_back(TestCase("test3\xe2\x82", false, "test3"));
217 test_cases
.push_back(TestCase("\xac", false, "\xe2\x82\xac"));
222 // http://crbug.com/396496
223 TEST_F(ProcessOutputWatcherTest
, DISABLED_SplitSoleUTF8CharacterThreeWays
) {
224 std::vector
<TestCase
> test_cases
;
225 test_cases
.push_back(TestCase("\xe2", false, ""));
226 test_cases
.push_back(TestCase("\x82", false, ""));
227 test_cases
.push_back(TestCase("\xac", false, "\xe2\x82\xac"));
232 TEST_F(ProcessOutputWatcherTest
, EndsWithThreeByteUTF8Character
) {
233 std::vector
<TestCase
> test_cases
;
234 test_cases
.push_back(TestCase("test\xe2\x82\xac", false, "test\xe2\x82\xac"));
239 TEST_F(ProcessOutputWatcherTest
, SoleThreeByteUTF8Character
) {
240 std::vector
<TestCase
> test_cases
;
241 test_cases
.push_back(TestCase("\xe2\x82\xac", false, "\xe2\x82\xac"));
246 TEST_F(ProcessOutputWatcherTest
, HasThreeByteUTF8Character
) {
247 std::vector
<TestCase
> test_cases
;
248 test_cases
.push_back(
249 TestCase("test\xe2\x82\xac_", false, "test\xe2\x82\xac_"));
254 TEST_F(ProcessOutputWatcherTest
, MulitByteUTF8CharNullTerminated
) {
255 std::vector
<TestCase
> test_cases
;
256 test_cases
.push_back(TestCase("test\xe2\x82\xac", true, "test\xe2\x82\xac"));
261 // http://crbug.com/396496
262 TEST_F(ProcessOutputWatcherTest
, DISABLED_MultipleMultiByteUTF8Characters
) {
263 std::vector
<TestCase
> test_cases
;
264 test_cases
.push_back(
265 TestCase("test\xe2\x82\xac\xc2", false, "test\xe2\x82\xac"));
266 test_cases
.push_back(TestCase("\xb5", false, "\xc2\xb5"));
271 TEST_F(ProcessOutputWatcherTest
, ContainsInvalidUTF8
) {
272 std::vector
<TestCase
> test_cases
;
273 test_cases
.push_back(TestCase("\xc2_", false, "\xc2_"));
278 // http://crbug.com/396496
279 TEST_F(ProcessOutputWatcherTest
, DISABLED_InvalidUTF8SeriesOfTrailingBytes
) {
280 std::vector
<TestCase
> test_cases
;
281 test_cases
.push_back(TestCase("\x82\x82\x82", false, "\x82\x82\x82"));
282 test_cases
.push_back(TestCase("\x82\x82\x82", false, "\x82\x82\x82"));
287 TEST_F(ProcessOutputWatcherTest
, EndsWithInvalidUTF8
) {
288 std::vector
<TestCase
> test_cases
;
289 test_cases
.push_back(TestCase("\xff", false, "\xff"));
294 // http://crbug.com/396496
295 TEST_F(ProcessOutputWatcherTest
, DISABLED_FourByteUTF8
) {
296 std::vector
<TestCase
> test_cases
;
297 test_cases
.push_back(TestCase("\xf0\xa4\xad", false, ""));
298 test_cases
.push_back(TestCase("\xa2", false, "\xf0\xa4\xad\xa2"));
303 // Verifies that sending '\0' generates PROCESS_OUTPUT_TYPE_OUT event and does
304 // not terminate output watcher.
305 // http://crbug.com/396496
306 TEST_F(ProcessOutputWatcherTest
, DISABLED_SendNull
) {
307 std::vector
<TestCase
> test_cases
;
308 // This will send '\0' to output watcher.
309 test_cases
.push_back(TestCase("", true));
310 // Let's verify that next input also gets detected (i.e. output watcher does
311 // not exit after seeing '\0' from previous test case).
312 test_cases
.push_back(TestCase("a", true));
317 } // namespace chromeos