chromium/ios/build/bots/scripts/gtest_utils_test.py

#!/usr/bin/env vpython3
# Copyright 2021 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Unit tests for classes in gtest_utils.py."""

import os
import unittest

import gtest_utils
from test_result_util import TestStatus

FAILURES = [
    'NavigationControllerTest.Reload',
    'NavigationControllerTest/SpdyNetworkTransTest.Constructor/0',
    'BadTest.TimesOut', 'MoreBadTest.TimesOutAndFails',
    'SomeOtherTest.SwitchTypes', 'SomeOtherTest.FAILS_ThisTestTimesOut'
]

FAILS_FAILURES = ['SomeOtherTest.FAILS_Bar']
FLAKY_FAILURES = ['SomeOtherTest.FLAKY_Baz']

CRASH_MESSAGE = ['Oops, this test crashed!']
TIMEOUT_MESSAGE = 'Killed (timed out).'

RELOAD_ERRORS = (r'C:\b\slave\chrome-release-snappy\build\chrome\browser'
                 r'\navigation_controller_unittest.cc:381: Failure' + """
Value of: -1
Expected: contents->controller()->GetPendingEntryIndex()
Which is: 0

""")

SPDY_ERRORS = (r'C:\b\slave\chrome-release-snappy\build\chrome\browser'
               r'\navigation_controller_unittest.cc:439: Failure' + """
Value of: -1
Expected: contents->controller()->GetPendingEntryIndex()
Which is: 0

""")

SWITCH_ERRORS = (r'C:\b\slave\chrome-release-snappy\build\chrome\browser'
                 r'\navigation_controller_unittest.cc:615: Failure' + """
Value of: -1
Expected: contents->controller()->GetPendingEntryIndex()
Which is: 0

""" + r'C:\b\slave\chrome-release-snappy\build\chrome\browser'
                 r'\navigation_controller_unittest.cc:617: Failure' + """
Value of: contents->controller()->GetPendingEntry()
  Actual: true
Expected: false

""")

# pylint: disable=line-too-long
TIMEOUT_ERRORS = (
    '[61613:263:0531/042613:2887943745568888:ERROR:/b/slave'
    '/chromium-rel-mac-builder/build/src/chrome/browser/extensions'
    '/extension_error_reporter.cc(56)] Extension error: Could not load extension '
    'from \'extensions/api_test/geolocation/no_permission\'. Manifest file is '
    'missing or unreadable.')

MOREBAD_ERRORS = """
Value of: entry->page_type()
  Actual: 2
Expected: NavigationEntry::NORMAL_PAGE
"""

TEST_DATA = (
    """
[==========] Running 7 tests from 3 test cases.
[----------] Global test environment set-up.
[----------] 1 test from HunspellTest
[ RUN      ] HunspellTest.All
[       OK ] HunspellTest.All (62 ms)
[----------] 1 test from HunspellTest (62 ms total)

[----------] 4 tests from NavigationControllerTest
[ RUN      ] NavigationControllerTest.Defaults
[       OK ] NavigationControllerTest.Defaults (48 ms)
[ RUN      ] NavigationControllerTest.Reload
%(reload_errors)s
[  FAILED  ] NavigationControllerTest.Reload (2 ms)
[ RUN      ] NavigationControllerTest.Reload_GeneratesNewPage
[       OK ] NavigationControllerTest.Reload_GeneratesNewPage (22 ms)
[ RUN      ] NavigationControllerTest/SpdyNetworkTransTest.Constructor/0
%(spdy_errors)s
[  FAILED  ] NavigationControllerTest/SpdyNetworkTransTest.Constructor/0 (2 ms)
[----------] 4 tests from NavigationControllerTest (74 ms total)

  YOU HAVE 2 FLAKY TESTS

[----------] 1 test from BadTest
[ RUN      ] BadTest.TimesOut
%(timeout_errors)s
""" % {
        'reload_errors': RELOAD_ERRORS,
        'spdy_errors': SPDY_ERRORS,
        'timeout_errors': TIMEOUT_ERRORS
    } + '[0531/042642:ERROR:/b/slave/chromium-rel-mac-builder/build/src/chrome'
    '/test/test_launcher/out_of_proc_test_runner.cc(79)] Test timeout (30000 ms) '
    'exceeded for BadTest.TimesOut' + """
Handling SIGTERM.
Successfully wrote to shutdown pipe, resetting signal handler.
""" +
    '[61613:19971:0531/042642:2887973024284693:INFO:/b/slave/chromium-rel-mac-'
    'builder/build/src/chrome/browser/browser_main.cc(285)] Handling shutdown for '
    'signal 15.' + """

[----------] 1 test from MoreBadTest
[ RUN      ] MoreBadTest.TimesOutAndFails
%(morebad_errors)s
""" % {
        'morebad_errors': MOREBAD_ERRORS
    } +
    '[0531/042642:ERROR:/b/slave/chromium-rel-mac-builder/build/src/chrome/test'
    '/test_launcher/out_of_proc_test_runner.cc(79)] Test timeout (30000 ms) '
    'exceeded for MoreBadTest.TimesOutAndFails' + """
Handling SIGTERM.
Successfully wrote to shutdown pipe, resetting signal handler.
[  FAILED  ] MoreBadTest.TimesOutAndFails (31000 ms)

[----------] 5 tests from SomeOtherTest
[ RUN      ] SomeOtherTest.SwitchTypes
%(switch_errors)s
[  FAILED  ] SomeOtherTest.SwitchTypes (40 ms)
[ RUN      ] SomeOtherTest.Foo
[       OK ] SomeOtherTest.Foo (20 ms)
[ RUN      ] SomeOtherTest.FAILS_Bar
Some error message for a failing test.
[  FAILED  ] SomeOtherTest.FAILS_Bar (40 ms)
[ RUN      ] SomeOtherTest.FAILS_ThisTestTimesOut
""" % {
        'switch_errors': SWITCH_ERRORS
    } + '[0521/041343:ERROR:test_launcher.cc(384)] Test timeout (5000 ms) '
    'exceeded for SomeOtherTest.FAILS_ThisTestTimesOut' + """
[ RUN      ] SomeOtherTest.FLAKY_Baz
Some error message for a flaky test.
[  FAILED  ] SomeOtherTest.FLAKY_Baz (40 ms)
[----------] 2 tests from SomeOtherTest (60 ms total)

[----------] Global test environment tear-down
[==========] 8 tests from 3 test cases ran. (3750 ms total)
[  PASSED  ] 4 tests.
[  FAILED  ] 4 tests, listed below:
[  FAILED  ] NavigationControllerTest.Reload
[  FAILED  ] NavigationControllerTest/SpdyNetworkTransTest.Constructor/0
[  FAILED  ] SomeOtherTest.SwitchTypes
[  FAILED  ] SomeOtherTest.FAILS_ThisTestTimesOut

 1 FAILED TEST
  YOU HAVE 10 DISABLED TESTS

  YOU HAVE 2 FLAKY TESTS

program finished with exit code 1
""")

