Simon Jakobi pushed to branch wip/sjakobi/T16720 at Glasgow Haskell Compiler / GHC

Commits:

1 changed file:

Changes:

  • testsuite/driver/testlib.py
    ... ... @@ -1493,6 +1493,14 @@ def _newTestDir(name: TestName, opts: TestOptions, tempdir, dir):
    1493 1493
         opts.testdir_raw = Path(os.path.join(tempdir, testdir, name + testdir_suffix))
    
    1494 1494
         opts.compiler_always_flags = config.compiler_always_flags
    
    1495 1495
     
    
    1496
    +def _result_directory(opts: TestOptions) -> str:
    
    1497
    +    # The test's source directory, relative to the GHC source root, so it reads
    
    1498
    +    # the same regardless of which directory `make` was invoked from.
    
    1499
    +    try:
    
    1500
    +        return os.path.relpath(opts.srcdir, config.top.parent)
    
    1501
    +    except Exception:
    
    1502
    +        return ''
    
    1503
    +
    
    1496 1504
     # -----------------------------------------------------------------------------
    
    1497 1505
     # Actually doing tests
    
    1498 1506
     
    
    ... ... @@ -1817,7 +1825,7 @@ async def do_test(name: TestName,
    1817 1825
         if opts.expect not in ['pass', 'fail', 'missing-lib']:
    
    1818 1826
             framework_fail(name, way, 'bad expected ' + opts.expect)
    
    1819 1827
     
    
    1820
    -    directory = str_removeprefix(str_removeprefix(str(opts.testdir), './'), '.\\')
    
    1828
    +    directory = _result_directory(opts)
    
    1821 1829
     
    
    1822 1830
         if way in opts.fragile_ways:
    
    1823 1831
             if_verbose(1, '*** fragile test %s resulted in %s' % (full_name, 'pass' if result.passed else 'fail'))
    
    ... ... @@ -1868,7 +1876,7 @@ def framework_fail(name: Optional[TestName], way: Optional[WayName], reason: str
    1868 1876
         # so we need to take care not to blow up with the wrong way
    
    1869 1877
         # and report the actual reason for the failure.
    
    1870 1878
         try:
    
    1871
    -      directory = str_removeprefix(str_removeprefix(str(opts.testdir), './'), '.\\')
    
    1879
    +      directory = _result_directory(opts)
    
    1872 1880
         except:
    
    1873 1881
           directory = ''
    
    1874 1882
         full_name = '%s(%s)' % (name, way)
    
    ... ... @@ -1881,7 +1889,7 @@ def framework_fail(name: Optional[TestName], way: Optional[WayName], reason: str
    1881 1889
     
    
    1882 1890
     def framework_warn(name: TestName, way: WayName, reason: str) -> None:
    
    1883 1891
         opts = getTestOpts()
    
    1884
    -    directory = str_removeprefix(str_removeprefix(str(opts.testdir), './'), '.\\')
    
    1892
    +    directory = _result_directory(opts)
    
    1885 1893
         full_name = name + '(' + way + ')'
    
    1886 1894
         if_verbose(1, '*** framework warning for %s %s ' % (full_name, reason))
    
    1887 1895
         t.framework_warnings.append(TestResult(directory, name, reason, way))
    
    ... ... @@ -3531,17 +3539,17 @@ def summary(t: TestRun, file: TextIO, color=False, junit_path: Optional[Path]=No
    3531 3539
     
    
    3532 3540
         file.write('\n')
    
    3533 3541
     
    
    3542
    +    too_many_failures = len(t.unexpected_failures) > MAX_SUMMARY_OUTPUT_TESTS
    
    3543
    +
    
    3534 3544
         if t.unexpected_failures:
    
    3535
    -        if len(t.unexpected_failures) > MAX_SUMMARY_OUTPUT_TESTS:
    
    3536
    -            # junit.xml only exists when a path was requested (e.g. in CI); don't
    
    3537
    -            # point at a file that a local run never wrote.
    
    3538
    -            where = 'see {}'.format(junit_path) if junit_path \
    
    3539
    -                else 'rerun them individually'
    
    3540
    -            file.write('Output of {} unexpected failures omitted (limit {}); {}.\n\n'
    
    3541
    -                       .format(len(t.unexpected_failures), MAX_SUMMARY_OUTPUT_TESTS, where))
    
    3542
    -        else:
    
    3545
    +        if not too_many_failures:
    
    3543 3546
                 file.write('Output of unexpected failures:\n\n')
    
    3544 3547
                 printTestOutputSummary(file, t.unexpected_failures, color, junit_path)
    
    3548
    +        else:
    
    3549
    +            where = '; see {}'.format(junit_path) if junit_path else ''
    
    3550
    +            file.write('Unexpected failures (output omitted, more than {}{}):\n'
    
    3551
    +                       .format(MAX_SUMMARY_OUTPUT_TESTS, where))
    
    3552
    +            printTestInfosSummary(file, t.unexpected_failures)
    
    3545 3553
     
    
    3546 3554
         printUnexpectedTests(file,
    
    3547 3555
             [t.unexpected_passes, t.unexpected_failures,
    
    ... ... @@ -3593,10 +3601,6 @@ def summary(t: TestRun, file: TextIO, color=False, junit_path: Optional[Path]=No
    3593 3601
             file.write('Unexpected passes:\n')
    
    3594 3602
             printTestInfosSummary(file, t.unexpected_passes)
    
    3595 3603
     
    
    3596
    -    if t.unexpected_failures:
    
    3597
    -        file.write('Unexpected failures:\n')
    
    3598
    -        printTestInfosSummary(file, t.unexpected_failures)
    
    3599
    -
    
    3600 3604
         if t.unexpected_stat_failures:
    
    3601 3605
             file.write('Unexpected stat failures:\n')
    
    3602 3606
             printTestInfosSummary(file, t.unexpected_stat_failures)
    
    ... ... @@ -3634,8 +3638,15 @@ def printTestOutputSummary(file: TextIO, testInfos, color: bool=False,
    3634 3638
         # Repeat failing tests' captured output in the summary, so one needn't
    
    3635 3639
         # hunt for it earlier in a possibly very long log; see #16720.
    
    3636 3640
         where = ', see {}'.format(junit_path) if junit_path else ''
    
    3637
    -    for result in sorted(testInfos, key=lambda r: (r.testname.lower(), r.way, r.directory)):
    
    3638
    -        header = '=====> {}({}) [{}]'.format(result.testname, result.way, result.reason)
    
    3641
    +    # Tests that fail identically in several ways (e.g. normal and g1) share one
    
    3642
    +    # output block, with the ways collected in the header.
    
    3643
    +    groups = collections.OrderedDict() # type: ignore
    
    3644
    +    for result in sorted(testInfos, key=lambda r: (r.testname.lower(), r.directory, r.way)):
    
    3645
    +        key = (result.testname, result.directory, result.reason, result.stdout, result.stderr)
    
    3646
    +        groups.setdefault(key, (result, []))[1].append(result.way)
    
    3647
    +    for result, ways in groups.values():
    
    3648
    +        header = '=====> {}({}) ({}) [{}]'.format(
    
    3649
    +            result.testname, ', '.join(ways), result.directory + os.sep, result.reason)
    
    3639 3650
             if color:
    
    3640 3651
                 header = colored(Color.RED, header)
    
    3641 3652
             file.write(header + '\n')
    
    ... ... @@ -3654,19 +3665,15 @@ def printTestOutputSummary(file: TextIO, testInfos, color: bool=False,
    3654 3665
                     # cannot represent; replace rather than crash (cf safe_print).
    
    3655 3666
                     enc = getattr(file, 'encoding', None) or 'utf-8'
    
    3656 3667
                     file.write(s.encode(enc, errors='replace').decode(enc))
    
    3657
    -        file.write('\n')
    
    3658 3668
         footer = '<===== end of output of unexpected failures'
    
    3659 3669
         if color:
    
    3660 3670
             footer = colored(Color.RED, footer)
    
    3661 3671
         file.write(footer + '\n\n')
    
    3662 3672
     
    
    3663 3673
     def printTestInfosSummary(file: TextIO, testInfos):
    
    3664
    -    maxDirLen = max(len(tr.directory) for tr in testInfos)
    
    3665 3674
         for result in sorted(testInfos, key=lambda r: (r.testname.lower(), r.way, r.directory)):
    
    3666
    -        directory = result.directory.ljust(maxDirLen)
    
    3667
    -        file.write('   {directory}  {r.testname} [{r.reason}] ({r.way})\n'.format(
    
    3668
    -            r = result,
    
    3669
    -            directory = directory))
    
    3675
    +        path = os.path.join(result.directory, result.testname)
    
    3676
    +        file.write('   {path} [{r.reason}] ({r.way})\n'.format(r=result, path=path))
    
    3670 3677
         file.write('\n')
    
    3671 3678
     
    
    3672 3679
     def modify_lines(s: str, f: Callable[[str], str]) -> str: