1#!/usr/bin/env python3 2 3"""Runs ./ninja and checks if the output is correct. 4 5In order to simulate a smart terminal it uses the 'script' command. 6""" 7 8import os 9import platform 10import subprocess 11import sys 12import tempfile 13import unittest 14 15default_env = dict(os.environ) 16if 'NINJA_STATUS' in default_env: 17 del default_env['NINJA_STATUS'] 18if 'CLICOLOR_FORCE' in default_env: 19 del default_env['CLICOLOR_FORCE'] 20default_env['TERM'] = '' 21NINJA_PATH = os.path.abspath('./ninja') 22 23def run(build_ninja, flags='', pipe=False, env=default_env): 24 with tempfile.TemporaryDirectory() as d: 25 os.chdir(d) 26 with open('build.ninja', 'w') as f: 27 f.write(build_ninja) 28 f.flush() 29 ninja_cmd = '{} {}'.format(NINJA_PATH, flags) 30 try: 31 if pipe: 32 output = subprocess.check_output([ninja_cmd], shell=True, env=env) 33 elif platform.system() == 'Darwin': 34 output = subprocess.check_output(['script', '-q', '/dev/null', 'bash', '-c', ninja_cmd], 35 env=env) 36 else: 37 output = subprocess.check_output(['script', '-qfec', ninja_cmd, '/dev/null'], 38 env=env) 39 except subprocess.CalledProcessError as err: 40 sys.stdout.buffer.write(err.output) 41 raise err 42 final_output = '' 43 for line in output.decode('utf-8').splitlines(True): 44 if len(line) > 0 and line[-1] == '\r': 45 continue 46 final_output += line.replace('\r', '') 47 return final_output 48 49@unittest.skipIf(platform.system() == 'Windows', 'These test methods do not work on Windows') 50class Output(unittest.TestCase): 51 def test_issue_1418(self): 52 self.assertEqual(run( 53'''rule echo 54 command = sleep $delay && echo $out 55 description = echo $out 56 57build a: echo 58 delay = 3 59build b: echo 60 delay = 2 61build c: echo 62 delay = 1 63''', '-j3'), 64'''[1/3] echo c\x1b[K 65c 66[2/3] echo b\x1b[K 67b 68[3/3] echo a\x1b[K 69a 70''') 71 72 def test_issue_1214(self): 73 print_red = '''rule echo 74 command = printf '\x1b[31mred\x1b[0m' 75 description = echo $out 76 77build a: echo 78''' 79 # Only strip color when ninja's output is piped. 80 self.assertEqual(run(print_red), 81'''[1/1] echo a\x1b[K 82\x1b[31mred\x1b[0m 83''') 84 self.assertEqual(run(print_red, pipe=True), 85'''[1/1] echo a 86red 87''') 88 # Even in verbose mode, colors should still only be stripped when piped. 89 self.assertEqual(run(print_red, flags='-v'), 90'''[1/1] printf '\x1b[31mred\x1b[0m' 91\x1b[31mred\x1b[0m 92''') 93 self.assertEqual(run(print_red, flags='-v', pipe=True), 94'''[1/1] printf '\x1b[31mred\x1b[0m' 95red 96''') 97 98 # CLICOLOR_FORCE=1 can be used to disable escape code stripping. 99 env = default_env.copy() 100 env['CLICOLOR_FORCE'] = '1' 101 self.assertEqual(run(print_red, pipe=True, env=env), 102'''[1/1] echo a 103\x1b[31mred\x1b[0m 104''') 105 106 def test_pr_1685(self): 107 # Running those tools without .ninja_deps and .ninja_log shouldn't fail. 108 self.assertEqual(run('', flags='-t recompact'), '') 109 self.assertEqual(run('', flags='-t restat'), '') 110 111 def test_status(self): 112 self.assertEqual(run(''), 'ninja: no work to do.\n') 113 114if __name__ == '__main__': 115 unittest.main() 116