Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
228 changes: 228 additions & 0 deletions test/mason/MasonBashSubTest
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
#!/usr/bin/env python3

import os
import sys
import subprocess as sp
import shutil
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Dict, Optional, List, Iterator, Tuple
import time
import signal

chpl_home = Path(os.environ.get("CHPL_HOME", ""))
if not chpl_home.exists():
sys.stdout.write("[Error: CHPL_HOME not set or does not exist]\n")
sys.exit(1)
sys.path.insert(0, str(chpl_home / "util" / "test"))
import sub_test as sub_test_util

sub_test_util.utildir = str(chpl_home / "util")


def mason() -> Path:
sub_dir = chpl_home / "util" / "chplenv" / "chpl_bin_subdir.py"
result = sp.check_output(
[sys.executable, str(sub_dir), "--host"],
encoding="utf-8",
stderr=sp.STDOUT,
).strip()
return chpl_home / "bin" / result / "mason"


@dataclass
class Test:
"""
The script file describes a series of commands to run
the optional good file contains the expected output of the executable
if no good file is provided, only the exit code of the script is checked
"""

source_file: Path
good_file: Optional[Path] = None

@classmethod
def find_tests(cls, directory: Path) -> Iterator["Test"]:
for f in sorted(directory.glob("*.masontest")):
if test := cls.test_factory(f):
yield test

@classmethod
def test_factory(cls, source_file: Path):
good_file = source_file.with_suffix(".good")
if not good_file.exists():
good_file = None
return cls(source_file, good_file=good_file)

def _compute_env(self) -> Dict[str, str]:
testenv = {}

def parse_env(lines: List[str]) -> Dict[str, str]:
env = {}
for l in lines:
if l.startswith("unset "):
var = l.split(" ", 1)[1]
env[var.strip()] = None
else:
var, val = l.split("=", 1)
env[var.strip()] = val.strip()
return env

EXECENV = self.source_file.parent / "EXECENV"
if EXECENV.exists():
globalExecenv = sub_test_util.ReadFileWithComments(str(EXECENV))
testenv.update(parse_env(globalExecenv))
execenv = self.source_file.with_suffix(".execenv")
if execenv.exists():
testExecenv = sub_test_util.ReadFileWithComments(str(execenv))
testenv.update(parse_env(testExecenv))

return sub_test_util.get_process_env(testenv)

def _execute(self) -> Tuple[Optional[int], Optional[Path]]:
executable = self.source_file

executable_output = self.source_file.with_suffix(".exec.out.tmp")
executable_fp = open(executable_output, "w")

cmd = [str(executable.absolute())]
sys.stdout.write("[Executing program: {}]\n".format(" ".join(cmd)))
sys.stdout.flush()
retcode, stdout, _ = sub_test_util.run_process(
cmd,
stdout=sp.PIPE,
stderr=sp.STDOUT,
env=self._compute_env(),
)
executable_fp.write(stdout)
executable_fp.close()

return retcode, executable_output

def _run_prediff(self, output_file: Path):
PREDIFF = self.source_file.parent / "PREDIFF"
if PREDIFF.exists():
sys.stdout.write("[Executing ./PREDIFF]\n")
sys.stdout.flush()
stdout = sub_test_util.run_process(
[
str(PREDIFF.absolute()),
self.source_file.stem,
str(output_file),
],
stdout=sp.PIPE,
stderr=sp.STDOUT,
)[1]
sys.stdout.write(stdout)
sys.stdout.flush()

prediff = self.source_file.with_suffix(".prediff")
if prediff.exists():
sys.stdout.write(f"[Executing {prediff.name}]\n")
sys.stdout.flush()
stdout = sub_test_util.run_process(
[
str(prediff.absolute()),
self.source_file.stem,
str(output_file),
],
stdout=sp.PIPE,
stderr=sp.STDOUT,
)[1]
sys.stdout.write(stdout)
sys.stdout.flush()

def _compare_output(self, executable_output: Path) -> bool:
# check executable output
self._run_prediff(executable_output)
if (
sub_test_util.DiffFiles(str(self.good_file), str(executable_output))
!= 0
):
sys.stdout.write(
f"[Error matching executable output for {self.source_file.stem}]\n"
)
return False
return True

