blob: ff4d5b9ad99a8b12a9ed8d86ec966b110f5b5287 [file] [log] [blame]
dschuyler613a1032016-12-15 19:22:351// Copyright 2016 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 <utility>
6
dschuyler613a1032016-12-15 19:22:357#include "net/base/io_buffer.h"
8#include "net/base/test_completion_callback.h"
9#include "net/filter/mock_source_stream.h"
10#include "testing/gtest/include/gtest/gtest.h"
Reilly Grantf31ae652017-11-16 20:40:0411#include "ui/base/webui/i18n_source_stream.h"
dschuyler613a1032016-12-15 19:22:3512
Reilly Grantf31ae652017-11-16 20:40:0413namespace ui {
dschuyler613a1032016-12-15 19:22:3514
15namespace {
16
dschuyleread12ef2017-01-10 02:36:1317// This constant is rather arbitrary, though the offsets and other sizes must
dschuyler613a1032016-12-15 19:22:3518// be less than kBufferSize.
19const int kBufferSize = 256;
dschuyler613a1032016-12-15 19:22:3520
dschuyleread12ef2017-01-10 02:36:1321const int kMinimumSize = 1;
22const int kSmallSize = 5; // Arbitrary small value > 1.
23const int kInOneReadSize = INT_MAX;
dschuyler613a1032016-12-15 19:22:3524
dschuyleread12ef2017-01-10 02:36:1325struct I18nTest {
26 constexpr I18nTest(const char* input, const char* expected_output)
27 : input(input), expected_output(expected_output) {}
dschuyler613a1032016-12-15 19:22:3528
dschuyleread12ef2017-01-10 02:36:1329 const char* input;
30 const char* expected_output;
31};
32
33constexpr I18nTest kTestEmpty = I18nTest("", "");
34
35constexpr I18nTest kTestNoReplacements =
36 I18nTest("This text has no i18n replacements.",
37 "This text has no i18n replacements.");
38
39constexpr I18nTest kTestTagAtEndOfLine =
40 I18nTest("test with tag at end of line $",
41 "test with tag at end of line $");
42
43constexpr I18nTest kTestOneReplacement = I18nTest("$i18n{alpha}", "apple");
44
45constexpr I18nTest kTestOneReplacementPlus =
46 I18nTest("Extra text $i18n{alpha}.", "Extra text apple.");
47
48constexpr I18nTest kTestThreeReplacements =
49 I18nTest("$i18n{alpha}^$i18n{beta}_$i18n{gamma}", "apple^banana_carrot");
50
51constexpr I18nTest kTestExtraBraces =
52 I18nTest("($i18n{alpha})^_^_^_^_$i18n{beta}_beta_$i18n{gamma}}}}}}",
53 "(apple)^_^_^_^_banana_beta_carrot}}}}}");
54
55// These tests with generic names are sequences that might catch an error in the
56// future, depending on how the code changes.
57constexpr I18nTest kTest1 =
58 I18nTest(" } $($i18n{gamma})^_^_^_^_$i18n{alpha}_$i18n{gamma}$",
59 " } $(carrot)^_^_^_^_apple_carrot$");
60
61constexpr I18nTest kTest2 =
62 I18nTest("$i18n{alpha} gamma}{ ^_^_^_^_$abc{beta}:$i18n{gamma}z",
63 "apple gamma}{ ^_^_^_^_$abc{beta}:carrotz");
dschuyler613a1032016-12-15 19:22:3564
65struct I18nTestParam {
dschuyleread12ef2017-01-10 02:36:1366 constexpr I18nTestParam(
67 const I18nTest* test,
68 int buf_size,
69 int read_size,
70 net::MockSourceStream::Mode read_mode = net::MockSourceStream::SYNC)
71 : buffer_size(buf_size),
72 read_size(read_size),
73 mode(read_mode),
74 test(test) {}
dschuyler613a1032016-12-15 19:22:3575
76 const int buffer_size;
dschuyleread12ef2017-01-10 02:36:1377 const int read_size;
dschuyler613a1032016-12-15 19:22:3578 const net::MockSourceStream::Mode mode;
dschuyleread12ef2017-01-10 02:36:1379 const I18nTest* test;
dschuyler613a1032016-12-15 19:22:3580};
81
82} // namespace
83
84class I18nSourceStreamTest : public ::testing::TestWithParam<I18nTestParam> {
85 protected:
86 I18nSourceStreamTest() : output_buffer_size_(GetParam().buffer_size) {}
87
88 // Helpful function to initialize the test fixture.
89 void Init() {
Victor Costandab6b732018-09-05 23:04:3690 output_buffer_ = base::MakeRefCounted<net::IOBuffer>(output_buffer_size_);
dschuyler613a1032016-12-15 19:22:3591 std::unique_ptr<net::MockSourceStream> source(new net::MockSourceStream());
92 source_ = source.get();
93
dschuyleread12ef2017-01-10 02:36:1394 replacements_["alpha"] = "apple";
95 replacements_["beta"] = "banana";
96 replacements_["gamma"] = "carrot";
dschuyler613a1032016-12-15 19:22:3597 stream_ = I18nSourceStream::Create(
98 std::move(source), net::SourceStream::TYPE_NONE, &replacements_);
99 }
100
101 // If MockSourceStream::Mode is ASYNC, completes 1 read from |mock_stream| and
102 // wait for |callback| to complete. If Mode is not ASYNC, does nothing and
103 // returns |previous_result|.
104 int CompleteReadIfAsync(int previous_result,
105 net::TestCompletionCallback* callback,
106 net::MockSourceStream* mock_stream) {
107 if (GetParam().mode == net::MockSourceStream::ASYNC) {
108 EXPECT_EQ(net::ERR_IO_PENDING, previous_result);
109 mock_stream->CompleteNextRead();
110 return callback->WaitForResult();
111 }
112 return previous_result;
113 }
114
dschuyler613a1032016-12-15 19:22:35115 net::IOBuffer* output_buffer() { return output_buffer_.get(); }
116 char* output_data() { return output_buffer_->data(); }
117 size_t output_buffer_size() { return output_buffer_size_; }
118
119 net::MockSourceStream* source() { return source_; }
120 I18nSourceStream* stream() { return stream_.get(); }
121
dschuyleread12ef2017-01-10 02:36:13122 void PushReadResults(const char* input, size_t chunk_size) {
123 size_t written = 0;
124 size_t source_size = strlen(GetParam().test->input);
125 while (written != source_size) {
126 size_t write_size = std::min(chunk_size, source_size - written);
127 source()->AddReadResult(input + written, write_size, net::OK,
128 GetParam().mode);
129 written += write_size;
130 }
131 source()->AddReadResult(nullptr, 0, net::OK, GetParam().mode);
132 }
133
dschuyler613a1032016-12-15 19:22:35134 // Reads from |stream_| until an error occurs or the EOF is reached.
135 // When an error occurs, returns the net error code. When an EOF is reached,
136 // returns the number of bytes read and appends data read to |output|.
137 int ReadStream(std::string* output) {
138 int bytes_read = 0;
139 while (true) {
140 net::TestCompletionCallback callback;
141 int rv = stream_->Read(output_buffer(), output_buffer_size(),
142 callback.callback());
143 if (rv == net::ERR_IO_PENDING)
144 rv = CompleteReadIfAsync(rv, &callback, source());
145 if (rv == net::OK)
146 break;
147 if (rv < net::OK)
148 return rv;
149 EXPECT_GT(rv, net::OK);
150 bytes_read += rv;
151 output->append(output_data(), rv);
152 }
153 return bytes_read;
154 }
155
156 private:
dschuyler613a1032016-12-15 19:22:35157 scoped_refptr<net::IOBuffer> output_buffer_;
158 const int output_buffer_size_;
159
160 net::MockSourceStream* source_;
161 std::unique_ptr<I18nSourceStream> stream_;
162
Reilly Grantf31ae652017-11-16 20:40:04163 TemplateReplacements replacements_;
dschuyler613a1032016-12-15 19:22:35164};
165
Victor Costanbe7d15f2019-01-27 03:19:40166INSTANTIATE_TEST_SUITE_P(
dschuyler613a1032016-12-15 19:22:35167 I18nSourceStreamTests,
168 I18nSourceStreamTest,
dschuyleread12ef2017-01-10 02:36:13169 ::testing::Values(
170 I18nTestParam(&kTest1, kBufferSize, kInOneReadSize),
171 I18nTestParam(&kTest1, kBufferSize, kSmallSize),
172 I18nTestParam(&kTest1, kMinimumSize, kMinimumSize),
173 I18nTestParam(&kTest1, kMinimumSize, kSmallSize),
dschuyler613a1032016-12-15 19:22:35174
dschuyleread12ef2017-01-10 02:36:13175 I18nTestParam(&kTest2, kBufferSize, kInOneReadSize),
176 I18nTestParam(&kTest2, kBufferSize, kSmallSize),
177 I18nTestParam(&kTest2, kMinimumSize, kMinimumSize),
178 I18nTestParam(&kTest2, kMinimumSize, kSmallSize),
dschuyler613a1032016-12-15 19:22:35179
dschuyleread12ef2017-01-10 02:36:13180 I18nTestParam(&kTestEmpty, kBufferSize, kInOneReadSize),
181 I18nTestParam(&kTestEmpty, kBufferSize, kSmallSize),
182 I18nTestParam(&kTestEmpty, kMinimumSize, kMinimumSize),
183 I18nTestParam(&kTestEmpty, kMinimumSize, kSmallSize),
184
185 I18nTestParam(&kTestExtraBraces, kBufferSize, kInOneReadSize),
186 I18nTestParam(&kTestExtraBraces, kBufferSize, kSmallSize),
187 I18nTestParam(&kTestExtraBraces, kMinimumSize, kMinimumSize),
188 I18nTestParam(&kTestExtraBraces, kMinimumSize, kSmallSize),
189
190 I18nTestParam(&kTestNoReplacements, kBufferSize, kInOneReadSize),
191 I18nTestParam(&kTestNoReplacements, kBufferSize, kSmallSize),
192 I18nTestParam(&kTestNoReplacements, kMinimumSize, kMinimumSize),
193 I18nTestParam(&kTestNoReplacements, kMinimumSize, kSmallSize),
194
195 I18nTestParam(&kTestOneReplacement, kBufferSize, kInOneReadSize),
196 I18nTestParam(&kTestOneReplacement, kBufferSize, kSmallSize),
197 I18nTestParam(&kTestOneReplacement, kMinimumSize, kMinimumSize),
198 I18nTestParam(&kTestOneReplacement, kMinimumSize, kSmallSize),
199
200 I18nTestParam(&kTestOneReplacementPlus, kBufferSize, kInOneReadSize),
201 I18nTestParam(&kTestOneReplacementPlus, kBufferSize, kSmallSize),
202 I18nTestParam(&kTestOneReplacementPlus, kMinimumSize, kMinimumSize),
203 I18nTestParam(&kTestOneReplacementPlus, kMinimumSize, kSmallSize),
204
205 I18nTestParam(&kTestTagAtEndOfLine, kBufferSize, kInOneReadSize),
206 I18nTestParam(&kTestTagAtEndOfLine, kBufferSize, kSmallSize),
207 I18nTestParam(&kTestTagAtEndOfLine, kMinimumSize, kMinimumSize),
208 I18nTestParam(&kTestTagAtEndOfLine, kMinimumSize, kSmallSize),
209
210 I18nTestParam(&kTestThreeReplacements, kBufferSize, kInOneReadSize),
211 I18nTestParam(&kTestThreeReplacements, kBufferSize, kSmallSize),
212 I18nTestParam(&kTestThreeReplacements, kMinimumSize, kMinimumSize),
213 I18nTestParam(&kTestThreeReplacements, kMinimumSize, kSmallSize)));
214
215TEST_P(I18nSourceStreamTest, FilterTests) {
dschuyler613a1032016-12-15 19:22:35216 Init();
dschuyleread12ef2017-01-10 02:36:13217 // Create the chain of read buffers.
218 PushReadResults(GetParam().test->input, GetParam().read_size);
219
220 // Process the buffers.
dschuyler613a1032016-12-15 19:22:35221 std::string actual_output;
222 int rv = ReadStream(&actual_output);
dschuyleread12ef2017-01-10 02:36:13223
224 // Check the results.
225 std::string expected_output(GetParam().test->expected_output);
226 EXPECT_EQ(expected_output.size(), static_cast<size_t>(rv));
227 EXPECT_EQ(expected_output, actual_output);
dschuyler613a1032016-12-15 19:22:35228 EXPECT_EQ("i18n", stream()->Description());
229}
230
dschuyleread12ef2017-01-10 02:36:13231TEST_P(I18nSourceStreamTest, LargeFilterTests) {
dschuyler613a1032016-12-15 19:22:35232 Init();
dschuyleread12ef2017-01-10 02:36:13233 std::string padding;
234 // 251 and 599 are prime and avoid power-of-two repetition.
235 int padding_modulus = 251;
236 int pad_size = 599;
237 padding.resize(pad_size);
238 for (int i = 0; i < pad_size; ++i)
239 padding[i] = i % padding_modulus;
dschuyler613a1032016-12-15 19:22:35240
dschuyleread12ef2017-01-10 02:36:13241 // Create the chain of read buffers.
242 const int kPadCount = 128; // Arbitrary number of pads to add.
243 for (int i = 0; i < kPadCount; ++i) {
244 source()->AddReadResult(padding.c_str(), padding.size(), net::OK,
dschuyler613a1032016-12-15 19:22:35245 GetParam().mode);
dschuyler613a1032016-12-15 19:22:35246 }
dschuyleread12ef2017-01-10 02:36:13247 PushReadResults(GetParam().test->input, GetParam().read_size);
dschuyler613a1032016-12-15 19:22:35248
dschuyleread12ef2017-01-10 02:36:13249 // Process the buffers.
dschuyler3ba7a97b2017-01-03 23:11:42250 std::string actual_output;
251 int rv = ReadStream(&actual_output);
dschuyleread12ef2017-01-10 02:36:13252
253 // Check the results.
254 size_t total_padding = kPadCount * padding.size();
255 std::string expected_output(GetParam().test->expected_output);
256 ASSERT_EQ(expected_output.size() + total_padding, static_cast<size_t>(rv));
257 for (int i = 0; i < kPadCount; ++i) {
258 EXPECT_EQ(actual_output.substr(i * padding.size(), padding.size()),
259 padding);
260 }
261 EXPECT_EQ(expected_output, &actual_output[total_padding]);
dschuyler3ba7a97b2017-01-03 23:11:42262 EXPECT_EQ("i18n", stream()->Description());
263}
264
Reilly Grantf31ae652017-11-16 20:40:04265} // namespace ui