1# Copyright 2024 The Pigweed Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); you may not 4# use this file except in compliance with the License. You may obtain a copy of 5# the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# License for the specific language governing permissions and limitations under 13# the License. 14"""Tests for GN's built-in formatter.""" 15 16import importlib.resources 17from pathlib import Path 18from tempfile import TemporaryDirectory 19import unittest 20 21from format_testing_utils import CapturingToolRunner 22from pw_presubmit.format.gn import GnFormatter 23 24 25_TEST_DATA_FILES = importlib.resources.files('pw_presubmit.format.test_data') 26_TEST_SRC_FILE = _TEST_DATA_FILES / 'gn_test_data.gn' 27_TEST_GOLDEN = _TEST_DATA_FILES / 'gn_test_data_golden.gn' 28_TEST_MALFORMED = _TEST_DATA_FILES / 'malformed_file.txt' 29 30 31class TestGnFormatter(unittest.TestCase): 32 """Tests for the GnFormatter.""" 33 34 def test_check_file(self): 35 tool_runner = CapturingToolRunner() 36 formatter = GnFormatter() 37 formatter.run_tool = tool_runner 38 39 result = formatter.format_file_in_memory( 40 _TEST_SRC_FILE, _TEST_SRC_FILE.read_bytes() 41 ) 42 self.assertTrue(result.ok) 43 self.assertEqual(result.error_message, None) 44 self.assertMultiLineEqual( 45 result.formatted_file_contents.decode(), _TEST_GOLDEN.read_text() 46 ) 47 48 self.assertEqual( 49 tool_runner.command_history.pop(0), 50 ' '.join( 51 ( 52 'gn', 53 'format', 54 '--stdin', 55 ) 56 ), 57 ) 58 59 def test_check_file_error(self): 60 tool_runner = CapturingToolRunner() 61 formatter = GnFormatter() 62 formatter.run_tool = tool_runner 63 64 result = formatter.format_file_in_memory( 65 _TEST_MALFORMED, _TEST_MALFORMED.read_bytes() 66 ) 67 self.assertFalse(result.ok) 68 self.assertTrue(result.error_message.startswith('ERROR at')) 69 self.assertTrue('Invalid token' in result.error_message) 70 self.assertEqual(result.formatted_file_contents, b'') 71 72 self.assertEqual( 73 tool_runner.command_history.pop(0), 74 ' '.join( 75 ( 76 'gn', 77 'format', 78 '--stdin', 79 ) 80 ), 81 ) 82 83 def test_fix_file(self): 84 """Tests that formatting is properly applied to files.""" 85 86 tool_runner = CapturingToolRunner() 87 formatter = GnFormatter() 88 formatter.run_tool = tool_runner 89 90 with TemporaryDirectory() as temp_dir: 91 file_to_fix = Path(temp_dir) / _TEST_SRC_FILE.name 92 file_to_fix.write_bytes(_TEST_SRC_FILE.read_bytes()) 93 94 malformed_file = Path(temp_dir) / _TEST_MALFORMED.name 95 malformed_file.write_bytes(_TEST_MALFORMED.read_bytes()) 96 97 errors = list(formatter.format_files([file_to_fix, malformed_file])) 98 99 # Should see three separate commands, one where we try to format 100 # both files together, and then the fallback logic that formats 101 # them individually to isolate errors. 102 self.assertEqual( 103 tool_runner.command_history.pop(0), 104 ' '.join( 105 ( 106 'gn', 107 'format', 108 str(file_to_fix), 109 str(malformed_file), 110 ) 111 ), 112 ) 113 114 self.assertEqual( 115 tool_runner.command_history.pop(0), 116 ' '.join( 117 ( 118 'gn', 119 'format', 120 str(file_to_fix), 121 ) 122 ), 123 ) 124 125 self.assertEqual( 126 tool_runner.command_history.pop(0), 127 ' '.join( 128 ( 129 'gn', 130 'format', 131 str(malformed_file), 132 ) 133 ), 134 ) 135 136 # Check good build file. 137 self.assertMultiLineEqual( 138 file_to_fix.read_text(), _TEST_GOLDEN.read_text() 139 ) 140 141 # Check malformed file. 142 self.assertEqual(len(errors), 1) 143 malformed_files = [malformed_file] 144 for file_path, error in errors: 145 self.assertIn(file_path, malformed_files) 146 self.assertFalse(error.ok) 147 self.assertTrue(error.error_message.startswith('ERROR at')) 148 149 150if __name__ == '__main__': 151 unittest.main() 152