Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

155 lines
3.8KB

  1. #!/usr/bin/env python3
  2. import argparse
  3. from pathlib import Path
  4. from typing import List, NamedTuple
  5. import shutil
  6. import subprocess
  7. import sys
  8. ROOT = Path(__file__).parent.parent.absolute()
  9. class TestOptions(NamedTuple):
  10. exe: Path
  11. toolchain: str
  12. def run_test_dir(dir: Path, opts: TestOptions) -> bool:
  13. fails = 0
  14. fails += _run_subproc_test(
  15. dir,
  16. opts,
  17. 'Full Build',
  18. 'build',
  19. '--full',
  20. f'--toolchain={opts.toolchain}',
  21. )
  22. fails += _run_subproc_test(
  23. dir,
  24. opts,
  25. 'Source Distribution',
  26. 'sdist',
  27. f'--out=_build/{dir.stem}/test.dsd',
  28. '--force',
  29. )
  30. return fails == 0
  31. def _run_subproc_test(dir: Path, opts: TestOptions, name: str,
  32. *args: str) -> int:
  33. print(f'Running test: {dir.stem} - {name} ', end='')
  34. out_dir = dir / '_build'
  35. if out_dir.exists():
  36. shutil.rmtree(out_dir)
  37. res = subprocess.run(
  38. [
  39. str(opts.exe),
  40. ] + list(str(s) for s in args),
  41. cwd=dir,
  42. stdout=subprocess.PIPE,
  43. stderr=subprocess.STDOUT,
  44. )
  45. if res.returncode != 0:
  46. print('- FAILED')
  47. print(f'Test failed with exit code '
  48. f'[{res.returncode}]:\n{res.stdout.decode()}')
  49. return 1
  50. print('- PASSED')
  51. return 0
  52. def _run_build_test(dir: Path, opts: TestOptions) -> int:
  53. print(f'Running test: {dir.stem} - build', end='')
  54. out_dir = dir / '_build'
  55. if out_dir.exists():
  56. shutil.rmtree(out_dir)
  57. res = subprocess.run(
  58. [
  59. str(opts.exe),
  60. 'build',
  61. '--export',
  62. '--warnings',
  63. '--tests',
  64. '--full',
  65. f'--toolchain={opts.toolchain}',
  66. f'--out={out_dir}',
  67. f'--export-name={dir.stem}',
  68. ],
  69. cwd=dir,
  70. stdout=subprocess.PIPE,
  71. stderr=subprocess.STDOUT,
  72. )
  73. if res.returncode != 0:
  74. print('- FAILED')
  75. print(f'Test failed with exit code '
  76. f'[{res.returncode}]:\n{res.stdout.decode()}')
  77. return 1
  78. print('- PASSED')
  79. return 0
  80. def run_tests(opts: TestOptions) -> int:
  81. print('Sanity check...')
  82. subprocess.check_output([str(opts.exe), '--help'])
  83. tests_subdir = ROOT / 'tests'
  84. test_dirs = tests_subdir.glob('*.test')
  85. ret = 0
  86. for td in test_dirs:
  87. if not run_test_dir(td, opts):
  88. ret = 1
  89. return ret
  90. def bootstrap_self(opts: TestOptions):
  91. # Copy the exe to another location, as windows refuses to let a binary be
  92. # replaced while it is executing
  93. new_exe = ROOT / '_ddslime.bootstrap-test.exe'
  94. shutil.copy2(opts.exe, new_exe)
  95. res = subprocess.run([
  96. str(new_exe),
  97. 'build',
  98. f'-FT{opts.toolchain}',
  99. ])
  100. new_exe.unlink()
  101. if res.returncode != 0:
  102. print('The bootstrap test failed!', file=sys.stderr)
  103. return False
  104. print('Bootstrap test PASSED!')
  105. return True
  106. def main(argv: List[str]) -> int:
  107. parser = argparse.ArgumentParser()
  108. parser.add_argument(
  109. '--exe',
  110. '-e',
  111. help='Path to the ddslim executable to test',
  112. required=True)
  113. parser.add_argument(
  114. '--toolchain',
  115. '-T',
  116. help='The ddslim toolchain to use while testing',
  117. required=True,
  118. )
  119. parser.add_argument(
  120. '--skip-bootstrap-test',
  121. action='store_true',
  122. help='Skip the self-bootstrap test',
  123. )
  124. args = parser.parse_args(argv)
  125. tc = args.toolchain
  126. if not tc.startswith(':'):
  127. tc = Path(tc).absolute()
  128. opts = TestOptions(exe=Path(args.exe).absolute(), toolchain=tc)
  129. if not args.skip_bootstrap_test and not bootstrap_self(opts):
  130. return 2
  131. return run_tests(opts)
  132. if __name__ == "__main__":
  133. sys.exit(main(sys.argv[1:]))