TEST_DATA_CRASH = """
[==========] Running 7 tests from 3 test cases.
[----------] Global test environment set-up.
[----------] 1 test from HunspellTest
[ RUN      ] HunspellTest.Crashes
Oops, this test crashed!
"""

TEST_DATA_MIXED_STDOUT = """
[==========] Running 3 tests from 3 test cases.
[----------] Global test environment set-up.

[----------] 1 tests from WebSocketHandshakeHandlerSpdy3Test
[ RUN      ] WebSocketHandshakeHandlerSpdy3Test.RequestResponse
[       OK ] WebSocketHandshakeHandlerSpdy3Test.RequestResponse (1 ms)
[----------] 1 tests from WebSocketHandshakeHandlerSpdy3Test (1 ms total)

[----------] 1 test from URLRequestTestFTP
[ RUN      ] URLRequestTestFTP.UnsafePort
FTP server started on port 32841...
sending server_data: {"host": "127.0.0.1", "port": 32841} (36 bytes)
starting FTP server[       OK ] URLRequestTestFTP.UnsafePort (300 ms)
[----------] 1 test from URLRequestTestFTP (300 ms total)

[ RUN      ] TestFix.TestCase
[1:2/3:WARNING:extension_apitest.cc(169)] Workaround for 177163,
prematurely stopping test
[       OK ] X (1000ms total)

[----------] 1 test from Crash
[ RUN      ] Crash.Test
Oops, this test crashed!
"""

TEST_DATA_SKIPPED = """
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from ProcessReaderLinux
[ RUN      ] ProcessReaderLinux.AbortMessage
../../third_party/crashpad/crashpad/snapshot/linux/process_reader_linux_test.cc:842: Skipped

Stack trace:
#00 pc 0x00000000002350b7 /data/local/tmp/crashpad_tests__dist/crashpad_tests
#01 pc 0x0000000000218183 /data/local/tmp/crashpad_tests__dist/crashpad_tests

[  SKIPPED ] ProcessReaderLinux.AbortMessage (1 ms)
[----------] 1 test from ProcessReaderLinux (2 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (2 ms total)
[  PASSED  ] 0 tests.
[  SKIPPED ] 1 test, listed below:
[  SKIPPED ] ProcessReaderLinux.AbortMessage
"""

VALGRIND_HASH = 'B254345E4D3B6A00'

VALGRIND_REPORT = """Leak_DefinitelyLost
1 (1 direct, 0 indirect) bytes in 1 blocks are lost in loss record 1 of 1
  operator new(unsigned long) (m_replacemalloc/vg_replace_malloc.c:1140)
  content::NavigationControllerTest_Reload::TestBody() (a/b/c/d.cc:1150)
Suppression (error hash=#%(hash)s#):
{
   <insert_a_suppression_name_here>
   Memcheck:Leak
   fun:_Znw*
   fun:_ZN31NavigationControllerTest_Reload8TestBodyEv
}""" % {
    'hash': VALGRIND_HASH
}

TEST_DATA_VALGRIND = """
[==========] Running 5 tests from 2 test cases.
[----------] Global test environment set-up.
[----------] 1 test from HunspellTest
[ RUN      ] HunspellTest.All
[       OK ] HunspellTest.All (62 ms)
[----------] 1 test from HunspellTest (62 ms total)

[----------] 4 tests from NavigationControllerTest
[ RUN      ] NavigationControllerTest.Defaults
[       OK ] NavigationControllerTest.Defaults (48 ms)
[ RUN      ] NavigationControllerTest.Reload
[       OK ] NavigationControllerTest.Reload (2 ms)
[ RUN      ] NavigationControllerTest.Reload_GeneratesNewPage
[       OK ] NavigationControllerTest.Reload_GeneratesNewPage (22 ms)
[ RUN      ] NavigationControllerTest/SpdyNetworkTransTest.Constructor/0
[       OK ] NavigationControllerTest/SpdyNetworkTransTest.Constructor/0 (2 ms)
[----------] 4 tests from NavigationControllerTest (74 ms total)

[----------] Global test environment tear-down
[==========] 5 tests from 1 test cases ran. (136 ms total)
[  PASSED  ] 5 tests.

### BEGIN MEMORY TOOL REPORT (error hash=#%(hash)s#)
%(report)s
### END MEMORY TOOL REPORT (error hash=#%(hash)s#)
program finished with exit code 255

""" % {
    'report': VALGRIND_REPORT,
    'hash': VALGRIND_HASH
}

FAILING_TESTS_OUTPUT = """
Failing tests:
ChromeRenderViewTest.FAILS_AllowDOMStorage
PrerenderBrowserTest.PrerenderHTML5VideoJs
"""

FAILING_TESTS_EXPECTED = [
    'ChromeRenderViewTest.FAILS_AllowDOMStorage',
    'PrerenderBrowserTest.PrerenderHTML5VideoJs'
]

