okami.mom/albedo
git clone https://git.nkp.pet/okami.mom/albedo
9b3df98
main
1"""Empty test selections must fail before the gate can report success. 2 3Application E2E cannot detect deleted test methods or runner discovery errors. 4Use temporary suites and the real runner processes, without starting a daemon. 5""" 6 7import os 8from pathlib import Path 9import re 10import subprocess 11import sys 12import tempfile 13import unittest 14 15ROOT = Path (__file__ ).resolve ().parents [2 ] 16 17 18class TestRunnerTests (unittest .TestCase ): 19def test_the_timed_modules_the_gleam_runner_runs_alone_still_exist (self ): 20# The runner skips a name it does not find, so a renamed module would 21# quietly rejoin the parallel burst whose load its windows cannot take. 22source = (ROOT / "test/albedo_test_runner.erl" ).read_text () 23match = re .search (r"-define\(TIMED, \[(.*?)\]\)" ,source ,re .S ) 24assert match ,"the runner no longer names its timed modules" 25names = re .findall (r"'([^']+)'" ,match .group (1 )) 26self .assertTrue (names ) 27for name in names : 28with self .subTest (name ): 29path = ROOT / "test" / (name .replace ("@" ,"/" )+ ".gleam" ) 30self .assertTrue (path .is_file (),f" { path } no longer exists" ) 31 32def test_python_runner_rejects_empty_files_and_preserves_failure_exit (self ): 33with tempfile .TemporaryDirectory ()as directory : 34path = Path (directory )/ "example_test.py" 35for source ,successful ,message in [ 36 ("import unittest\n" ,False ,"no tests collected" ), 37 ( 38"import unittest\nclass Example(unittest.TestCase):\n" 39" def test_works(self): self.assertTrue(True)\n" , 40True , 41"Ran 1 test" , 42 ), 43 ( 44"import unittest\nclass Example(unittest.TestCase):\n" 45" def test_fails(self): self.fail('fixture failure')\n" , 46False , 47"fixture failure" , 48 ), 49 ]: 50with self .subTest (source = source ): 51path .write_text (source ) 52result = subprocess .run ( 53 [ 54sys .executable , 55str (ROOT / "test/python_test_runner.py" ), 56str (path ), 57 ], 58capture_output = True , 59text = True , 60timeout = 15 , 61 ) 62self .assertEqual (result .returncode == 0 ,successful ,result .stderr ) 63self .assertIn (message ,result .stderr ) 64 65def test_e2e_rejects_empty_file_among_valid_files_and_empty_aggregate (self ): 66script = """ 67import sys, unittest 68from pathlib import Path 69sys.path.insert(0, str(Path('test/e2e').resolve())) 70import run 71root = Path(sys.argv[1]) 72valid = root / 'valid_test.py' 73suite = run.suite_for(valid, 'Example.test_works') 74assert suite.countTestCases() == 1 75assert unittest.TextTestRunner().run(suite).wasSuccessful() 76for collect in [ 77lambda: unittest.TestSuite(run.suite_for(p) for p in sorted(root.glob('*_test.py'))), 78lambda: run.run_suite(unittest.TestSuite(), 1, 1), 79]: 80try: 81collect() 82except ValueError as error: 83assert 'no ' in str(error) and 'tests collected' in str(error), str(error) 84else: 85raise AssertionError('empty selection passed') 86""" 87with tempfile .TemporaryDirectory ()as directory : 88root = Path (directory ) 89 (root / "empty_test.py" ).write_text ("import unittest\n" ) 90 (root / "valid_test.py" ).write_text ( 91"import unittest\nclass Example(unittest.TestCase):\n" 92" def test_works(self): pass\n" 93 ) 94result = subprocess .run ( 95 [sys .executable ,"-c" ,script ,directory ], 96cwd = ROOT , 97capture_output = True , 98text = True , 99timeout = 15 , 100 ) 101self .assertEqual (result .returncode ,0 ,result .stdout + result .stderr ) 102 103def test_erlang_runner_requires_test_exports_but_ignores_support (self ): 104with tempfile .TemporaryDirectory ()as directory : 105root = Path (directory ) 106tests = root / "test" 107tests .mkdir () 108sources = [ 109ROOT / "test/albedo_test_runner.erl" , 110ROOT / "test/albedo_test_home.erl" , 111 ] 112subprocess .run ( 113 ["erlc" ,"-Werror" ,"-o" ,directory ,* map (str ,sources )], 114check = True , 115timeout = 30 , 116 ) 117for source ,successful ,message in [ 118 (None ,False ,"no_test_modules" ), 119 ( 120"-module(example_test).\n-export([helper/0]).\nhelper() -> ok.\n" , 121False , 122"no_tests_in_module" , 123 ), 124 ( 125'-module(example_test).\n-include_lib("eunit/include/eunit.hrl").\n' 126"ordinary_test() -> ?assert(true).\n" 127"generated_test_() -> [?_assert(true)].\n" , 128True , 129"" , 130 ), 131 ]: 132with self .subTest (source = source ): 133if source is not None : 134path = tests / "example_test.erl" 135path .write_text (source ) 136subprocess .run ( 137 ["erlc" ,"-Werror" ,"-o" ,directory ,str (path )], 138check = True , 139timeout = 30 , 140 ) 141 (tests / "fixture.erl" ).write_text ( 142"intentionally not a compiled test module\n" 143 ) 144# The actual Gleam entrypoint and fixtures must be excluded. 145 (tests / "albedo_test.gleam" ).write_text ("pub fn main() { Nil }\n" ) 146paths = [directory ,str (ROOT / "build/dev/erlang/gleeunit/ebin" )] 147result = subprocess .run ( 148 [ 149"erl" , 150"+S" , 151"2:2" , 152"-pa" , 153* paths , 154"-noshell" , 155"-eval" , 156"albedo_test_home:isolate(), albedo_test_runner:main()." , 157 ], 158cwd = root , 159env = {** os .environ ,"ALBEDO_TEST_TMP" :str (root / "scratch" )}, 160capture_output = True , 161text = True , 162timeout = 30 , 163 ) 164self .assertEqual ( 165result .returncode == 0 , 166successful , 167result .stdout + result .stderr , 168 ) 169if message : 170self .assertIn (message ,result .stdout + result .stderr ) 171 172 173if __name__ == "__main__" : 174unittest .main ()