webkitpy: update unit tests in preparation for making host a mandatory parameter...
[WebKit-https.git] / Tools / Scripts / webkitpy / layout_tests / models / test_expectations_unittest.py
1 #!/usr/bin/python
2 # Copyright (C) 2010 Google Inc. All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met:
7 #
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.
17 #
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.
29
30 import unittest
31
32 from webkitpy.common.host_mock import MockHost
33
34 from webkitpy.layout_tests.models.test_configuration import *
35 from webkitpy.layout_tests.models.test_expectations import *
36 from webkitpy.layout_tests.models.test_configuration import *
37
38
39 class MockBugManager(object):
40     def close_bug(self, bug_id, reference_bug_id=None):
41         pass
42
43     def create_bug(self):
44         return "BUG_NEWLY_CREATED"
45
46
47 class FunctionsTest(unittest.TestCase):
48     def test_result_was_expected(self):
49         # test basics
50         self.assertEquals(result_was_expected(PASS, set([PASS]),
51                                               False, False), True)
52         self.assertEquals(result_was_expected(TEXT, set([PASS]),
53                                               False, False), False)
54
55         # test handling of FAIL expectations
56         self.assertEquals(result_was_expected(IMAGE_PLUS_TEXT, set([FAIL]),
57                                               False, False), True)
58         self.assertEquals(result_was_expected(IMAGE, set([FAIL]),
59                                               False, False), True)
60         self.assertEquals(result_was_expected(TEXT, set([FAIL]),
61                                               False, False), True)
62         self.assertEquals(result_was_expected(CRASH, set([FAIL]),
63                                               False, False), False)
64
65         # test handling of SKIPped tests and results
66         self.assertEquals(result_was_expected(SKIP, set([CRASH]),
67                                               False, True), True)
68         self.assertEquals(result_was_expected(SKIP, set([CRASH]),
69                                               False, False), False)
70
71         # test handling of MISSING results and the REBASELINE modifier
72         self.assertEquals(result_was_expected(MISSING, set([PASS]),
73                                               True, False), True)
74         self.assertEquals(result_was_expected(MISSING, set([PASS]),
75                                               False, False), False)
76
77     def test_remove_pixel_failures(self):
78         self.assertEquals(remove_pixel_failures(set([TEXT])),
79                           set([TEXT]))
80         self.assertEquals(remove_pixel_failures(set([PASS])),
81                           set([PASS]))
82         self.assertEquals(remove_pixel_failures(set([IMAGE])),
83                           set([PASS]))
84         self.assertEquals(remove_pixel_failures(set([IMAGE_PLUS_TEXT])),
85                           set([TEXT]))
86         self.assertEquals(remove_pixel_failures(set([PASS, IMAGE, CRASH])),
87                           set([PASS, CRASH]))
88
89
90 class Base(unittest.TestCase):
91     # Note that all of these tests are written assuming the configuration
92     # being tested is Windows XP, Release build.
93
94     def __init__(self, testFunc, setUp=None, tearDown=None, description=None):
95         host = MockHost()
96         self._port = host.port_factory.get('test-win-xp', None)
97         self._fs = host.filesystem
98         self._exp = None
99         unittest.TestCase.__init__(self, testFunc)
100
101     def get_test(self, test_name):
102         # FIXME: Remove this routine and just reference test names directly.
103         return test_name
104
105     def get_basic_tests(self):
106         return [self.get_test('failures/expected/text.html'),
107                 self.get_test('failures/expected/image_checksum.html'),
108                 self.get_test('failures/expected/crash.html'),
109                 self.get_test('failures/expected/missing_text.html'),
110                 self.get_test('failures/expected/image.html'),
111                 self.get_test('passes/text.html')]
112
113     def get_basic_expectations(self):
114         return """
115 BUG_TEST : failures/expected/text.html = TEXT
116 BUG_TEST WONTFIX SKIP : failures/expected/crash.html = CRASH
117 BUG_TEST REBASELINE : failures/expected/missing_image.html = MISSING
118 BUG_TEST WONTFIX : failures/expected/image_checksum.html = IMAGE
119 BUG_TEST WONTFIX MAC : failures/expected/image.html = IMAGE
120 """
121
122     def parse_exp(self, expectations, overrides=None, is_lint_mode=False):
123         test_config = self._port.test_configuration()
124         self._exp = TestExpectations(self._port,
125              tests=self.get_basic_tests(),
126              expectations=expectations,
127              test_config=test_config,
128              is_lint_mode=is_lint_mode,
129              overrides=overrides)
130
131     def assert_exp(self, test, result):
132         self.assertEquals(self._exp.get_expectations(self.get_test(test)),
133                           set([result]))
134
135
136 class BasicTests(Base):
137     def test_basic(self):
138         self.parse_exp(self.get_basic_expectations())
139         self.assert_exp('failures/expected/text.html', TEXT)
140         self.assert_exp('failures/expected/image_checksum.html', IMAGE)
141         self.assert_exp('passes/text.html', PASS)
142         self.assert_exp('failures/expected/image.html', PASS)
143
144
145 class MiscTests(Base):
146     def test_multiple_results(self):
147         self.parse_exp('BUGX : failures/expected/text.html = TEXT CRASH')
148         self.assertEqual(self._exp.get_expectations(
149             self.get_test('failures/expected/text.html')),
150             set([TEXT, CRASH]))
151
152     def test_category_expectations(self):
153         # This test checks unknown tests are not present in the
154         # expectations and that known test part of a test category is
155         # present in the expectations.
156         exp_str = """
157 BUGX WONTFIX : failures/expected = IMAGE
158 """
159         self.parse_exp(exp_str)
160         test_name = 'failures/expected/unknown-test.html'
161         unknown_test = self.get_test(test_name)
162         self.assertRaises(KeyError, self._exp.get_expectations,
163                           unknown_test)
164         self.assert_exp('failures/expected/crash.html', IMAGE)
165
166     def test_get_modifiers(self):
167         self.parse_exp(self.get_basic_expectations())
168         self.assertEqual(self._exp.get_modifiers(
169                          self.get_test('passes/text.html')), [])
170
171     def test_get_expectations_string(self):
172         self.parse_exp(self.get_basic_expectations())
173         self.assertEquals(self._exp.get_expectations_string(
174                           self.get_test('failures/expected/text.html')),
175                           'TEXT')
176
177     def test_expectation_to_string(self):
178         # Normal cases are handled by other tests.
179         self.parse_exp(self.get_basic_expectations())
180         self.assertRaises(ValueError, self._exp.expectation_to_string,
181                           -1)
182
183     def test_get_test_set(self):
184         # Handle some corner cases for this routine not covered by other tests.
185         self.parse_exp(self.get_basic_expectations())
186         s = self._exp.get_test_set(WONTFIX)
187         self.assertEqual(s,
188             set([self.get_test('failures/expected/crash.html'),
189                  self.get_test('failures/expected/image_checksum.html')]))
190         s = self._exp.get_test_set(WONTFIX, CRASH)
191         self.assertEqual(s,
192             set([self.get_test('failures/expected/crash.html')]))
193         s = self._exp.get_test_set(WONTFIX, CRASH, include_skips=False)
194         self.assertEqual(s, set([]))
195
196     def test_parse_error_fatal(self):
197         try:
198             self.parse_exp("""FOO : failures/expected/text.html = TEXT
199 SKIP : failures/expected/image.html""")
200             self.assertFalse(True, "ParseError wasn't raised")
201         except ParseError, e:
202             self.assertTrue(e.fatal)
203             exp_errors = [u"FAILURES FOR %s in LayoutTests/platform/test/test_expectations.txt" % self._port.test_configuration(),
204                           u"Line:1 Unrecognized modifier 'foo' failures/expected/text.html",
205                           u"Line:2 Missing expectations SKIP : failures/expected/image.html"]
206             self.assertEqual(str(e), '\n'.join(map(str, exp_errors)))
207             self.assertEqual(e.errors, exp_errors)
208
209     def test_parse_error_nonfatal(self):
210         try:
211             self.parse_exp('SKIP : failures/expected/text.html = TEXT',
212                            is_lint_mode=True)
213             self.assertFalse(True, "ParseError wasn't raised")
214         except ParseError, e:
215             self.assertFalse(e.fatal)
216             exp_errors = [u'FAILURES FOR %s in LayoutTests/platform/test/test_expectations.txt' % self._port.test_configuration(),
217                           u'Line:1 Test lacks BUG modifier. failures/expected/text.html']
218             self.assertEqual(str(e), '\n'.join(map(str, exp_errors)))
219             self.assertEqual(e.errors, exp_errors)
220
221     def test_overrides(self):
222         self.parse_exp("BUG_EXP: failures/expected/text.html = TEXT",
223                        "BUG_OVERRIDE : failures/expected/text.html = IMAGE")
224         self.assert_exp('failures/expected/text.html', IMAGE)
225
226     def test_overrides__duplicate(self):
227         self.assertRaises(ParseError, self.parse_exp,
228              "BUG_EXP: failures/expected/text.html = TEXT",
229              """
230 BUG_OVERRIDE : failures/expected/text.html = IMAGE
231 BUG_OVERRIDE : failures/expected/text.html = CRASH
232 """)
233
234     def test_pixel_tests_flag(self):
235         def match(test, result, pixel_tests_enabled):
236             return self._exp.matches_an_expected_result(
237                 self.get_test(test), result, pixel_tests_enabled)
238
239         self.parse_exp(self.get_basic_expectations())
240         self.assertTrue(match('failures/expected/text.html', TEXT, True))
241         self.assertTrue(match('failures/expected/text.html', TEXT, False))
242         self.assertFalse(match('failures/expected/text.html', CRASH, True))
243         self.assertFalse(match('failures/expected/text.html', CRASH, False))
244         self.assertTrue(match('failures/expected/image_checksum.html', IMAGE,
245                               True))
246         self.assertTrue(match('failures/expected/image_checksum.html', PASS,
247                               False))
248         self.assertTrue(match('failures/expected/crash.html', SKIP, False))
249         self.assertTrue(match('passes/text.html', PASS, False))
250
251     def test_more_specific_override_resets_skip(self):
252         self.parse_exp("BUGX SKIP : failures/expected = TEXT\n"
253                        "BUGX : failures/expected/text.html = IMAGE\n")
254         self.assert_exp('failures/expected/text.html', IMAGE)
255         self.assertFalse(self._port._filesystem.join(self._port.layout_tests_dir(),
256                                                      'failures/expected/text.html') in
257                          self._exp.get_tests_with_result_type(SKIP))
258
259     def test_add_skipped_tests(self):
260         port = MockHost().port_factory.get('qt')
261         port._filesystem.files[port._filesystem.join(port.layout_tests_dir(), 'platform/qt/Skipped')] = 'failures/expected/text.html'
262         port._filesystem.files[port._filesystem.join(port.layout_tests_dir(), 'failures/expected/text.html')] = 'foo'
263         self.assertRaises(ParseError, TestExpectations, port, 'failures/expected/text.html\n', 'BUGX : failures/expected/text.html = text\n', None, True)
264
265
266 class ExpectationSyntaxTests(Base):
267     def test_missing_expectation(self):
268         # This is missing the expectation.
269         self.assertRaises(ParseError, self.parse_exp,
270                           'BUG_TEST: failures/expected/text.html')
271
272     def test_missing_colon(self):
273         # This is missing the modifiers and the ':'
274         self.assertRaises(ParseError, self.parse_exp,
275                           'failures/expected/text.html = TEXT')
276
277     def disabled_test_too_many_colons(self):
278         # FIXME: Enable this test and fix the underlying bug.
279         self.assertRaises(ParseError, self.parse_exp,
280                           'BUG_TEST: failures/expected/text.html = PASS :')
281
282     def test_too_many_equals_signs(self):
283         self.assertRaises(ParseError, self.parse_exp,
284                           'BUG_TEST: failures/expected/text.html = TEXT = IMAGE')
285
286     def test_unrecognized_expectation(self):
287         self.assertRaises(ParseError, self.parse_exp,
288                           'BUG_TEST: failures/expected/text.html = UNKNOWN')
289
290     def test_macro(self):
291         exp_str = """
292 BUG_TEST WIN : failures/expected/text.html = TEXT
293 """
294         self.parse_exp(exp_str)
295         self.assert_exp('failures/expected/text.html', TEXT)
296
297
298 class SemanticTests(Base):
299     def test_bug_format(self):
300         self.assertRaises(ParseError, self.parse_exp, 'BUG1234 : failures/expected/text.html = TEXT')
301
302     def test_missing_bugid(self):
303         # This should log a non-fatal error.
304         self.parse_exp('SLOW : failures/expected/text.html = TEXT')
305         self.assertTrue(self._exp.has_warnings())
306
307     def test_slow_and_timeout(self):
308         # A test cannot be SLOW and expected to TIMEOUT.
309         self.assertRaises(ParseError, self.parse_exp,
310             'BUG_TEST SLOW : failures/expected/timeout.html = TIMEOUT')
311
312     def test_rebaseline(self):
313         # Can't lint a file w/ 'REBASELINE' in it.
314         self.assertRaises(ParseError, self.parse_exp,
315             'BUG_TEST REBASELINE : failures/expected/text.html = TEXT',
316             is_lint_mode=True)
317
318     def test_duplicates(self):
319         self.assertRaises(ParseError, self.parse_exp, """
320 BUG_EXP : failures/expected/text.html = TEXT
321 BUG_EXP : failures/expected/text.html = IMAGE""")
322
323         self.assertRaises(ParseError, self.parse_exp,
324             self.get_basic_expectations(), overrides="""
325 BUG_OVERRIDE : failures/expected/text.html = TEXT
326 BUG_OVERRIDE : failures/expected/text.html = IMAGE""", )
327
328     def test_missing_file(self):
329         # This should log a non-fatal error.
330         self.parse_exp('BUG_TEST : missing_file.html = TEXT')
331         self.assertTrue(self._exp.has_warnings(), 1)
332
333
334 class PrecedenceTests(Base):
335     def test_file_over_directory(self):
336         # This tests handling precedence of specific lines over directories
337         # and tests expectations covering entire directories.
338         exp_str = """
339 BUGX : failures/expected/text.html = TEXT
340 BUGX WONTFIX : failures/expected = IMAGE
341 """
342         self.parse_exp(exp_str)
343         self.assert_exp('failures/expected/text.html', TEXT)
344         self.assert_exp('failures/expected/crash.html', IMAGE)
345
346         exp_str = """
347 BUGX WONTFIX : failures/expected = IMAGE
348 BUGX : failures/expected/text.html = TEXT
349 """
350         self.parse_exp(exp_str)
351         self.assert_exp('failures/expected/text.html', TEXT)
352         self.assert_exp('failures/expected/crash.html', IMAGE)
353
354     def test_ambiguous(self):
355         self.assertRaises(ParseError, self.parse_exp, """
356 BUG_TEST RELEASE : passes/text.html = PASS
357 BUG_TEST WIN : passes/text.html = FAIL
358 """)
359
360     def test_more_modifiers(self):
361         exp_str = """
362 BUG_TEST RELEASE : passes/text.html = PASS
363 BUG_TEST WIN RELEASE : passes/text.html = TEXT
364 """
365         self.assertRaises(ParseError, self.parse_exp, exp_str)
366
367     def test_order_in_file(self):
368         exp_str = """
369 BUG_TEST WIN RELEASE : passes/text.html = TEXT
370 BUG_TEST RELEASE : passes/text.html = PASS
371 """
372         self.assertRaises(ParseError, self.parse_exp, exp_str)
373
374     def test_macro_overrides(self):
375         exp_str = """
376 BUG_TEST WIN : passes/text.html = PASS
377 BUG_TEST XP : passes/text.html = TEXT
378 """
379         self.assertRaises(ParseError, self.parse_exp, exp_str)
380
381
382 class RebaseliningTest(Base):
383     """Test rebaselining-specific functionality."""
384     def assertRemove(self, input_expectations, tests, expected_expectations):
385         self.parse_exp(input_expectations)
386         actual_expectations = self._exp.remove_rebaselined_tests(tests)
387         self.assertEqual(expected_expectations, actual_expectations)
388
389     def test_remove(self):
390         self.assertRemove('BUGX REBASELINE : failures/expected/text.html = TEXT\n'
391                           'BUGY : failures/expected/image.html = IMAGE\n'
392                           'BUGZ REBASELINE : failures/expected/crash.html = CRASH\n',
393                           ['failures/expected/text.html'],
394                           'BUGY : failures/expected/image.html = IMAGE\n'
395                           'BUGZ REBASELINE : failures/expected/crash.html = CRASH\n')
396
397     def test_no_get_rebaselining_failures(self):
398         self.parse_exp(self.get_basic_expectations())
399         self.assertEqual(len(self._exp.get_rebaselining_failures()), 0)
400
401
402 class TestExpectationParserTests(unittest.TestCase):
403     def test_tokenize_blank(self):
404         expectation = TestExpectationParser.tokenize('')
405         self.assertEqual(expectation.is_malformed(), False)
406         self.assertEqual(expectation.comment, None)
407         self.assertEqual(len(expectation.errors), 0)
408
409     def test_tokenize_missing_colon(self):
410         expectation = TestExpectationParser.tokenize('Qux.')
411         self.assertEqual(expectation.is_malformed(), True)
412         self.assertEqual(str(expectation.errors), '["Missing a \':\'"]')
413
414     def test_tokenize_extra_colon(self):
415         expectation = TestExpectationParser.tokenize('FOO : : bar')
416         self.assertEqual(expectation.is_malformed(), True)
417         self.assertEqual(str(expectation.errors), '["Extraneous \':\'"]')
418
419     def test_tokenize_empty_comment(self):
420         expectation = TestExpectationParser.tokenize('//')
421         self.assertEqual(expectation.is_malformed(), False)
422         self.assertEqual(expectation.comment, '')
423         self.assertEqual(len(expectation.errors), 0)
424
425     def test_tokenize_comment(self):
426         expectation = TestExpectationParser.tokenize('//Qux.')
427         self.assertEqual(expectation.is_malformed(), False)
428         self.assertEqual(expectation.comment, 'Qux.')
429         self.assertEqual(len(expectation.errors), 0)
430
431     def test_tokenize_missing_equal(self):
432         expectation = TestExpectationParser.tokenize('FOO : bar')
433         self.assertEqual(expectation.is_malformed(), True)
434         self.assertEqual(str(expectation.errors), "['Missing expectations\']")
435
436     def test_tokenize_extra_equal(self):
437         expectation = TestExpectationParser.tokenize('FOO : bar = BAZ = Qux.')
438         self.assertEqual(expectation.is_malformed(), True)
439         self.assertEqual(str(expectation.errors), '["Extraneous \'=\'"]')
440
441     def test_tokenize_valid(self):
442         expectation = TestExpectationParser.tokenize('FOO : bar = BAZ')
443         self.assertEqual(expectation.is_malformed(), False)
444         self.assertEqual(expectation.comment, None)
445         self.assertEqual(len(expectation.errors), 0)
446
447     def test_tokenize_valid_with_comment(self):
448         expectation = TestExpectationParser.tokenize('FOO : bar = BAZ //Qux.')
449         self.assertEqual(expectation.is_malformed(), False)
450         self.assertEqual(expectation.comment, 'Qux.')
451         self.assertEqual(str(expectation.modifiers), '[\'foo\']')
452         self.assertEqual(str(expectation.expectations), '[\'baz\']')
453         self.assertEqual(len(expectation.errors), 0)
454
455     def test_tokenize_valid_with_multiple_modifiers(self):
456         expectation = TestExpectationParser.tokenize('FOO1 FOO2 : bar = BAZ //Qux.')
457         self.assertEqual(expectation.is_malformed(), False)
458         self.assertEqual(expectation.comment, 'Qux.')
459         self.assertEqual(str(expectation.modifiers), '[\'foo1\', \'foo2\']')
460         self.assertEqual(str(expectation.expectations), '[\'baz\']')
461         self.assertEqual(len(expectation.errors), 0)
462
463     def test_parse_empty_string(self):
464         host = MockHost()
465         test_port = host.port_factory.get('test-win-xp', None)
466         test_port.test_exists = lambda test: True
467         test_config = test_port.test_configuration()
468         full_test_list = []
469         expectation_line = TestExpectationParser.tokenize('')
470         parser = TestExpectationParser(test_port, full_test_list, allow_rebaseline_modifier=False)
471         parser.parse(expectation_line)
472         self.assertFalse(expectation_line.is_invalid())
473
474
475 class TestExpectationSerializerTests(unittest.TestCase):
476     def __init__(self, testFunc):
477         host = MockHost()
478         test_port = host.port_factory.get('test-win-xp', None)
479         self._converter = TestConfigurationConverter(test_port.all_test_configurations(), test_port.configuration_specifier_macros())
480         self._serializer = TestExpectationSerializer(self._converter)
481         unittest.TestCase.__init__(self, testFunc)
482
483     def assert_round_trip(self, in_string, expected_string=None):
484         expectation = TestExpectationParser.tokenize(in_string)
485         if expected_string is None:
486             expected_string = in_string
487         self.assertEqual(expected_string, self._serializer.to_string(expectation))
488
489     def assert_list_round_trip(self, in_string, expected_string=None):
490         expectations = TestExpectationParser.tokenize_list(in_string)
491         if expected_string is None:
492             expected_string = in_string
493         self.assertEqual(expected_string, TestExpectationSerializer.list_to_string(expectations, self._converter))
494
495     def test_unparsed_to_string(self):
496         expectation = TestExpectationLine()
497         serializer = TestExpectationSerializer()
498
499         self.assertEqual(serializer.to_string(expectation), '')
500         expectation.comment = 'Qux.'
501         self.assertEqual(serializer.to_string(expectation), '//Qux.')
502         expectation.name = 'bar'
503         self.assertEqual(serializer.to_string(expectation), ' : bar =  //Qux.')
504         expectation.modifiers = ['foo']
505         self.assertEqual(serializer.to_string(expectation), 'FOO : bar =  //Qux.')
506         expectation.expectations = ['bAz']
507         self.assertEqual(serializer.to_string(expectation), 'FOO : bar = BAZ //Qux.')
508         expectation.expectations = ['bAz1', 'baZ2']
509         self.assertEqual(serializer.to_string(expectation), 'FOO : bar = BAZ1 BAZ2 //Qux.')
510         expectation.modifiers = ['foo1', 'foO2']
511         self.assertEqual(serializer.to_string(expectation), 'FOO1 FOO2 : bar = BAZ1 BAZ2 //Qux.')
512         expectation.errors.append('Oh the horror.')
513         self.assertEqual(serializer.to_string(expectation), '')
514         expectation.original_string = 'Yes it is!'
515         self.assertEqual(serializer.to_string(expectation), 'Yes it is!')
516
517     def test_unparsed_list_to_string(self):
518         expectation = TestExpectationLine()
519         expectation.comment = 'Qux.'
520         expectation.name = 'bar'
521         expectation.modifiers = ['foo']
522         expectation.expectations = ['bAz1', 'baZ2']
523         self.assertEqual(TestExpectationSerializer.list_to_string([expectation]), 'FOO : bar = BAZ1 BAZ2 //Qux.')
524
525     def test_parsed_to_string(self):
526         expectation_line = TestExpectationLine()
527         expectation_line.parsed_bug_modifiers = ['BUGX']
528         expectation_line.name = 'test/name/for/realz.html'
529         expectation_line.parsed_expectations = set([IMAGE])
530         self.assertEqual(self._serializer.to_string(expectation_line), None)
531         expectation_line.matching_configurations = set([TestConfiguration('xp', 'x86', 'release', 'cpu')])
532         self.assertEqual(self._serializer.to_string(expectation_line), 'BUGX XP RELEASE CPU : test/name/for/realz.html = IMAGE')
533         expectation_line.matching_configurations = set([TestConfiguration('xp', 'x86', 'release', 'cpu'), TestConfiguration('xp', 'x86', 'release', 'gpu')])
534         self.assertEqual(self._serializer.to_string(expectation_line), 'BUGX XP RELEASE : test/name/for/realz.html = IMAGE')
535         expectation_line.matching_configurations = set([TestConfiguration('xp', 'x86', 'release', 'cpu'), TestConfiguration('xp', 'x86', 'debug', 'gpu')])
536         self.assertEqual(self._serializer.to_string(expectation_line), 'BUGX XP RELEASE CPU : test/name/for/realz.html = IMAGE\nBUGX XP DEBUG GPU : test/name/for/realz.html = IMAGE')
537
538     def test_parsed_expectations_string(self):
539         expectation_line = TestExpectationLine()
540         expectation_line.parsed_expectations = set([])
541         self.assertEqual(self._serializer._parsed_expectations_string(expectation_line), '')
542         expectation_line.parsed_expectations = set([IMAGE_PLUS_TEXT])
543         self.assertEqual(self._serializer._parsed_expectations_string(expectation_line), 'image+text')
544         expectation_line.parsed_expectations = set([PASS, FAIL])
545         self.assertEqual(self._serializer._parsed_expectations_string(expectation_line), 'pass fail')
546         expectation_line.parsed_expectations = set([FAIL, PASS])
547         self.assertEqual(self._serializer._parsed_expectations_string(expectation_line), 'pass fail')
548
549     def test_parsed_modifier_string(self):
550         expectation_line = TestExpectationLine()
551         expectation_line.parsed_bug_modifiers = ['garden-o-matic']
552         expectation_line.parsed_modifiers = ['for', 'the']
553         self.assertEqual(self._serializer._parsed_modifier_string(expectation_line, []), 'garden-o-matic for the')
554         self.assertEqual(self._serializer._parsed_modifier_string(expectation_line, ['win']), 'garden-o-matic for the win')
555         expectation_line.parsed_bug_modifiers = []
556         expectation_line.parsed_modifiers = []
557         self.assertEqual(self._serializer._parsed_modifier_string(expectation_line, []), '')
558         self.assertEqual(self._serializer._parsed_modifier_string(expectation_line, ['win']), 'win')
559         expectation_line.parsed_bug_modifiers = ['garden-o-matic', 'total', 'is']
560         self.assertEqual(self._serializer._parsed_modifier_string(expectation_line, ['win']), 'garden-o-matic is total win')
561         expectation_line.parsed_bug_modifiers = []
562         expectation_line.parsed_modifiers = ['garden-o-matic', 'total', 'is']
563         self.assertEqual(self._serializer._parsed_modifier_string(expectation_line, ['win']), 'garden-o-matic is total win')
564
565     def test_format_result(self):
566         self.assertEqual(TestExpectationSerializer._format_result('modifiers', 'name', 'expectations', 'comment'), 'MODIFIERS : name = EXPECTATIONS //comment')
567         self.assertEqual(TestExpectationSerializer._format_result('modifiers', 'name', 'expectations', None), 'MODIFIERS : name = EXPECTATIONS')
568
569     def test_string_roundtrip(self):
570         self.assert_round_trip('')
571         self.assert_round_trip('FOO')
572         self.assert_round_trip(':')
573         self.assert_round_trip('FOO :')
574         self.assert_round_trip('FOO : bar')
575         self.assert_round_trip('  FOO :')
576         self.assert_round_trip('    FOO : bar')
577         self.assert_round_trip('FOO : bar = BAZ')
578         self.assert_round_trip('FOO : bar = BAZ //Qux.')
579         self.assert_round_trip('FOO : bar = BAZ // Qux.')
580         self.assert_round_trip('FOO : bar = BAZ // Qux.     ')
581         self.assert_round_trip('FOO : bar = BAZ //        Qux.     ')
582         self.assert_round_trip('FOO : : bar = BAZ')
583         self.assert_round_trip('FOO : : bar = BAZ')
584         self.assert_round_trip('FOO : : bar ==== BAZ')
585         self.assert_round_trip('=')
586         self.assert_round_trip('//')
587         self.assert_round_trip('// ')
588         self.assert_round_trip('// Foo')
589         self.assert_round_trip('// Foo')
590         self.assert_round_trip('// Foo :')
591         self.assert_round_trip('// Foo : =')
592
593     def test_list_roundtrip(self):
594         self.assert_list_round_trip('')
595         self.assert_list_round_trip('\n')
596         self.assert_list_round_trip('\n\n')
597         self.assert_list_round_trip('bar')
598         self.assert_list_round_trip('bar\n//Qux.')
599         self.assert_list_round_trip('bar\n//Qux.\n')
600
601     def test_reconstitute_only_these(self):
602         lines = []
603         reconstitute_only_these = []
604
605         def add_line(matching_configurations, reconstitute):
606             expectation_line = TestExpectationLine()
607             expectation_line.original_string = "Nay"
608             expectation_line.parsed_bug_modifiers = ['BUGX']
609             expectation_line.name = 'Yay'
610             expectation_line.parsed_expectations = set([IMAGE])
611             expectation_line.matching_configurations = matching_configurations
612             lines.append(expectation_line)
613             if reconstitute:
614                 reconstitute_only_these.append(expectation_line)
615
616         add_line(set([TestConfiguration('xp', 'x86', 'release', 'cpu')]), False)
617         add_line(set([TestConfiguration('xp', 'x86', 'release', 'cpu'), TestConfiguration('xp', 'x86', 'release', 'gpu')]), True)
618         add_line(set([TestConfiguration('xp', 'x86', 'release', 'cpu'), TestConfiguration('xp', 'x86', 'debug', 'gpu')]), False)
619         serialized = TestExpectationSerializer.list_to_string(lines, self._converter)
620         self.assertEquals(serialized, "BUGX XP RELEASE CPU : Yay = IMAGE\nBUGX XP RELEASE : Yay = IMAGE\nBUGX XP RELEASE CPU : Yay = IMAGE\nBUGX XP DEBUG GPU : Yay = IMAGE")
621         serialized = TestExpectationSerializer.list_to_string(lines, self._converter, reconstitute_only_these=reconstitute_only_these)
622         self.assertEquals(serialized, "Nay\nBUGX XP RELEASE : Yay = IMAGE\nNay")
623
624     def test_string_whitespace_stripping(self):
625         self.assert_round_trip('\n', '')
626         self.assert_round_trip('  FOO : bar = BAZ', 'FOO : bar = BAZ')
627         self.assert_round_trip('FOO    : bar = BAZ', 'FOO : bar = BAZ')
628         self.assert_round_trip('FOO : bar = BAZ       // Qux.', 'FOO : bar = BAZ // Qux.')
629         self.assert_round_trip('FOO : bar =        BAZ // Qux.', 'FOO : bar = BAZ // Qux.')
630         self.assert_round_trip('FOO :       bar =    BAZ // Qux.', 'FOO : bar = BAZ // Qux.')
631         self.assert_round_trip('FOO :       bar     =    BAZ // Qux.', 'FOO : bar = BAZ // Qux.')
632
633
634 if __name__ == '__main__':
635     unittest.main()