1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
needs "packages.m2"
needs "code.m2"
needs "run.m2"
-----------------------------------------------------------------------------
-- Local utilities
-----------------------------------------------------------------------------
sourceFileStamp = (filename, linenum) -> concatenate(
"--", toAbsolutePath filename, ":", toString linenum, ": location of test code")
-----------------------------------------------------------------------------
-- TestInput
-----------------------------------------------------------------------------
TestInput = new SelfInitializingType of HashTable
new TestInput from Sequence := (T, S) -> TestInput {
"filename" => S_0,
"line number" => S_1,
"code" => concatenate(sourceFileStamp(S_0, S_1), newline, S_2)}
TestInput.synonym = "test input"
code TestInput := T -> T#"code"
locate TestInput := T -> (T#"filename",
T#"line number" - depth net code T, 1,
T#"line number", 1,,)
toString TestInput := T -> (
loc := locate T;
loc#0 | ":" | loc#1 | ":" | loc#2 | "-" | loc#3 | ":" | loc#4 | ":"
)
net TestInput := T -> (toString T)^-1
editMethod TestInput := EDIT @@ locate
-----------------------------------------------------------------------------
-- TEST
-----------------------------------------------------------------------------
TEST = method(Options => {FileName => false})
TEST List := opts -> testlist -> apply(testlist, test -> TEST(test, opts))
TEST String := opts -> teststring -> (
n := currentPackage#"test number";
currentPackage#"test inputs"#n = TestInput if opts.FileName then (
testCode := get teststring;
(minimizeFilename teststring, depth net testCode + 1, testCode)
) else
(minimizeFilename currentFileName, currentRowNumber(), teststring);
currentPackage#"test number" = n + 1;)
-- TODO: support test titles
TEST(String, String) := (title, teststring) -> (
n := currentPackage#"test number"; () -> check(n - 1, currentPackage))
-----------------------------------------------------------------------------
-- check
-----------------------------------------------------------------------------
checkmsg := (verb, desc) ->
stderr << commentize pad(pad(verb, 10) | desc, 72) << flush;
captureTestResult := (desc, teststring, pkg, usermode) -> (
stdio << flush; -- just in case previous timing information hasn't been flushed yet
if match("no-check-flag", teststring) then (
checkmsg("skipping", desc);
return true);
if (m := regex("(?<=no-check-architecture:)[^(\\n]*", teststring)) =!= null
then (
badarchs := apply(separate(", ", substring(m#0, teststring)),
s -> replace("^\\s*|\\s*$", "", s));
if member(version#"architecture", badarchs) then (
checkmsg("skipping", desc);
return true));
-- TODO: remove this when capture uses ArgQ
if usermode === not noinitfile then
-- try capturing in the same process
if isCapturable(teststring, pkg, true) then (
checkmsg("capturing", desc);
-- TODO: adjust and pass argumentMode, instead. This can be done earlier, too.
-- Note: UserMode option of capture is not related to UserMode option of check
(err, output) := capture(teststring, PackageExports => pkg, UserMode => false);
if err then printerr "capture failed; retrying ..." else return true);
-- fallback to using an external process
checkmsg("running", desc);
runString(teststring, pkg, usermode))
loadTestDir := pkg -> (
-- TODO: prioritize reading the tests from topSrcdir | "Macaulay2/tests/normal" instead
testDir := pkg#"package prefix" |
replace("PKG", pkg#"pkgname", currentLayout#"packagetests");
pkg#"test directory loaded" =
if fileExists testDir then (
tmp := currentPackage;
currentPackage = pkg;
TEST(sort apply(select(readDirectory testDir, file ->
match("\\.m2$", file)), test -> testDir | test),
FileName => true);
currentPackage = tmp;
true) else false)
tests = method()
tests Package := pkg -> (
if not pkg#?"test directory loaded" then loadTestDir pkg;
if pkg#?"documentation not loaded" then pkg = loadPackage(pkg#"pkgname", LoadDocumentation => true, Reload => true);
previousMethodsFound = new HashTable from pkg#"test inputs"
)
tests String := pkg -> tests needsPackage(pkg, LoadDocumentation => true)
check = method(Options => {UserMode => null, Verbose => false})
check String :=
check Package := opts -> pkg -> check({}, pkg, opts)
check(ZZ, String) :=
check(ZZ, Package) := opts -> (n, pkg) -> check({n}, pkg, opts)
check(List, String) := opts -> (L, pkg) -> check(L, needsPackage (pkg, LoadDocumentation => true), opts)
check(List, Package) := opts -> (L, pkg) -> (
if not pkg.Options.OptionalComponentsPresent then (
printerr("warning: skipping tests; ", toString pkg, " requires optional components"); return);
usermode := if opts.UserMode === null then not noinitfile else opts.UserMode;
--
use pkg;
tmp := previousMethodsFound;
inputs := tests pkg;
previousMethodsFound = tmp;
testKeys := if L == {} then keys inputs else L;
if #testKeys == 0 then printerr("warning: ", toString pkg, " has no tests");
--
errorList := for k in testKeys list (
if not inputs#?k then error(pkg, " has no test #", k);
teststring := code inputs#k;
desc := "check(" | toString k | ", " | format pkg#"pkgname" | ")";
ret := elapsedTime captureTestResult(desc, teststring, pkg, usermode);
if not ret then (k, temporaryFilenameCounter - 2) else continue);
outfile := errfile -> temporaryDirectory() | errfile | ".tmp";
if #errorList > 0 then (
if opts.Verbose then apply(errorList, (k, errfile) -> (
stderr << toString inputs#k << " error:" << endl;
printerr getErrors(outfile errfile)));
error("test(s) #", demark(", ", toString \ first \ errorList), " of package ", toString pkg, " failed.")))
checkAllPackages = () -> (
tmp := argumentMode;
argumentMode = defaultMode - SetCaptureErr - SetUlimit -
if noinitfile then 0 else ArgQ;
fails := for pkg in sort separate(" ", version#"packages") list (
stderr << HEADER1 pkg << endl;
if runString("check(" | format pkg | ", Verbose => true)",
Core, false) then continue else pkg) do stderr << endl;
argumentMode = tmp;
if #fails > 0 then printerr("package(s) with failing tests: ",
demark(", ", fails));
#fails)
|