You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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