TEST_DATA_SHARD_0 = (
    """Note: This is test shard 1 of 30.
[==========] Running 6 tests from 3 test cases.
[----------] Global test environment set-up.
[----------] 1 test from HunspellTest
[ RUN      ] HunspellTest.All
[       OK ] HunspellTest.All (62 ms)
[----------] 1 test from HunspellTest (62 ms total)

[----------] 1 test from BadTest
[ RUN      ] BadTest.TimesOut
%(timeout_errors)s
""" % {
        'timeout_errors': TIMEOUT_ERRORS
    } +
    '[0531/042642:ERROR:/b/slave/chromium-rel-mac-builder/build/src/chrome/test'
    '/test_launcher/out_of_proc_test_runner.cc(79)] Test timeout (30000 ms) '
    'exceeded for BadTest.TimesOut' + """
Handling SIGTERM.
Successfully wrote to shutdown pipe, resetting signal handler.
""" +
    '[61613:19971:0531/042642:2887973024284693:INFO:/b/slave/chromium-rel-mac-'
    'builder/build/src/chrome/browser/browser_main.cc(285)] Handling shutdown for '
    'signal 15.' + """

[----------] 4 tests from SomeOtherTest
[ RUN      ] SomeOtherTest.SwitchTypes
%(switch_errors)s
[  FAILED  ] SomeOtherTest.SwitchTypes (40 ms)
[ RUN      ] SomeOtherTest.Foo
[       OK ] SomeOtherTest.Foo (20 ms)
[ RUN      ] SomeOtherTest.FAILS_Bar
Some error message for a failing test.
[  FAILED  ] SomeOtherTest.FAILS_Bar (40 ms)
[ RUN      ] SomeOtherTest.FAILS_ThisTestTimesOut
""" % {
        'switch_errors': SWITCH_ERRORS
    } +
    '[0521/041343:ERROR:test_launcher.cc(384)] Test timeout (5000 ms) exceeded '
    'for SomeOtherTest.FAILS_ThisTestTimesOut' + """
[ RUN      ] SomeOtherTest.FLAKY_Baz
Some error message for a flaky test.
[  FAILED  ] SomeOtherTest.FLAKY_Baz (40 ms)
[----------] 2 tests from SomeOtherTest (60 ms total)

[----------] Global test environment tear-down
[==========] 7 tests from 3 test cases ran. (3750 ms total)
[  PASSED  ] 5 tests.
[  FAILED  ] 2 test, listed below:
[  FAILED  ] SomeOtherTest.SwitchTypes
[  FAILED  ] SomeOtherTest.FAILS_ThisTestTimesOut

 1 FAILED TEST
  YOU HAVE 10 DISABLED TESTS

  YOU HAVE 2 FLAKY TESTS
""")

TEST_DATA_SHARD_1 = (
    """Note: This is test shard 13 of 30.
[==========] Running 5 tests from 2 test cases.
[----------] Global test environment set-up.
[----------] 4 tests from NavigationControllerTest
[ RUN      ] NavigationControllerTest.Defaults
[       OK ] NavigationControllerTest.Defaults (48 ms)
[ RUN      ] NavigationControllerTest.Reload
%(reload_errors)s
[  FAILED  ] NavigationControllerTest.Reload (2 ms)
[ RUN      ] NavigationControllerTest.Reload_GeneratesNewPage
[       OK ] NavigationControllerTest.Reload_GeneratesNewPage (22 ms)
[ RUN      ] NavigationControllerTest/SpdyNetworkTransTest.Constructor/0
%(spdy_errors)s
""" % {
        'reload_errors': RELOAD_ERRORS,
        'spdy_errors': SPDY_ERRORS
    } + '[  FAILED  ] NavigationControllerTest/SpdyNetworkTransTest.Constructor'
    '/0 (2 ms)' + """
[----------] 4 tests from NavigationControllerTest (74 ms total)

  YOU HAVE 2 FLAKY TESTS

[----------] 1 test from MoreBadTest
[ RUN      ] MoreBadTest.TimesOutAndFails
%(morebad_errors)s
""" % {
        'morebad_errors': MOREBAD_ERRORS
    } +
    '[0531/042642:ERROR:/b/slave/chromium-rel-mac-builder/build/src/chrome/test'
    '/test_launcher/out_of_proc_test_runner.cc(79)] Test timeout (30000 ms) '
    'exceeded for MoreBadTest.TimesOutAndFails' + """
Handling SIGTERM.
Successfully wrote to shutdown pipe, resetting signal handler.
[  FAILED  ] MoreBadTest.TimesOutAndFails (31000 ms)

[----------] Global test environment tear-down
[==========] 5 tests from 2 test cases ran. (3750 ms total)
[  PASSED  ] 3 tests.
[  FAILED  ] 2 tests, listed below:
[  FAILED  ] NavigationControllerTest.Reload
[  FAILED  ] NavigationControllerTest/SpdyNetworkTransTest.Constructor/0

 1 FAILED TEST
  YOU HAVE 10 DISABLED TESTS

  YOU HAVE 2 FLAKY TESTS
""")

TEST_DATA_SHARD_EXIT = 'program finished with exit code '

TEST_DATA_CRASH_SHARD = """Note: This is test shard 5 of 5.
[==========] Running 7 tests from 3 test cases.
[----------] Global test environment set-up.
[----------] 1 test from HunspellTest
[ RUN      ] HunspellTest.Crashes
Oops, this test crashed!"""

TEST_DATA_NESTED_RUNS = (
    """
[ 1/3] 1.0s Foo.Bar (45.5s)
Note: Google Test filter = Foo.Bar
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from Foo, where TypeParam =
[ RUN      ] Foo.Bar
""" +
    '[0725/050653:ERROR:test_launcher.cc(380)] Test timeout (45000 ms) exceeded '
    'for Foo.Bar' + """
Starting tests...
IMPORTANT DEBUGGING NOTE: each test is run inside its own process.
For debugging a test inside a debugger, use the
--gtest_filter=<your_test_name> flag along with either
--single_process (to run all tests in one launcher/browser process) or
--single-process (to do the above, and also run Chrome in single-
process mode).
1 test run
1 test failed (0 ignored)
Failing tests:
Foo.Bar
[ 2/2] 2.00s Foo.Pass (1.0s)""")

# Data generated with run_test_case.py
TEST_DATA_RUN_TEST_CASE_FAIL = """
[  6/422]   7.45s SUIDSandboxUITest.testSUIDSandboxEnabled (1.49s) - retry #2
[ RUN      ] SUIDSandboxUITest.testSUIDSandboxEnabled
[  FAILED  ] SUIDSandboxUITest.testSUIDSandboxEnabled (771 ms)
[  8/422]   7.76s PrintPreviewWebUITest.SourceIsPDFShowFitToPageOption (1.67s)
"""

TEST_DATA_RUN_TEST_CASE_TIMEOUT = """
[  6/422]   7.45s SUIDSandboxUITest.testSUIDSandboxEnabled (1.49s) - retry #2
[ RUN      ] SUIDSandboxUITest.testSUIDSandboxEnabled
(junk)
[  8/422]   7.76s PrintPreviewWebUITest.SourceIsPDFShowFitToPageOption (1.67s)
"""

