Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / platform / text / BidiResolverTest.cpp
blob51abdaa23ba539791e9f65c388015c9651691f47
1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "config.h"
32 #include "platform/text/BidiResolver.h"
34 #include "platform/text/BidiTestHarness.h"
35 #include "platform/text/TextRunIterator.h"
36 #include "wtf/OwnPtr.h"
37 #include <fstream>
38 #include <gtest/gtest.h>
40 namespace blink {
42 TEST(BidiResolver, Basic)
44 bool hasStrongDirectionality;
45 String value("foo");
46 TextRun run(value);
47 BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
48 bidiResolver.setStatus(BidiStatus(run.direction(), run.directionalOverride()));
49 bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&run, 0));
50 TextDirection direction = bidiResolver.determineParagraphDirectionality(&hasStrongDirectionality);
51 EXPECT_TRUE(hasStrongDirectionality);
52 EXPECT_EQ(LTR, direction);
55 TextDirection determineParagraphDirectionality(const TextRun& textRun, bool* hasStrongDirectionality = 0)
57 BidiResolver<TextRunIterator, BidiCharacterRun> resolver;
58 resolver.setStatus(BidiStatus(LTR, false));
59 resolver.setPositionIgnoringNestedIsolates(TextRunIterator(&textRun, 0));
60 return resolver.determineParagraphDirectionality(hasStrongDirectionality);
63 struct TestData {
64 UChar text[3];
65 size_t length;
66 TextDirection expectedDirection;
67 bool expectedStrong;
70 void testDirectionality(const TestData& entry)
72 bool hasStrongDirectionality;
73 String data(entry.text, entry.length);
74 TextRun run(data);
75 TextDirection direction = determineParagraphDirectionality(run, &hasStrongDirectionality);
76 EXPECT_EQ(entry.expectedStrong, hasStrongDirectionality);
77 EXPECT_EQ(entry.expectedDirection, direction);
80 TEST(BidiResolver, ParagraphDirectionSurrogates)
82 const TestData testData[] = {
83 // Test strong RTL, non-BMP. (U+10858 Imperial Aramaic number one, strong RTL)
84 { { 0xD802, 0xDC58 }, 2, RTL, true },
86 // Test strong LTR, non-BMP. (U+1D15F Musical symbol quarter note, strong LTR)
87 { { 0xD834, 0xDD5F }, 2, LTR, true },
89 // Test broken surrogate: valid leading, invalid trail. (Lead of U+10858, space)
90 { { 0xD802, ' ' }, 2, LTR, false },
92 // Test broken surrogate: invalid leading. (Trail of U+10858, U+05D0 Hebrew Alef)
93 { { 0xDC58, 0x05D0 }, 2, RTL, true },
95 // Test broken surrogate: valid leading, invalid trail/valid lead, valid trail.
96 { { 0xD802, 0xD802, 0xDC58 }, 3, RTL, true },
98 // Test broken surrogate: valid leading, no trail (string too short). (Lead of U+10858)
99 { { 0xD802, 0xDC58 }, 1, LTR, false },
101 // Test broken surrogate: trail appearing before lead. (U+10858 units reversed)
102 { { 0xDC58, 0xD802 }, 2, LTR, false }
104 for (size_t i = 0; i < WTF_ARRAY_LENGTH(testData); ++i)
105 testDirectionality(testData[i]);
108 class BidiTestRunner {
109 public:
110 BidiTestRunner()
111 : m_testsRun(0)
112 , m_testsSkipped(0)
113 , m_ignoredCharFailures(0)
114 , m_levelFailures(0)
115 , m_orderFailures(0)
119 void skipTestsWith(UChar codepoint)
121 m_skippedCodePoints.insert(codepoint);
124 void runTest(const std::basic_string<UChar>& input, const std::vector<int>& reorder,
125 const std::vector<int>& levels, bidi_test::ParagraphDirection,
126 const std::string& line, size_t lineNumber);
128 size_t m_testsRun;
129 size_t m_testsSkipped;
130 std::set<UChar> m_skippedCodePoints;
131 size_t m_ignoredCharFailures;
132 size_t m_levelFailures;
133 size_t m_orderFailures;
136 // Blink's UBA does not filter out control characters, etc. Maybe it should?
137 // Instead it depends on later layers of Blink to simply ignore them.
138 // This function helps us emulate that to be compatible with BidiTest.txt expectations.
139 static bool isNonRenderedCodePoint(UChar c)
141 // The tests also expect us to ignore soft-hyphen.
142 if (c == 0xAD)
143 return true;
144 // Control characters are not rendered:
145 return c >= 0x202A && c <= 0x202E;
146 // But it seems to expect LRI, etc. to be rendered!?
149 std::string diffString(const std::vector<int>& actual, const std::vector<int>& expected)
151 std::ostringstream diff;
152 diff << "actual: ";
153 // This is the magical way to print a vector to a stream, clear, right?
154 std::copy(actual.begin(), actual.end(), std::ostream_iterator<int>(diff, " "));
155 diff << " expected: ";
156 std::copy(expected.begin(), expected.end(), std::ostream_iterator<int>(diff, " "));
157 return diff.str();
160 void BidiTestRunner::runTest(const std::basic_string<UChar>& input, const std::vector<int>& expectedOrder,
161 const std::vector<int>& expectedLevels, bidi_test::ParagraphDirection paragraphDirection,
162 const std::string& line, size_t lineNumber)
164 if (!m_skippedCodePoints.empty()) {
165 for (size_t i = 0; i < input.size(); i++) {
166 if (m_skippedCodePoints.count(input[i])) {
167 m_testsSkipped++;
168 return;
173 m_testsRun++;
175 TextRun textRun(input.data(), input.size());
176 switch (paragraphDirection) {
177 case bidi_test::DirectionAutoLTR:
178 textRun.setDirection(determineParagraphDirectionality(textRun));
179 break;
180 case bidi_test::DirectionLTR:
181 textRun.setDirection(LTR);
182 break;
183 case bidi_test::DirectionRTL:
184 textRun.setDirection(RTL);
185 break;
187 BidiResolver<TextRunIterator, BidiCharacterRun> resolver;
188 resolver.setStatus(BidiStatus(textRun.direction(), textRun.directionalOverride()));
189 resolver.setPositionIgnoringNestedIsolates(TextRunIterator(&textRun, 0));
191 BidiRunList<BidiCharacterRun>& runs = resolver.runs();
192 resolver.createBidiRunsForLine(TextRunIterator(&textRun, textRun.length()));
194 std::ostringstream errorContext;
195 errorContext << ", line " << lineNumber << " \"" << line << "\"";
196 errorContext << " context: " << bidi_test::nameFromParagraphDirection(paragraphDirection);
198 std::vector<int> actualOrder;
199 std::vector<int> actualLevels;
200 actualLevels.assign(input.size(), -1);
201 BidiCharacterRun* run = runs.firstRun();
202 while (run) {
203 // Blink's UBA just makes runs, the actual ordering of the display of characters
204 // is handled later in our pipeline, so we fake it here:
205 bool reversed = run->reversed(false);
206 ASSERT(run->stop() >= run->start());
207 size_t length = run->stop() - run->start();
208 for (size_t i = 0; i < length; i++) {
209 int inputIndex = reversed ? run->stop() - i - 1 : run->start() + i;
210 if (!isNonRenderedCodePoint(input[inputIndex]))
211 actualOrder.push_back(inputIndex);
212 // BidiTest.txt gives expected level data in the order of the original input.
213 actualLevels[inputIndex] = run->level();
215 run = run->next();
218 if (expectedOrder.size() != actualOrder.size()) {
219 m_ignoredCharFailures++;
220 EXPECT_EQ(expectedOrder.size(), actualOrder.size()) << errorContext.str();
221 } else if (expectedOrder != actualOrder) {
222 m_orderFailures++;
223 printf("ORDER %s%s\n", diffString(actualOrder, expectedOrder).c_str(), errorContext.str().c_str());
226 if (expectedLevels.size() != actualLevels.size()) {
227 m_ignoredCharFailures++;
228 EXPECT_EQ(expectedLevels.size(), actualLevels.size()) << errorContext.str();
229 } else {
230 for (size_t i = 0; i < expectedLevels.size(); i++) {
231 // level == -1 means the level should be ignored.
232 if (expectedLevels[i] == actualLevels[i] || expectedLevels[i] == -1)
233 continue;
235 printf("LEVELS %s%s\n", diffString(actualLevels, expectedLevels).c_str(), errorContext.str().c_str());
236 m_levelFailures++;
237 break;
240 runs.deleteRuns();
244 TEST(BidiResolver, BidiTest_txt)
246 BidiTestRunner runner;
247 // Blink's Unicode Bidi Algorithm (UBA) doesn't yet support the
248 // new isolate directives from Unicode 6.3:
249 // http://www.unicode.org/reports/tr9/#Explicit_Directional_Isolates
250 runner.skipTestsWith(0x2066); // LRI
251 runner.skipTestsWith(0x2067); // RLI
252 runner.skipTestsWith(0x2068); // FSI
253 runner.skipTestsWith(0x2069); // PDI
255 // This code wants to use PathService from base/path_service.h
256 // but we aren't allowed to depend on base/ directly from Blink yet.
257 // Alternatively we could use:
258 // blink::Platform::current()->unitTestSupport()->webKitRootDir()
259 // and a relative path, but that would require running inside
260 // webkit_unit_tests (to have a functioning Platform object).
261 // The file we want is:
262 // src/third_party/icu/source/test/testdata/BidiTest.txt
263 // but we don't have any good way to find it from this unittest.
264 // Just assume we're running this test manually for now. On the
265 // bots we just print a warning that we can't find the test file.
266 std::string bidiTestPath = "BidiTest.txt";
267 std::ifstream bidiTestFile(bidiTestPath.c_str());
268 if (!bidiTestFile.is_open()) {
269 printf("ERROR: Failed to open BidiTest.txt, cannot run tests.\n");
270 return;
273 bidi_test::Harness<BidiTestRunner> harness(runner);
274 harness.parse(bidiTestFile);
275 bidiTestFile.close();
277 if (runner.m_testsSkipped)
278 printf("WARNING: Skipped %zu tests.\n", runner.m_testsSkipped);
279 printf("Ran %zu tests: %zu level failures %zu order failures.\n",
280 runner.m_testsRun, runner.m_levelFailures, runner.m_orderFailures);
282 // The unittest harness only pays attention to GTest output, so we verify
283 // that the tests behaved as expected:
284 EXPECT_EQ(352098u, runner.m_testsRun);
285 EXPECT_EQ(418143u, runner.m_testsSkipped);
286 EXPECT_EQ(0u, runner.m_ignoredCharFailures);
287 EXPECT_EQ(44882u, runner.m_levelFailures);
288 EXPECT_EQ(19151u, runner.m_orderFailures);
291 } // namespace blink