Update V8 to version 4.7.52.
[chromium-blink-merge.git] / chromeos / process_proxy / process_output_watcher_unittest.cc
blob2f2eb9996dfa7b0647dbb4958cf653b2892cc7bb
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>
7 #include <queue>
8 #include <string>
9 #include <vector>
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"
22 namespace chromeos {
24 namespace {
26 struct TestCase {
27 TestCase(const std::string& input, bool send_terminating_null)
28 : input(input),
29 should_send_terminating_null(send_terminating_null),
30 expected_output(input) {}
32 // Conctructor for cases where the output is not expected to be the same as
33 // input.
34 TestCase(const std::string& input,
35 bool send_terminating_null,
36 const std::string& expected_output)
37 : input(input),
38 should_send_terminating_null(send_terminating_null),
39 expected_output(expected_output) {}
41 std::string input;
42 bool should_send_terminating_null;
43 std::string expected_output;
46 class ProcessWatcherExpectations {
47 public:
48 ProcessWatcherExpectations() {}
50 void SetTestCase(const TestCase& test_case) {
51 received_from_out_ = 0;
53 out_expectations_ = test_case.expected_output;
54 if (test_case.should_send_terminating_null)
55 out_expectations_.append(std::string("", 1));
58 bool CheckExpectations(const std::string& data, ProcessOutputType type) {
59 EXPECT_EQ(PROCESS_OUTPUT_TYPE_OUT, type);
60 if (type != PROCESS_OUTPUT_TYPE_OUT)
61 return false;
63 if (out_expectations_.length() == 0 && data.length() == 0)
64 return true;
66 EXPECT_LT(received_from_out_, out_expectations_.length());
67 if (received_from_out_ >= out_expectations_.length())
68 return false;
70 EXPECT_EQ(received_from_out_,
71 out_expectations_.find(data, received_from_out_));
72 if (received_from_out_ != out_expectations_.find(data, received_from_out_))
73 return false;
75 received_from_out_ += data.length();
76 return true;
79 bool IsDone() {
80 return received_from_out_ >= out_expectations_.length();
83 private:
84 std::string out_expectations_;
85 size_t received_from_out_;
88 void StopProcessOutputWatcher(scoped_ptr<ProcessOutputWatcher> watcher) {
89 // Just deleting |watcher| if sufficient.
92 } // namespace
94 class ProcessOutputWatcherTest : public testing::Test {
95 public:
96 ProcessOutputWatcherTest() : output_watch_thread_started_(false),
97 failed_(false) {
100 ~ProcessOutputWatcherTest() override {}
102 void TearDown() override {
103 if (output_watch_thread_started_)
104 output_watch_thread_->Stop();
107 void OnRead(ProcessOutputType type, const std::string& output) {
108 ASSERT_FALSE(failed_);
109 // There may be an EXIT signal sent during test tear down (which is sent
110 // by process output watcher when master end of test pseudo-terminal is
111 // closed). If this happens, ignore it. If EXIT is seen before test
112 // expectations are met, fall through in order to fail the test.
113 if (type == PROCESS_OUTPUT_TYPE_EXIT && expectations_.IsDone()) {
114 ASSERT_TRUE(test_case_done_callback_.is_null());
115 return;
118 failed_ = !expectations_.CheckExpectations(output, type);
119 if (failed_ || expectations_.IsDone()) {
120 ASSERT_FALSE(test_case_done_callback_.is_null());
121 message_loop_.task_runner()->PostTask(FROM_HERE,
122 test_case_done_callback_);
123 test_case_done_callback_.Reset();
127 protected:
128 std::string VeryLongString() {
129 std::string result = "0123456789";
130 for (int i = 0; i < 8; i++)
131 result = result.append(result);
132 return result;
135 void RunTest(const std::vector<TestCase>& test_cases) {
136 ASSERT_FALSE(output_watch_thread_started_);
137 output_watch_thread_.reset(new base::Thread("ProcessOutpuWatchThread"));
138 output_watch_thread_started_ = output_watch_thread_->StartWithOptions(
139 base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
140 ASSERT_TRUE(output_watch_thread_started_);
142 int pt_pipe[2];
143 ASSERT_FALSE(HANDLE_EINTR(pipe(pt_pipe)));
145 scoped_ptr<ProcessOutputWatcher> crosh_watcher(new ProcessOutputWatcher(
146 pt_pipe[0],
147 base::Bind(&ProcessOutputWatcherTest::OnRead, base::Unretained(this))));
149 output_watch_thread_->task_runner()->PostTask(
150 FROM_HERE, base::Bind(&ProcessOutputWatcher::Start,
151 base::Unretained(crosh_watcher.get())));
153 for (size_t i = 0; i < test_cases.size(); i++) {
154 expectations_.SetTestCase(test_cases[i]);
156 base::RunLoop run_loop;
157 ASSERT_TRUE(test_case_done_callback_.is_null());
158 test_case_done_callback_ = run_loop.QuitClosure();
160 const std::string& test_str = test_cases[i].input;
161 // Let's make inputs not NULL terminated, unless other is specified in
162 // the test case.
163 ssize_t test_size = test_str.length() * sizeof(*test_str.c_str());
164 if (test_cases[i].should_send_terminating_null)
165 test_size += sizeof(*test_str.c_str());
166 EXPECT_TRUE(base::WriteFileDescriptor(pt_pipe[1], test_str.c_str(),
167 test_size));
169 run_loop.Run();
170 EXPECT_TRUE(expectations_.IsDone());
171 if (failed_)
172 break;
175 output_watch_thread_->task_runner()->PostTask(
176 FROM_HERE,
177 base::Bind(&StopProcessOutputWatcher, base::Passed(&crosh_watcher)));
179 EXPECT_NE(-1, IGNORE_EINTR(close(pt_pipe[1])));
182 private:
183 base::Closure test_case_done_callback_;
184 base::MessageLoop message_loop_;
185 scoped_ptr<base::Thread> output_watch_thread_;
186 bool output_watch_thread_started_;
187 bool failed_;
188 ProcessWatcherExpectations expectations_;
189 std::vector<TestCase> exp;
192 TEST_F(ProcessOutputWatcherTest, OutputWatcher) {
193 std::vector<TestCase> test_cases;
194 test_cases.push_back(TestCase("t", false));
195 test_cases.push_back(TestCase("testing output\n", false));
196 test_cases.push_back(TestCase("testing error\n", false));
197 test_cases.push_back(TestCase("testing error1\n", false));
198 test_cases.push_back(TestCase("testing output1\n", false));
199 test_cases.push_back(TestCase("testing output2\n", false));
200 test_cases.push_back(TestCase("testing output3\n", false));
201 test_cases.push_back(TestCase(VeryLongString(), false));
202 test_cases.push_back(TestCase("testing error2\n", false));
204 RunTest(test_cases);
207 TEST_F(ProcessOutputWatcherTest, SplitUTF8Character) {
208 std::vector<TestCase> test_cases;
209 test_cases.push_back(TestCase("test1\xc2", false, "test1"));
210 test_cases.push_back(TestCase("\xb5test1", false, "\xc2\xb5test1"));
212 RunTest(test_cases);
215 TEST_F(ProcessOutputWatcherTest, SplitSoleUTF8Character) {
216 std::vector<TestCase> test_cases;
217 test_cases.push_back(TestCase("\xc2", false, ""));
218 test_cases.push_back(TestCase("\xb5", false, "\xc2\xb5"));
220 RunTest(test_cases);
223 TEST_F(ProcessOutputWatcherTest, SplitUTF8CharacterLength3) {
224 std::vector<TestCase> test_cases;
225 test_cases.push_back(TestCase("test3\xe2\x82", false, "test3"));
226 test_cases.push_back(TestCase("\xac", false, "\xe2\x82\xac"));
228 RunTest(test_cases);
231 TEST_F(ProcessOutputWatcherTest, SplitSoleUTF8CharacterThreeWays) {
232 std::vector<TestCase> test_cases;
233 test_cases.push_back(TestCase("\xe2", false, ""));
234 test_cases.push_back(TestCase("\x82", false, ""));
235 test_cases.push_back(TestCase("\xac", false, "\xe2\x82\xac"));
237 RunTest(test_cases);
240 TEST_F(ProcessOutputWatcherTest, EndsWithThreeByteUTF8Character) {
241 std::vector<TestCase> test_cases;
242 test_cases.push_back(TestCase("test\xe2\x82\xac", false, "test\xe2\x82\xac"));
244 RunTest(test_cases);
247 TEST_F(ProcessOutputWatcherTest, SoleThreeByteUTF8Character) {
248 std::vector<TestCase> test_cases;
249 test_cases.push_back(TestCase("\xe2\x82\xac", false, "\xe2\x82\xac"));
251 RunTest(test_cases);
254 TEST_F(ProcessOutputWatcherTest, HasThreeByteUTF8Character) {
255 std::vector<TestCase> test_cases;
256 test_cases.push_back(
257 TestCase("test\xe2\x82\xac_", false, "test\xe2\x82\xac_"));
259 RunTest(test_cases);
262 TEST_F(ProcessOutputWatcherTest, MulitByteUTF8CharNullTerminated) {
263 std::vector<TestCase> test_cases;
264 test_cases.push_back(TestCase("test\xe2\x82\xac", true, "test\xe2\x82\xac"));
266 RunTest(test_cases);
269 TEST_F(ProcessOutputWatcherTest, MultipleMultiByteUTF8Characters) {
270 std::vector<TestCase> test_cases;
271 test_cases.push_back(
272 TestCase("test\xe2\x82\xac\xc2", false, "test\xe2\x82\xac"));
273 test_cases.push_back(TestCase("\xb5", false, "\xc2\xb5"));
275 RunTest(test_cases);
278 TEST_F(ProcessOutputWatcherTest, ContainsInvalidUTF8) {
279 std::vector<TestCase> test_cases;
280 test_cases.push_back(TestCase("\xc2_", false, "\xc2_"));
282 RunTest(test_cases);
285 TEST_F(ProcessOutputWatcherTest, InvalidUTF8SeriesOfTrailingBytes) {
286 std::vector<TestCase> test_cases;
287 test_cases.push_back(TestCase("\x82\x82\x82", false, "\x82\x82\x82"));
288 test_cases.push_back(TestCase("\x82\x82\x82", false, "\x82\x82\x82"));
290 RunTest(test_cases);
293 TEST_F(ProcessOutputWatcherTest, EndsWithInvalidUTF8) {
294 std::vector<TestCase> test_cases;
295 test_cases.push_back(TestCase("\xff", false, "\xff"));
297 RunTest(test_cases);
300 TEST_F(ProcessOutputWatcherTest, FourByteUTF8) {
301 std::vector<TestCase> test_cases;
302 test_cases.push_back(TestCase("\xf0\xa4\xad", false, ""));
303 test_cases.push_back(TestCase("\xa2", false, "\xf0\xa4\xad\xa2"));
305 RunTest(test_cases);
308 // Verifies that sending '\0' generates PROCESS_OUTPUT_TYPE_OUT event and does
309 // not terminate output watcher.
310 TEST_F(ProcessOutputWatcherTest, SendNull) {
311 std::vector<TestCase> test_cases;
312 // This will send '\0' to output watcher.
313 test_cases.push_back(TestCase("", true));
314 // Let's verify that next input also gets detected (i.e. output watcher does
315 // not exit after seeing '\0' from previous test case).
316 test_cases.push_back(TestCase("a", true));
318 RunTest(test_cases);
321 } // namespace chromeos