• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2
3# Copyright © 2024 Valve Corporation
4# SPDX-License-Identifier: MIT
5
6import argparse
7import collections
8import subprocess
9import os
10import re
11import sys
12import tempfile
13import textwrap
14from pathlib import Path
15
16class TestFileChange:
17    def __init__(self, line, result):
18        self.line = line
19        self.result = result
20
21class TestFileChanges:
22    def __init__(self, name):
23        self.name = name
24        self.changes = []
25
26if __name__ == '__main__':
27    parser = argparse.ArgumentParser()
28    parser.add_argument('--build-dir', '-B', required=False)
29    parser.add_argument('--test-filter', '-f', required=False)
30    parser.add_argument('--update-all', '-u', action='store_true')
31    args = parser.parse_args()
32
33    bin_path = 'src/compiler/nir/nir_tests'
34    if args.build_dir:
35        bin_path = args.build_dir + '/' + bin_path
36
37    if not os.path.isfile(bin_path):
38        print(f'{bin_path} \033[91m does not exist!\033[0m')
39        exit(1)
40
41    build_args = ['meson', 'compile']
42    if args.build_dir:
43        build_args.append(f'-C{args.build_dir}')
44    subprocess.run(build_args)
45
46    test_args = [bin_path]
47    if args.test_filter:
48        test_args.append(f'--gtest_filter={args.test_filter}')
49
50    env = os.environ.copy()
51    if args.update_all:
52        env['NIR_TEST_DUMP_SHADERS'] = 'true'
53
54    output = subprocess.run(test_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, env=env)
55
56    expected_pattern = re.compile(r'Expected \(([\d\w\W/.-_]+):(\d+)\):')
57
58    test_result = None
59    expectations = collections.defaultdict(list)
60
61    # Parse the output of the test binary and gather the changed shaders.
62    for output_line in output.stdout.split('\n'):
63        if output_line.startswith('Got:'):
64            test_result = ''
65
66            continue
67
68        if output_line.startswith('Expected ('):
69            match = expected_pattern.match(output_line)
70            file = match.group(1).removeprefix('../')
71            line = int(match.group(2))
72
73            expectations[file].append(TestFileChange(line, test_result.strip()))
74
75            test_result = None
76
77            continue
78
79        if test_result is not None:
80            test_result += output_line + '\n'
81
82    patches = []
83
84    # Generate patches for the changed shaders.
85    for file in expectations:
86        changes = expectations[file]
87
88        updated_test_file = ''
89        change_index = 0
90        line_index = 1
91        inside_expectation = False
92
93        with open(file) as test_file:
94            for test_line in test_file:
95                if test_line.strip().startswith(')\"'):
96                    inside_expectation = False
97
98                if not inside_expectation:
99                    updated_test_file += test_line
100
101                if change_index < len(changes) and line_index == changes[change_index].line:
102                    inside_expectation = True
103                    indentation = len(test_line) - len(test_line.lstrip()) + 3
104                    updated_test_file += textwrap.indent(changes[change_index].result, " " * indentation) + '\n'
105                    change_index += 1
106
107                line_index += 1
108
109        with tempfile.NamedTemporaryFile(delete_on_close=False) as tmp:
110            tmp.write(bytes(updated_test_file, encoding="utf-8"))
111            tmp.close()
112
113            diff = subprocess.run(
114                ['git', 'diff', '--no-index', file, tmp.name],
115                stdout=subprocess.PIPE,
116                stderr=subprocess.STDOUT,
117                universal_newlines=True,
118            )
119            patch = diff.stdout.replace(tmp.name, '/' + file)
120
121            print(patch)
122
123            patches.append(patch)
124
125    if len(patches) != 0:
126        sys.stdout.write('\033[96mApply the changes listed above?\033[0m [Y/n]')
127        response = None
128        try:
129            response = input()
130        except KeyboardInterrupt:
131            print()
132            sys.exit(1)
133
134        if response in ['', 'y', 'Y']:
135            for patch in patches:
136                apply = subprocess.Popen(
137                    ['git', 'apply', '--allow-empty'],
138                    stdin=subprocess.PIPE,
139                )
140                apply.communicate(input=bytes(patch, encoding="utf-8"))
141