# Data generated by swarming.py
TEST_DATA_SWARM_TEST_FAIL = """

================================================================
Begin output from shard index 0 (machine tag: swarm12.c, id: swarm12)
================================================================

[==========] Running 2 tests from linux_swarm_trigg-8-base_unittests test run.
Starting tests (using 2 parallel jobs)...
IMPORTANT DEBUGGING NOTE: batches of tests are run inside their
own process. For debugging a test inside a debugger, use the
--gtest_filter=<your_test_name> flag along with
--single-process-tests.
[1/1242] HistogramDeathTest.BadRangesTest (62 ms)
[2/1242] OutOfMemoryDeathTest.New (22 ms)
[1242/1242] ThreadIdNameManagerTest.ThreadNameInterning (0 ms)
Retrying 1 test (retry #1)
[ RUN      ] PickleTest.EncodeDecode
../../base/pickle_unittest.cc:69: Failure
Value of: false
  Actual: false
Expected: true
[  FAILED  ] PickleTest.EncodeDecode (0 ms)
[1243/1243] PickleTest.EncodeDecode (0 ms)
Retrying 1 test (retry #2)
[ RUN      ] PickleTest.EncodeDecode
../../base/pickle_unittest.cc:69: Failure
Value of: false
  Actual: false
Expected: true
[  FAILED  ] PickleTest.EncodeDecode (1 ms)
[1244/1244] PickleTest.EncodeDecode (1 ms)
Retrying 1 test (retry #3)
[ RUN      ] PickleTest.EncodeDecode
../../base/pickle_unittest.cc:69: Failure
Value of: false
  Actual: false
Expected: true
[  FAILED  ] PickleTest.EncodeDecode (0 ms)
[1245/1245] PickleTest.EncodeDecode (0 ms)
1245 tests run
1 test failed:
    PickleTest.EncodeDecode
Summary of all itest iterations:
1 test failed:
    PickleTest.EncodeDecode
End of the summary.
Tests took 31 seconds.


================================================================
End output from shard index 0 (machine tag: swarm12.c, id: swarm12). Return 1
================================================================

"""

TEST_DATA_COMPILED_FILE = """

Testing started
Wrote compiled tests to file: test_data/compiled_tests.json

[----------] 1 tests from test1
[ RUN      ] test1.test_method1
[       OK ] test1.test_method1 (5 ms)
[----------] 1 tests from test1 (5 ms total)

"""

COMPILED_FILE_PATH = 'test_data/compiled_tests.json'

TEST_DATA_LAUNCHER_SPAWN = """
[03:12:19:INFO] Using 8 parallel jobs.
[03:12:19:INFO] [1/2] TestFix.TestCase (8 ms)
[04:20:17:INFO] [ RUN      ] TextPaintTimingDetectorTest.LargestTextPaint
[04:20:17:INFO] ../../third_party/blink/renderer/core/paint/timing/text_paint_timing_detector_test.cc:361: Failure
[04:20:17:INFO] Expected equality of these values:
[04:20:17:INFO]   1u
[04:20:17:INFO]     Which is: 1
[04:20:17:INFO]   events.size()
[04:20:17:INFO]     Which is: 8
[04:20:17:INFO]
[04:20:17:INFO] [  FAILED  ] TextPaintTimingDetectorTest.LargestTextPaint (567 ms)
[04:22:58:INFO] Retrying 1 test (retry #0)
[04:23:01:INFO] [3/3] TextPaintTimingDetectorTest.LargestTextPaint (138 ms)
[03:12:19:INFO] SUCCESS: all tests passed.
[03:12:20:INFO] Tests took 46 seconds.

"""

TEST_DATA_LAUNCHER_SPAWN_CRASH = """

IMPORTANT DEBUGGING NOTE: batches of tests are run inside their
own process. For debugging a test inside a debugger, use the
--gtest_filter=<your_test_name> flag along with
--single-process-tests.
Using sharding settings from environment. This is shard 0/1
Using 1 parallel jobs.
[==========] Running 3 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 3 tests from LoggingTest
[ RUN      ] LoggingTest.FailedTest
../../base/logging_unittest.cc:143: Failure
Value of: (::logging::ShouldCreateLogMessage(::logging::LOGGING_INFO))
  Actual: true
Expected: false
Stack trace:
#0 0x560c1971de44 logging::(anonymous namespace)::LoggingTest_LogIsOn_Test::TestBody()

[  FAILED  ] LoggingTest.FailedTest (1 ms)
[ RUN      ] LoggingTest.StreamingWstringFindsCorrectOperator
[       OK ] LoggingTest.StreamingWstringFindsCorrectOperator (0 ms)
[ RUN      ] LoggingTest.CrashedTest
[1309853:1309853:FATAL:logging_unittest.cc(145)] Check failed: false.
#0 0x7f151e295152 base::debug::CollectStackTrace()

[1/3] LoggingTest.FailedTest (1 ms)
[2/3] LoggingTest.StreamingWstringFindsCorrectOperator (1 ms)
[3/3] LoggingTest.CrashedTest (CRASHED)
1 test failed:
    LoggingTest.FailedTest (../../base/logging_unittest.cc:141)
1 test crashed:
    LoggingTest.CrashedTest (../../base/logging_unittest.cc:141)
Tests took 0 seconds.

"""

TEST_REPO = 'https://test'
# pylint: enable=line-too-long


class TestGTestLogParserTests(unittest.TestCase):

  def testGTestLogParserNoSharding(self):
    # Tests for log parsing without sharding.
    parser = gtest_utils.GTestLogParser()
    for line in TEST_DATA.splitlines():
      parser.ProcessLine(line)
    parser.Finalize()

    self.assertEqual(0, len(parser.ParsingErrors()))
    self.assertFalse(parser.RunningTests())

    self.assertEqual(sorted(FAILURES), sorted(parser.FailedTests()))
    self.assertEqual(
        sorted(FAILURES + FAILS_FAILURES),
        sorted(parser.FailedTests(include_fails=True)))
    self.assertEqual(
        sorted(FAILURES + FLAKY_FAILURES),
        sorted(parser.FailedTests(include_flaky=True)))
    self.assertEqual(
        sorted(FAILURES + FAILS_FAILURES + FLAKY_FAILURES),
        sorted(parser.FailedTests(include_fails=True, include_flaky=True)))

    self.assertEqual(10, parser.DisabledTests())
    self.assertEqual(2, parser.FlakyTests())

    test_name = 'NavigationControllerTest.Reload'
    self.assertEqual('\n'.join(['%s: ' % test_name, RELOAD_ERRORS]),
                     '\n'.join(parser.FailureDescription(test_name)))
    self.assertEqual(['FAILURE'], parser.TriesForTest(test_name))

    test_name = 'NavigationControllerTest/SpdyNetworkTransTest.Constructor/0'
    self.assertEqual('\n'.join(['%s: ' % test_name, SPDY_ERRORS]),
                     '\n'.join(parser.FailureDescription(test_name)))
    self.assertEqual(['FAILURE'], parser.TriesForTest(test_name))

    test_name = 'SomeOtherTest.SwitchTypes'
    self.assertEqual('\n'.join(['%s: ' % test_name, SWITCH_ERRORS]),
                     '\n'.join(parser.FailureDescription(test_name)))
    self.assertEqual(['FAILURE'], parser.TriesForTest(test_name))

    test_name = 'BadTest.TimesOut'
    self.assertEqual(
        '\n'.join(['%s: ' % test_name, TIMEOUT_ERRORS, TIMEOUT_MESSAGE]),
        '\n'.join(parser.FailureDescription(test_name)))
    self.assertEqual(['TIMEOUT'], parser.TriesForTest(test_name))

    test_name = 'MoreBadTest.TimesOutAndFails'
    self.assertEqual(
        '\n'.join(['%s: ' % test_name, MOREBAD_ERRORS, TIMEOUT_MESSAGE]),
        '\n'.join(parser.FailureDescription(test_name)))
    self.assertEqual(['TIMEOUT'], parser.TriesForTest(test_name))

    self.assertEqual(['SUCCESS'], parser.TriesForTest('SomeOtherTest.Foo'))

    # Same unit tests (when applicable) using ResultCollection
    collection = parser.GetResultCollection()
    self.assertEqual(
        sorted(FAILURES + FAILS_FAILURES + FLAKY_FAILURES),
        sorted(collection.never_expected_tests()))

    self.assertEqual(len(collection.test_results), 12)

    # To know that each condition branch in for loop is covered.
    cover_set = set()
    for test_result in collection.test_results:
      name = test_result.name
      if name == 'NavigationControllerTest.Reload':
        cover_set.add(name)
        self.assertEqual('\n'.join([RELOAD_ERRORS]), test_result.test_log)
        self.assertEqual(TestStatus.FAIL, test_result.status)
        self.assertEqual(2, test_result.duration)

      if name == 'NavigationControllerTest/SpdyNetworkTransTest.Constructor/0':
        cover_set.add(name)
        self.assertEqual('\n'.join([SPDY_ERRORS]), test_result.test_log)
        self.assertEqual(TestStatus.FAIL, test_result.status)
        self.assertEqual(2, test_result.duration)

      if name == 'SomeOtherTest.SwitchTypes':
        cover_set.add(name)
        self.assertEqual('\n'.join([SWITCH_ERRORS]), test_result.test_log)
        self.assertEqual(TestStatus.FAIL, test_result.status)
        self.assertEqual(40, test_result.duration)

      if name == 'BadTest.TimesOut':
        cover_set.add(name)
        self.assertEqual('\n'.join([TIMEOUT_ERRORS, TIMEOUT_MESSAGE]),
                         test_result.test_log)
        self.assertEqual(TestStatus.ABORT, test_result.status)
        self.assertEqual(None, test_result.duration)

      if name == 'MoreBadTest.TimesOutAndFails':
        cover_set.add(name)
        self.assertEqual('\n'.join([MOREBAD_ERRORS, TIMEOUT_MESSAGE]),
                         test_result.test_log)
        self.assertEqual(TestStatus.ABORT, test_result.status)
        self.assertEqual(None, test_result.duration)

      if name == 'SomeOtherTest.Foo':
        cover_set.add(name)
        self.assertEqual('', test_result.test_log)
        self.assertEqual(TestStatus.PASS, test_result.status)
        self.assertEqual(20, test_result.duration)

    test_list = [
        'BadTest.TimesOut', 'MoreBadTest.TimesOutAndFails',
        'NavigationControllerTest.Reload',
        'NavigationControllerTest/SpdyNetworkTransTest.Constructor/0',
        'SomeOtherTest.Foo', 'SomeOtherTest.SwitchTypes'
    ]
    self.assertEqual(sorted(test_list), sorted(cover_set))

    parser = gtest_utils.GTestLogParser()
    for line in TEST_DATA_CRASH.splitlines():
      parser.ProcessLine(line)
    parser.Finalize()

    self.assertEqual(0, len(parser.ParsingErrors()))
    self.assertTrue(parser.RunningTests())
    self.assertEqual(['HunspellTest.Crashes'], parser.FailedTests())
    self.assertEqual(0, parser.DisabledTests())
    self.assertEqual(0, parser.FlakyTests())

    test_name = 'HunspellTest.Crashes'
    expected_log_lines = [
        'Did not complete.',
        'Potential test logs from crash until the end of test program:'
    ] + CRASH_MESSAGE
    self.assertEqual('\n'.join(['%s: ' % test_name] + expected_log_lines),
                     '\n'.join(parser.FailureDescription(test_name)))
    self.assertEqual(['UNKNOWN'], parser.TriesForTest(test_name))

    collection = parser.GetResultCollection()
    self.assertEqual(
        set(['HunspellTest.Crashes']), collection.unexpected_tests())
    for result in collection.test_results:
      covered = False
      if result.name == 'HunspellTest.Crashes':
        covered = True
        self.assertEqual('\n'.join(expected_log_lines), result.test_log)
        self.assertEqual(TestStatus.CRASH, result.status)
    self.assertTrue(covered)

  def testGTestLogParserSharding(self):
    # Same tests for log parsing with sharding_supervisor.
    parser = gtest_utils.GTestLogParser()
    test_data_shard = TEST_DATA_SHARD_0 + TEST_DATA_SHARD_1
    for line in test_data_shard.splitlines():
      parser.ProcessLine(line)
    parser.ProcessLine(TEST_DATA_SHARD_EXIT + '2')
    parser.Finalize()

    self.assertEqual(0, len(parser.ParsingErrors()))
    self.assertFalse(parser.RunningTests())

    self.assertEqual(sorted(FAILURES), sorted(parser.FailedTests()))
    self.assertEqual(
        sorted(FAILURES + FAILS_FAILURES),
        sorted(parser.FailedTests(include_fails=True)))
    self.assertEqual(
        sorted(FAILURES + FLAKY_FAILURES),
        sorted(parser.FailedTests(include_flaky=True)))
    self.assertEqual(
        sorted(FAILURES + FAILS_FAILURES + FLAKY_FAILURES),
        sorted(parser.FailedTests(include_fails=True, include_flaky=True)))

    self.assertEqual(10, parser.DisabledTests())
    self.assertEqual(2, parser.FlakyTests())

    test_name = 'NavigationControllerTest.Reload'
    self.assertEqual('\n'.join(['%s: ' % test_name, RELOAD_ERRORS]),
                     '\n'.join(parser.FailureDescription(test_name)))
    self.assertEqual(['FAILURE'], parser.TriesForTest(test_name))

    test_name = ('NavigationControllerTest/SpdyNetworkTransTest.Constructor/0')
    self.assertEqual('\n'.join(['%s: ' % test_name, SPDY_ERRORS]),
                     '\n'.join(parser.FailureDescription(test_name)))
    self.assertEqual(['FAILURE'], parser.TriesForTest(test_name))

    test_name = 'SomeOtherTest.SwitchTypes'
    self.assertEqual('\n'.join(['%s: ' % test_name, SWITCH_ERRORS]),
                     '\n'.join(parser.FailureDescription(test_name)))
    self.assertEqual(['FAILURE'], parser.TriesForTest(test_name))

    test_name = 'BadTest.TimesOut'
    self.assertEqual(
        '\n'.join(['%s: ' % test_name, TIMEOUT_ERRORS, TIMEOUT_MESSAGE]),
        '\n'.join(parser.FailureDescription(test_name)))
    self.assertEqual(['TIMEOUT'], parser.TriesForTest(test_name))

    test_name = 'MoreBadTest.TimesOutAndFails'
    self.assertEqual(
        '\n'.join(['%s: ' % test_name, MOREBAD_ERRORS, TIMEOUT_MESSAGE]),
        '\n'.join(parser.FailureDescription(test_name)))
    self.assertEqual(['TIMEOUT'], parser.TriesForTest(test_name))

    self.assertEqual(['SUCCESS'], parser.TriesForTest('SomeOtherTest.Foo'))

    # Same unit tests (when applicable) using ResultCollection
    collection = parser.GetResultCollection()
    self.assertEqual(
        sorted(FAILURES + FAILS_FAILURES + FLAKY_FAILURES),
        sorted(collection.never_expected_tests()))

    self.assertEqual(len(collection.test_results), 12)

    # To know that each condition branch in for loop is covered.
    cover_set = set()
    for test_result in collection.test_results:
      name = test_result.name
      if name == 'NavigationControllerTest.Reload':
        cover_set.add(name)
        self.assertEqual('\n'.join([RELOAD_ERRORS]), test_result.test_log)
        self.assertEqual(TestStatus.FAIL, test_result.status)
        self.assertEqual(2, test_result.duration)

      if name == 'NavigationControllerTest/SpdyNetworkTransTest.Constructor/0':
        cover_set.add(name)
        self.assertEqual('\n'.join([SPDY_ERRORS]), test_result.test_log)
        self.assertEqual(TestStatus.FAIL, test_result.status)
        self.assertEqual(2, test_result.duration)

      if name == 'SomeOtherTest.SwitchTypes':
        cover_set.add(name)
        self.assertEqual('\n'.join([SWITCH_ERRORS]), test_result.test_log)
        self.assertEqual(TestStatus.FAIL, test_result.status)
        self.assertEqual(40, test_result.duration)

      if name == 'BadTest.TimesOut':
        cover_set.add(name)
        self.assertEqual('\n'.join([TIMEOUT_ERRORS, TIMEOUT_MESSAGE]),
                         test_result.test_log)
        self.assertEqual(TestStatus.ABORT, test_result.status)
        self.assertEqual(None, test_result.duration)

      if name == 'MoreBadTest.TimesOutAndFails':
        cover_set.add(name)
        self.assertEqual('\n'.join([MOREBAD_ERRORS, TIMEOUT_MESSAGE]),
                         test_result.test_log)
        self.assertEqual(TestStatus.ABORT, test_result.status)
        self.assertEqual(None, test_result.duration)

      if name == 'SomeOtherTest.Foo':
        cover_set.add(name)
        self.assertEqual('', test_result.test_log)
        self.assertEqual(TestStatus.PASS, test_result.status)

    test_list = [
        'BadTest.TimesOut', 'MoreBadTest.TimesOutAndFails',
        'NavigationControllerTest.Reload',
        'NavigationControllerTest/SpdyNetworkTransTest.Constructor/0',
        'SomeOtherTest.Foo', 'SomeOtherTest.SwitchTypes'
    ]
    self.assertEqual(sorted(test_list), sorted(cover_set))

    parser = gtest_utils.GTestLogParser()
    for line in TEST_DATA_CRASH.splitlines():
      parser.ProcessLine(line)
    parser.Finalize()

    self.assertEqual(0, len(parser.ParsingErrors()))
    self.assertTrue(parser.RunningTests())
    self.assertEqual(['HunspellTest.Crashes'], parser.FailedTests())
    self.assertEqual(0, parser.DisabledTests())
    self.assertEqual(0, parser.FlakyTests())

    test_name = 'HunspellTest.Crashes'
    expected_log_lines = [
        'Did not complete.',
        'Potential test logs from crash until the end of test program:'
    ] + CRASH_MESSAGE
    self.assertEqual('\n'.join(['%s: ' % test_name] + expected_log_lines),
                     '\n'.join(parser.FailureDescription(test_name)))
    self.assertEqual(['UNKNOWN'], parser.TriesForTest(test_name))

    collection = parser.GetResultCollection()
    self.assertEqual(
        set(['HunspellTest.Crashes']), collection.unexpected_tests())
    for result in collection.test_results:
      covered = False
      if result.name == 'HunspellTest.Crashes':
        covered = True
        self.assertEqual('\n'.join(expected_log_lines), result.test_log)
        self.assertEqual(TestStatus.CRASH, result.status)
    self.assertTrue(covered)

  def testGTestLogParserMixedStdout(self):
    parser = gtest_utils.GTestLogParser()
    for line in TEST_DATA_MIXED_STDOUT.splitlines():
      parser.ProcessLine(line)
    parser.Finalize()

    self.assertEqual([], parser.ParsingErrors())
    self.assertEqual(['Crash.Test'], parser.RunningTests())
    self.assertEqual(['TestFix.TestCase', 'Crash.Test'], parser.FailedTests())
    self.assertEqual(0, parser.DisabledTests())
    self.assertEqual(0, parser.FlakyTests())
    self.assertEqual(['UNKNOWN'], parser.TriesForTest('Crash.Test'))
    self.assertEqual(['TIMEOUT'], parser.TriesForTest('TestFix.TestCase'))
    self.assertEqual(['SUCCESS'],
                     parser.TriesForTest(
                         'WebSocketHandshakeHandlerSpdy3Test.RequestResponse'))

    # Same unit tests (when applicable) using ResultCollection
    collection = parser.GetResultCollection()
    self.assertEqual(
        sorted(['TestFix.TestCase', 'Crash.Test']),
        sorted(collection.never_expected_tests()))

    # To know that each condition branch in for loop is covered.
    cover_set = set()
    for test_result in collection.test_results:
      name = test_result.name
      if name == 'Crash.Test':
        cover_set.add(name)
        self.assertEqual(TestStatus.CRASH, test_result.status)

      if name == 'TestFix.TestCase':
        cover_set.add(name)
        self.assertEqual(TestStatus.ABORT, test_result.status)

      if name == 'WebSocketHandshakeHandlerSpdy3Test.RequestResponse':
        cover_set.add(name)
        self.assertEqual(TestStatus.PASS, test_result.status)
        self.assertEqual(1, test_result.duration)
    test_list = [
        'Crash.Test', 'TestFix.TestCase',
        'WebSocketHandshakeHandlerSpdy3Test.RequestResponse'
    ]
    self.assertEqual(test_list, sorted(cover_set))

  def testGtestLogParserSkipped(self):
    parser = gtest_utils.GTestLogParser()
    for line in TEST_DATA_SKIPPED.splitlines():
      parser.ProcessLine(line)
    parser.Finalize()

    self.assertEqual([], parser.ParsingErrors())
    self.assertEqual([], parser.RunningTests())
    self.assertEqual([], parser.FailedTests())
    self.assertEqual(['ProcessReaderLinux.AbortMessage'], parser.SkippedTests())
    self.assertEqual(0, parser.DisabledTests())
    self.assertEqual(0, parser.FlakyTests())
    self.assertEqual(['SKIPPED'],
                     parser.TriesForTest('ProcessReaderLinux.AbortMessage'))

    # Same unit tests (when applicable) using ResultCollection
    collection = parser.GetResultCollection()
    self.assertEqual(['ProcessReaderLinux.AbortMessage'],
                     sorted(
                         collection.tests_by_expression(lambda tr: tr.status ==
                                                        TestStatus.SKIP)))
    self.assertEqual([], sorted(collection.unexpected_tests()))

    covered = False
    for test_result in collection.test_results:
      if test_result.name == 'ProcessReaderLinux.AbortMessage':
        covered = True
        self.assertEqual(TestStatus.SKIP, test_result.status)
    self.assertTrue(covered)

  def testRunTestCaseFail(self):
    parser = gtest_utils.GTestLogParser()
    for line in TEST_DATA_RUN_TEST_CASE_FAIL.splitlines():
      parser.ProcessLine(line)
    parser.Finalize()

    self.assertEqual(0, len(parser.ParsingErrors()))
    self.assertEqual([], parser.RunningTests())
    self.assertEqual(['SUIDSandboxUITest.testSUIDSandboxEnabled'],
                     parser.FailedTests())
    self.assertEqual(
        ['SUIDSandboxUITest.testSUIDSandboxEnabled: '],
        parser.FailureDescription('SUIDSandboxUITest.testSUIDSandboxEnabled'))
    self.assertEqual(
        ['FAILURE'],
        parser.TriesForTest('SUIDSandboxUITest.testSUIDSandboxEnabled'))

    # Same unit tests (when applicable) using ResultCollection
    collection = parser.GetResultCollection()
    self.assertEqual(['SUIDSandboxUITest.testSUIDSandboxEnabled'],
                     sorted(collection.failed_tests()))

    covered = False
    for test_result in collection.test_results:
      if test_result.name == 'SUIDSandboxUITest.testSUIDSandboxEnabled':
        covered = True
        self.assertEqual(TestStatus.FAIL, test_result.status)
        self.assertEqual('', test_result.test_log)
        self.assertEqual(771, test_result.duration)

    self.assertTrue(covered)

  def testRunTestCaseTimeout(self):
    parser = gtest_utils.GTestLogParser()
    for line in TEST_DATA_RUN_TEST_CASE_TIMEOUT.splitlines():
      parser.ProcessLine(line)
    parser.Finalize()

    self.assertEqual(0, len(parser.ParsingErrors()))
    self.assertEqual([], parser.RunningTests())
    self.assertEqual(['SUIDSandboxUITest.testSUIDSandboxEnabled'],
                     parser.FailedTests())
    self.assertEqual(
        ['SUIDSandboxUITest.testSUIDSandboxEnabled: ', '(junk)'],
        parser.FailureDescription('SUIDSandboxUITest.testSUIDSandboxEnabled'))
    self.assertEqual(
        ['TIMEOUT'],
        parser.TriesForTest('SUIDSandboxUITest.testSUIDSandboxEnabled'))

    # Same unit tests (when applicable) using ResultCollection
    collection = parser.GetResultCollection()
    self.assertEqual(['SUIDSandboxUITest.testSUIDSandboxEnabled'],
                     sorted(collection.never_expected_tests()))

    covered = False
    for test_result in collection.test_results:
      if test_result.name == 'SUIDSandboxUITest.testSUIDSandboxEnabled':
        covered = True
        self.assertEqual(TestStatus.ABORT, test_result.status)
        self.assertEqual('(junk)', test_result.test_log)
        self.assertEqual(None, test_result.duration)

    self.assertTrue(covered)

  def testRunTestCaseParseSwarm(self):
    parser = gtest_utils.GTestLogParser()
    for line in TEST_DATA_SWARM_TEST_FAIL.splitlines():
      parser.ProcessLine(line)
    parser.Finalize()

    self.assertEqual(0, len(parser.ParsingErrors()))
    self.assertEqual([], parser.RunningTests())
    self.assertEqual(['PickleTest.EncodeDecode'], parser.FailedTests())
    log_lines = [
        'PickleTest.EncodeDecode: ',
        '../../base/pickle_unittest.cc:69: Failure',
        'Value of: false',
        '  Actual: false',
        'Expected: true',
    ]
    self.assertEqual(log_lines,
                     parser.FailureDescription('PickleTest.EncodeDecode'))
    self.assertEqual(['FAILURE'],
                     parser.TriesForTest('PickleTest.EncodeDecode'))

    # Same unit tests (when applicable) using ResultCollection
    collection = parser.GetResultCollection()
    self.assertEqual(['PickleTest.EncodeDecode'],
                     sorted(collection.never_expected_tests()))

    covered_count = 0
    for test_result in collection.test_results:
      if test_result.name == 'PickleTest.EncodeDecode':
        covered_count += 1
        self.assertEqual(TestStatus.FAIL, test_result.status)
        self.assertEqual('\n'.join(log_lines[1:]), test_result.test_log)

    self.assertEqual(3, covered_count)

  def testNestedGtests(self):
    parser = gtest_utils.GTestLogParser()
    for line in TEST_DATA_NESTED_RUNS.splitlines():
      parser.ProcessLine(line)
    parser.Finalize()
    self.assertEqual(['Foo.Bar'], parser.FailedTests(True, True))

    # Same unit tests (when applicable) using ResultCollection
    collection = parser.GetResultCollection()
    self.assertEqual(['Foo.Bar'], sorted(collection.never_expected_tests()))

    covered = False
    for test_result in collection.test_results:
      if test_result.name == 'Foo.Bar':
        covered = True
        self.assertEqual(TestStatus.ABORT, test_result.status)

    self.assertTrue(covered)

  def testParseCompiledFileLocation(self):
    parser = gtest_utils.GTestLogParser()
    for line in TEST_DATA_COMPILED_FILE.splitlines():
      parser.ProcessLine(line)
    parser.Finalize()
    self.assertEqual(COMPILED_FILE_PATH, parser.compiled_tests_file_path)

    # Just a hack so that we can point the compiled file path to right place
    parser.compiled_tests_file_path = os.path.join(
        os.getcwd(), parser.compiled_tests_file_path)
    parser.ParseAndPopulateTestResultLocations(TEST_REPO, False)
    collection = parser.GetResultCollection()

    covered = False
    for test_result in collection.test_results:
      if test_result.name == 'test1.test_method1':
        covered = True
        self.assertEqual(TestStatus.PASS, test_result.status)
        test_loc = {'repo': TEST_REPO, 'fileName': '//random/path/test1.cc'}
        self.assertEqual(test_loc, test_result.test_loc)
    self.assertTrue(covered)

    disabled_tests_covered = True
    # disabled tests shouldn't be included in the result
    # because output_disabled_tests is false
    for test_result in collection.test_results:
      if test_result.name == 'test2.DISABLED_test_method1':
        covered = False
    self.assertTrue(disabled_tests_covered)

  def testParseCompiledFileLocationWithCustomPath(self):
    parser = gtest_utils.GTestLogParser()
    for line in TEST_DATA_COMPILED_FILE.splitlines():
      parser.ProcessLine(line)
    parser.Finalize()
    self.assertEqual(COMPILED_FILE_PATH, parser.compiled_tests_file_path)

    # Just a hack so that we can point the compiled file path to right place
    parser.compiled_tests_file_path = os.path.join(
        os.getcwd(), parser.compiled_tests_file_path)

    host_file_path = parser.compiled_tests_file_path
    # setting it to None to make sure overriding the path arg really works
    parser.compiled_tests_file_path = None

    parser.ParseAndPopulateTestResultLocations(TEST_REPO, False, host_file_path)
    collection = parser.GetResultCollection()

    covered = False
    for test_result in collection.test_results:
      if test_result.name == 'test1.test_method1':
        covered = True
        self.assertEqual(TestStatus.PASS, test_result.status)
        test_loc = {'repo': TEST_REPO, 'fileName': '//random/path/test1.cc'}
        self.assertEqual(test_loc, test_result.test_loc)
    self.assertTrue(covered)

    disabled_tests_covered = True
    # disabled tests shouldn't be included in the result
    # because output_disabled_tests is false
    for test_result in collection.test_results:
      if test_result.name == 'test2.DISABLED_test_method1':
        covered = False
    self.assertTrue(disabled_tests_covered)

  def testParseCompiledFileLocationOutputDisabledTests(self):
    parser = gtest_utils.GTestLogParser()
    for line in TEST_DATA_COMPILED_FILE.splitlines():
      parser.ProcessLine(line)
    parser.Finalize()
    self.assertEqual(COMPILED_FILE_PATH, parser.compiled_tests_file_path)

    # Just a hack so that we can point the compiled file path to right place
    parser.compiled_tests_file_path = os.path.join(
        os.getcwd(), parser.compiled_tests_file_path)
    parser.ParseAndPopulateTestResultLocations(TEST_REPO, True)
    collection = parser.GetResultCollection()

    covered = False
    for test_result in collection.test_results:
      if test_result.name == 'test1.test_method1':
        covered = True
        self.assertEqual(TestStatus.PASS, test_result.status)
        test_loc = {'repo': TEST_REPO, 'fileName': '//random/path/test1.cc'}
        self.assertEqual(test_loc, test_result.test_loc)

    covered = False
    for test_result in collection.test_results:
      if test_result.name == 'test2.DISABLED_test_method1':
        covered = True
        self.assertEqual(TestStatus.SKIP, test_result.status)
        test_loc = {'repo': TEST_REPO, 'fileName': '//random/path/test2.cc'}
        self.assertEqual(test_loc, test_result.test_loc)
    self.assertTrue(covered)

  def testGTestLogLauncherSpawn(self):
    parser = gtest_utils.GTestLogParser()
    for line in TEST_DATA_LAUNCHER_SPAWN.splitlines():
      parser.ProcessLine(line)
    parser.Finalize()

    self.assertEqual([], parser.ParsingErrors())
    self.assertEqual([], parser.RunningTests())
    self.assertEqual([], parser.FailedTests())
    self.assertEqual(0, parser.DisabledTests())
    self.assertEqual(0, parser.FlakyTests())
    self.assertEqual(
        ['TestFix.TestCase', 'TextPaintTimingDetectorTest.LargestTextPaint'],
        parser.PassedTests())
    collection = parser.GetResultCollection()
    self.assertFalse(collection.crashed)

  def testGTestLogLauncherSpawnCrash(self):
    parser = gtest_utils.GTestLogParser()
    for line in TEST_DATA_LAUNCHER_SPAWN_CRASH.splitlines():
      parser.ProcessLine(line)
    parser.Finalize()

    self.assertEqual([], parser.ParsingErrors())
    self.assertEqual(['LoggingTest.CrashedTest'], parser.RunningTests())
    self.assertEqual(['LoggingTest.FailedTest', 'LoggingTest.CrashedTest'],
                     parser.FailedTests())
    self.assertEqual(0, parser.DisabledTests())
    self.assertEqual(0, parser.FlakyTests())
    self.assertEqual(['LoggingTest.StreamingWstringFindsCorrectOperator'],
                     parser.PassedTests())
    collection = parser.GetResultCollection()
    self.assertTrue(collection.crashed)


if __name__ == '__main__':
  unittest.main()