1"""Test cases for utils/check-package. 2 3It does not inherit from infra.basetest.BRTest and therefore does not generate 4a logfile. Only when the tests fail there will be output to the console. 5 6The make target ('make check-package') is already used by the job 7'check-package' and won't be tested here. 8""" 9import os 10import subprocess 11import unittest 12 13import infra 14 15 16def call_script(args, env, cwd): 17 """Call a script and return stdout and stderr as lists.""" 18 out, err = subprocess.Popen(args, cwd=cwd, stdout=subprocess.PIPE, 19 stderr=subprocess.PIPE, env=env, 20 universal_newlines=True).communicate() 21 return out.splitlines(), err.splitlines() 22 23 24class TestCheckPackage(unittest.TestCase): 25 """Test the various ways the script can be called. 26 27 The script can be called either using relative path, absolute path or from 28 PATH. 29 30 The files to be checked can be passed as arguments using either relative 31 path or absolute path. 32 33 When in in-tree mode (without -b) some in-tree files and also all 34 out-of-tree files are ignored. 35 36 When in out-tree mode (with -b) the script does generate warnings for these 37 but ignores external.mk. 38 """ 39 40 WITH_EMPTY_PATH = {} 41 WITH_UTILS_IN_PATH = {"PATH": infra.basepath("utils") + ":" + os.environ["PATH"]} 42 relative = [ 43 # base_script base_file rel_script rel_file rel_cwd 44 ["utils/check-package", "package/atop/atop.mk", "./utils/check-package", "package/atop/atop.mk", ""], 45 ["utils/check-package", "package/atop/atop.mk", "./utils/check-package", "./package/atop/atop.mk", ""], 46 ["utils/check-package", "package/atop/atop.mk", "../../utils/check-package", "atop.mk", "package/atop"], 47 ["utils/check-package", "package/atop/atop.mk", "../../utils/check-package", "./atop.mk", "package/atop"], 48 ["utils/check-package", "package/atop/atop.mk", "../utils/check-package", "atop/atop.mk", "package"], 49 ["utils/check-package", "package/atop/atop.mk", "../utils/check-package", "./atop/atop.mk", "package"], 50 ["utils/check-package", "package/atop/Config.in", "./utils/check-package", "package/atop/Config.in", ""], 51 ["utils/check-package", "package/atop/Config.in", "./utils/check-package", "./package/atop/Config.in", ""], 52 ["utils/check-package", "package/atop/Config.in", "../../utils/check-package", "Config.in", "package/atop"], 53 ["utils/check-package", "package/atop/Config.in", "../../utils/check-package", "./Config.in", "package/atop"], 54 ["utils/check-package", "package/atop/Config.in", "../utils/check-package", "atop/Config.in", "package"], 55 ["utils/check-package", "package/atop/Config.in", "../utils/check-package", "./atop/Config.in", "package"]] 56 57 def assert_file_was_processed(self, stderr): 58 """Infer from check-package stderr if at least one file was processed 59 and fail otherwise.""" 60 self.assertIn("lines processed", stderr[0], stderr) 61 processed = int(stderr[0].split()[0]) 62 self.assertGreater(processed, 0) 63 64 def assert_file_was_ignored(self, stderr): 65 """Infer from check-package stderr if no file was processed and fail 66 otherwise.""" 67 self.assertIn("lines processed", stderr[0], stderr) 68 processed = int(stderr[0].split()[0]) 69 self.assertEqual(processed, 0) 70 71 def assert_warnings_generated_for_file(self, stderr): 72 """Infer from check-package stderr if at least one warning was generated 73 and fail otherwise.""" 74 self.assertIn("warnings generated", stderr[1], stderr) 75 generated = int(stderr[1].split()[0]) 76 self.assertGreater(generated, 0) 77 78 def assert_no_warnings_generated_for_file(self, stderr): 79 """Infer from check-package stderr if no warning was generated and fail otherwise.""" 80 self.assertIn("warnings generated", stderr[1], stderr) 81 generated = int(stderr[1].split()[0]) 82 self.assertEqual(generated, 0) 83 84 def test_run(self): 85 """Test the various ways the script can be called in a simple top to 86 bottom sequence.""" 87 # an intree file can be checked by the script called from relative path, 88 # absolute path and from PATH 89 for base_script, base_file, rel_script, rel_file, rel_cwd in self.relative: 90 abs_script = infra.basepath(base_script) 91 abs_file = infra.basepath(base_file) 92 cwd = infra.basepath(rel_cwd) 93 94 _, m = call_script([rel_script, rel_file], 95 self.WITH_EMPTY_PATH, cwd) 96 self.assert_file_was_processed(m) 97 98 _, m = call_script([abs_script, rel_file], 99 self.WITH_EMPTY_PATH, cwd) 100 self.assert_file_was_processed(m) 101 102 _, m = call_script(["check-package", rel_file], 103 self.WITH_UTILS_IN_PATH, cwd) 104 self.assert_file_was_processed(m) 105 106 _, m = call_script([rel_script, abs_file], 107 self.WITH_EMPTY_PATH, cwd) 108 self.assert_file_was_processed(m) 109 110 _, m = call_script([abs_script, abs_file], 111 self.WITH_EMPTY_PATH, cwd) 112 self.assert_file_was_processed(m) 113 114 _, m = call_script(["check-package", abs_file], 115 self.WITH_UTILS_IN_PATH, cwd) 116 self.assert_file_was_processed(m) 117 118 # some intree files are ignored 119 _, m = call_script(["./utils/check-package", "package/pkg-generic.mk"], 120 self.WITH_EMPTY_PATH, infra.basepath()) 121 self.assert_file_was_ignored(m) 122 123 _, m = call_script(["./utils/check-package", "-b", "package/pkg-generic.mk"], 124 self.WITH_EMPTY_PATH, infra.basepath()) 125 self.assert_file_was_processed(m) 126 127 # an out-of-tree file can be checked by the script called from relative 128 # path, absolute path and from PATH 129 for base_script, base_file, rel_script, rel_file, rel_cwd in self.relative: 130 abs_script = infra.basepath(base_script) 131 abs_file = infra.basepath(base_file) 132 cwd = infra.basepath(rel_cwd) 133 134 _, m = call_script([rel_script, "-b", rel_file], 135 self.WITH_EMPTY_PATH, cwd) 136 self.assert_file_was_processed(m) 137 138 _, m = call_script([abs_script, "-b", rel_file], 139 self.WITH_EMPTY_PATH, cwd) 140 self.assert_file_was_processed(m) 141 142 _, m = call_script(["check-package", "-b", rel_file], 143 self.WITH_UTILS_IN_PATH, cwd) 144 self.assert_file_was_processed(m) 145 146 _, m = call_script([rel_script, "-b", abs_file], 147 self.WITH_EMPTY_PATH, cwd) 148 self.assert_file_was_processed(m) 149 150 _, m = call_script([abs_script, "-b", abs_file], 151 self.WITH_EMPTY_PATH, cwd) 152 self.assert_file_was_processed(m) 153 154 _, m = call_script(["check-package", "-b", abs_file], 155 self.WITH_UTILS_IN_PATH, cwd) 156 self.assert_file_was_processed(m) 157 158 # out-of-tree files are are ignored without -b but can generate warnings 159 # with -b 160 abs_path = infra.filepath("tests/utils/br2-external") 161 rel_file = "Config.in" 162 abs_file = os.path.join(abs_path, rel_file) 163 164 _, m = call_script(["check-package", rel_file], 165 self.WITH_UTILS_IN_PATH, abs_path) 166 self.assert_file_was_ignored(m) 167 168 _, m = call_script(["check-package", abs_file], 169 self.WITH_UTILS_IN_PATH, infra.basepath()) 170 self.assert_file_was_ignored(m) 171 172 w, m = call_script(["check-package", "-b", rel_file], 173 self.WITH_UTILS_IN_PATH, abs_path) 174 self.assert_file_was_processed(m) 175 self.assert_warnings_generated_for_file(m) 176 self.assertIn("{}:1: empty line at end of file".format(rel_file), w) 177 178 w, m = call_script(["check-package", "-b", abs_file], 179 self.WITH_UTILS_IN_PATH, infra.basepath()) 180 self.assert_file_was_processed(m) 181 self.assert_warnings_generated_for_file(m) 182 self.assertIn("{}:1: empty line at end of file".format(abs_file), w) 183 184 # external.mk is ignored only when in the root path of a br2-external 185 rel_file = "external.mk" 186 abs_file = os.path.join(abs_path, rel_file) 187 188 _, m = call_script(["check-package", "-b", rel_file], 189 self.WITH_UTILS_IN_PATH, abs_path) 190 self.assert_file_was_ignored(m) 191 192 _, m = call_script(["check-package", "-b", abs_file], 193 self.WITH_UTILS_IN_PATH, infra.basepath()) 194 self.assert_file_was_ignored(m) 195 196 abs_path = infra.filepath("tests/utils/br2-external/package/external") 197 abs_file = os.path.join(abs_path, rel_file) 198 199 w, m = call_script(["check-package", "-b", rel_file], 200 self.WITH_UTILS_IN_PATH, abs_path) 201 self.assert_file_was_processed(m) 202 self.assert_warnings_generated_for_file(m) 203 self.assertIn("{}:1: should be 80 hashes (https://nightly.buildroot.org/#writing-rules-mk)".format(rel_file), w) 204 205 w, m = call_script(["check-package", "-b", abs_file], 206 self.WITH_UTILS_IN_PATH, infra.basepath()) 207 self.assert_file_was_processed(m) 208 self.assert_warnings_generated_for_file(m) 209 self.assertIn("{}:1: should be 80 hashes (https://nightly.buildroot.org/#writing-rules-mk)".format(abs_file), w) 210 211 # br2-external with ignore list 212 topdir_path = infra.filepath("tests/utils/br2-external") 213 topdir_file = os.path.join(topdir_path, "package/external/external.mk") 214 subdir_path = infra.filepath("tests/utils/br2-external/package") 215 subdir_file = os.path.join(subdir_path, "external/external.mk") 216 217 w, m = call_script(["check-package", "--ignore-list=.checkpackageignore", "-b", topdir_file], 218 self.WITH_UTILS_IN_PATH, topdir_path) 219 self.assert_file_was_processed(m) 220 self.assert_no_warnings_generated_for_file(m) 221 222 w, m = call_script(["check-package", "--ignore-list=.checkpackageignore", "-b", subdir_file], 223 self.WITH_UTILS_IN_PATH, subdir_path) 224 self.assert_file_was_processed(m) 225 self.assert_no_warnings_generated_for_file(m) 226 227 w, m = call_script(["check-package", "--ignore-list=.checkpackageignore_outdated", "-b", subdir_file], 228 self.WITH_UTILS_IN_PATH, subdir_path) 229 self.assert_file_was_processed(m) 230 self.assert_warnings_generated_for_file(m) 231 self.assertIn("{}:0: Indent was expected to fail, did you fix the file and forget to update .checkpackageignore_outdated?" 232 .format(subdir_file), w) 233 self.assertIn("{}:0: NewlineAtEof was expected to fail, did you fix the file and forget to update " 234 ".checkpackageignore_outdated?" 235 .format(subdir_file), w) 236 237 # shell scripts are tested using shellcheck 238 rel_file = "utils/x-shellscript" 239 abs_path = infra.filepath("tests/utils/br2-external") 240 abs_file = os.path.join(abs_path, rel_file) 241 242 w, m = call_script(["check-package", "-b", rel_file], 243 self.WITH_UTILS_IN_PATH, abs_path) 244 self.assert_file_was_processed(m) 245 self.assert_warnings_generated_for_file(m) 246 self.assertIn("{}:0: run 'shellcheck' and fix the warnings".format(rel_file), w) 247 248 w, m = call_script(["check-package", "-b", abs_file], 249 self.WITH_UTILS_IN_PATH, infra.basepath()) 250 self.assert_file_was_processed(m) 251 self.assert_warnings_generated_for_file(m) 252 self.assertIn("{}:0: run 'shellcheck' and fix the warnings".format(abs_file), w) 253 254 # python scripts are tested using flake8 255 rel_file = "utils/x-python" 256 abs_path = infra.filepath("tests/utils/br2-external") 257 abs_file = os.path.join(abs_path, rel_file) 258 259 w, m = call_script(["check-package", "-vvv", "-b", rel_file], 260 self.WITH_UTILS_IN_PATH, abs_path) 261 self.assert_file_was_processed(m) 262 self.assert_warnings_generated_for_file(m) 263 self.assertIn("{}:0: run 'flake8' and fix the warnings".format(rel_file), w) 264 265 w, m = call_script(["check-package", "-b", abs_file], 266 self.WITH_UTILS_IN_PATH, infra.basepath()) 267 self.assert_file_was_processed(m) 268 self.assert_warnings_generated_for_file(m) 269 self.assertIn("{}:0: run 'flake8' and fix the warnings".format(abs_file), w) 270