def _cleanup(self, executable_output: Path):
if executable_output.exists():
executable_output.unlink()

def test(self):
start_time = time.time()
sub_test_util.printTestName(self.source_file)
retcode, executable_output = self._execute()
if executable_output is not None:

if retcode != 0:
sys.stdout.write(
"[Error matching output for {} (exited with exit code {})]\n".format(self.source_file.stem, retcode)
)
elif self.good_file is None:
self._cleanup(executable_output)
sys.stdout.write(
"[Success matching output for {}]\n".format(
self.source_file.stem
)
)
else:
if self._compare_output(
executable_output
):
self._cleanup(executable_output)
sys.stdout.write(
"[Success matching output for {}]\n".format(
self.source_file.stem
)
)
elapsed = time.time() - start_time
sub_test_util.printEndOfTestMsg(self.source_file, elapsed)


def dirSkipIf(d: Path):
skipif_file = d / "SKIPIF"
if skipif_file.exists() and os.getenv("CHPL_TEST_SINGLES") == "0":
sys.stdout.write("[Checking SKIPIF]\n")
sys.stdout.flush()
do_not_test = False
try:
skipme = False
skiptest = sub_test_util.runSkipIf(str(skipif_file.name))
if skiptest.strip() != "False":
skipme = skiptest.strip() == "True" or int(skiptest) == 1
if skipme:
sys.stdout.write("[Skipping test based on SKIPIF]\n")
do_not_test = True
except (ValueError, RuntimeError) as e:
sys.stdout.write(str(e) + "\n")
sys.stdout.write("[Error processing SKIPIF file]\n")
do_not_test = True
if do_not_test:
return True
return False


def main():
sub_test_util.printStartOfTestMsg(time.localtime())

d = Path(os.path.dirname(os.path.abspath(__file__)))

if dirSkipIf(d):
return

if not mason().exists():
sys.stdout.write("[Skipping test based on missing mason]\n")

if onetest := os.environ.get("CHPL_ONETEST"):
if t := Test.test_factory(Path(onetest)):
t.test()
else:
for t in Test.find_tests(d):
t.test()

sys.stdout.write("[Finished subtest {}]\n".format(d))


if __name__ == "__main__":
main()
1 change: 1 addition & 0 deletions test/mason/mason-build/CLEANFILES
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*/target
8 changes: 8 additions & 0 deletions test/mason/mason-build/CompflagsBug.masontest
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash

set -exo pipefail

cd CompflagsBug

mason build -- -stestFlagCmdLine=1
mason run -- --testExecFlagCmdLine=bar
1 change: 0 additions & 1 deletion test/mason/mason-build/CompflagsBug/CLEANFILES

This file was deleted.

51 changes: 0 additions & 51 deletions test/mason/mason-build/CompflagsBug/functions.bash

This file was deleted.

1 change: 1 addition & 0 deletions test/mason/mason-build/sub_test
1 change: 1 addition & 0 deletions test/mason/mason-prereq/CLEANFILES
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*/target
1 change: 1 addition & 0 deletions test/mason/mason-prereq/EXECENV
Empty file.
1 change: 0 additions & 1 deletion test/mason/mason-prereq/prereq1/CLEANFILES

This file was deleted.

51 changes: 0 additions & 51 deletions test/mason/mason-prereq/prereq1/functions.bash

This file was deleted.

19 changes: 0 additions & 19 deletions test/mason/mason-prereq/prereq1/sub_test

This file was deleted.

Empty file.
20 changes: 20 additions & 0 deletions test/mason/mason-prereq/prereq2/Mason.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[brick]
name="prereq2"
version="0.1.0"
chplVersion="2.7.0"
license="None"
type="library"
compopts=["-smyParam=2"]

tests = [
"Test.chpl",
]

[examples]
examples = [ "Ex1.chpl", "Ex2.chpl" ]

[examples.Ex2]
compopts = ["-smyParam=3"]

[dependencies]

Loading