Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a list instead of a hash table for storing package tests #3419

Merged
merged 14 commits into from
Sep 2, 2024
Merged
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
1 change: 1 addition & 0 deletions M2/Macaulay2/d/binding.d
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ bumpPrecedence();
export elapsedTimeS := special("elapsedTime",unaryop,precSpace,wide);
export elapsedTimingS := special("elapsedTiming",unaryop,precSpace,wide);
export shieldS := special("shield",unaryop,precSpace,wide);
export TestS := special("TEST",unaryop,precSpace,wide);
export throwS := special("throw",nunaryop,precSpace,wide);
export returnS := special("return",nunaryop,precSpace,wide);
export breakS := special("break",nunaryop,precSpace,wide);
Expand Down
2 changes: 1 addition & 1 deletion M2/Macaulay2/d/debugging.dd
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ setupfun("pseudocode", pseudocode);
export filePositionClass := newHashTableWithHash(typeClass, basicListClass);
setupconst("FilePosition", Expr(filePositionClass));

locate(p:Position):Expr := (
export locate(p:Position):Expr := (
if p == dummyPosition || p == tempPosition
then nullE
else Expr(sethash(List(filePositionClass,
Expand Down
8 changes: 8 additions & 0 deletions M2/Macaulay2/d/evaluate.d
Original file line number Diff line number Diff line change
Expand Up @@ -1663,6 +1663,14 @@ breakFun(a:Code):Expr := (
when e is Error do e else Expr(Error(dummyPosition,breakMessage,e,false,dummyFrame)));
setupop(breakS,breakFun);

addTestS := setupvar("addTest", nullE); -- will be overwritten in testing.m2
testfun(c:Code):Expr := (
r := applyEE(
getGlobalVariable(addTestS),
seq(eval(c), locate(codePosition(c))));
when r is Error do r else nullE);
setupop(TestS, testfun);

assigntofun(lhs:Code,rhs:Code):Expr := (
left := eval(lhs);
when left is Error do return left else (
Expand Down
3 changes: 1 addition & 2 deletions M2/Macaulay2/m2/packages.m2
Original file line number Diff line number Diff line change
Expand Up @@ -339,8 +339,7 @@ newPackage String := opts -> pkgname -> (
"previous currentPackage" => currentPackage,
"previous dictionaries" => dictionaryPath,
"previous packages" => loadedPackages,
"test number" => 0,
"test inputs" => new MutableHashTable,
"test inputs" => new MutableList,
"raw documentation" => new MutableHashTable, -- deposited here by 'document'
"processed documentation" => new MutableHashTable, -- the output from 'documentation', look here first
"example inputs" => new MutableHashTable,
Expand Down
59 changes: 24 additions & 35 deletions M2/Macaulay2/m2/testing.m2
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,36 @@ needs "packages.m2"
needs "code.m2"
needs "run.m2"

-----------------------------------------------------------------------------
-- Local utilities
-----------------------------------------------------------------------------

sourceFileStamp = (filename, linenum) -> toString commentize(
pos := new FilePosition from (toAbsolutePath filename, linenum, 1);
toString pos, ": 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 -> new FilePosition from (T#"filename",
T#"line number" - depth net code T, 1,
T#"line number", 1,,)
toString TestInput := toString @@ locate
net TestInput := T -> "TestInput[" | toString T | "]"
code TestInput := code @@ locate
toString TestInput := T -> T#"code"
locate TestInput := T -> T#"location"
net TestInput := lookup(net, Function)
precedence TestInput := lookup(precedence, Function)
editMethod TestInput := editMethod @@ locate
capture TestInput := opt -> T -> capture(toString T, opt)

-----------------------------------------------------------------------------
-- 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;)
-- TEST is a keyword that takes an object as input and determines its
-- location. It then passes the object and its location to addTest.
addTest = method()
addTest(String, FilePosition) := (str, loc) -> (
n := #currentPackage#"test inputs";
currentPackage#"test inputs"#n = TestInput {
"location" => loc,
"code" => str})
-- the following is not called by TEST, but called directly when we want to
-- add a test from a file (used by loadTestDir)
addTest String := filename -> addTest(get filename,
new FilePosition from(filename, 1, 1))
-- TODO: support test titles

-----------------------------------------------------------------------------
Expand Down Expand Up @@ -77,17 +67,16 @@ loadTestDir := pkg -> (
if fileExists testDir then (
tmp := currentPackage;
currentPackage = pkg;
TEST(sort apply(select(readDirectory testDir, file ->
match("\\.m2$", file)), test -> testDir | test),
FileName => true);
scan(sort select(readDirectory testDir, file -> match("\\.m2$", file)),
test -> addTest(testDir | test));
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"
previousMethodsFound = new NumberedVerticalList from pkg#"test inputs"
)
tests String := pkg -> tests needsPackage(pkg, LoadDocumentation => true)
tests(ZZ, Package) := tests(ZZ, String) := (i, pkg) -> (tests pkg)#i
Expand All @@ -107,19 +96,19 @@ check(List, Package) := opts -> (L, pkg) -> (
tmp := previousMethodsFound;
inputs := tests pkg;
previousMethodsFound = tmp;
testKeys := if L == {} then keys inputs else L;
testKeys := if L == {} then toList(0..#inputs-1) 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;
teststring := inputs#k#"code";
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;
stderr << locate inputs#k << " error:" << endl;
printerr getErrors(outfile errfile)));
error("test(s) #", demark(", ", toString \ first \ errorList), " of package ", toString pkg, " failed.")))

Expand Down
2 changes: 1 addition & 1 deletion M2/Macaulay2/packages/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ set(M2_INSTALL_TEMPLATE [[installPackage("@package@",
DebuggingMode => true)]])
set(M2_NEED_TEMPLATE [[needsPackage("@package@", LoadDocumentation=>true, DebuggingMode=>true)]])
set(M2_TEST_TEMPLATE [[debug Core \; argumentMode = @ArgumentMode@ \; check(@_i@, "@package@")]])
set(M2_INFO_TEMPLATE [["info-"|"@package@" << @package@#"test number" << close]]) # ignore the color
set(M2_INFO_TEMPLATE [["info-"|"@package@" << #@package@#"test inputs" << close]]) # ignore the color
set(M2_CHECK_TEMPLATE [[check("@package@", UserMode=>false, Verbose=>$<IF:$<BOOL:${VERBOSE}>,true,false>)]])

# TODO: simplify
Expand Down
7 changes: 2 additions & 5 deletions M2/Macaulay2/packages/JSON.m2
Original file line number Diff line number Diff line change
Expand Up @@ -358,8 +358,5 @@ for tst in sort select(tsts, f -> match("^y_", f)) do (
close outfile
///

TEST(currentPackage#"source directory" | "JSON/test-parse.m2",
FileName => true)

TEST(currentPackage#"source directory" | "JSON/test-encode.m2",
FileName => true)
TEST get(currentPackage#"auxiliary files" | "test-parse.m2")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading this line, I would be more confused about where to look for that file than before. You can of course go with whatever solution you prefer in your package.

TEST get(currentPackage#"auxiliary files" | "test-encode.m2")
1 change: 1 addition & 0 deletions M2/Macaulay2/packages/LLLBases.m2
Original file line number Diff line number Diff line change
Expand Up @@ -1248,6 +1248,7 @@ TEST ///
TEST
/// -- DON'T TEST YET??
-- no-check-flag (encountered an unknown key or option: Engine)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mikestillman - This test appears to never have been run since TEST and the test string were on separate lines. After changing TEST to a keyword, the test does get run, but it fails because LLL doesn't have an Engine option.

I'm proposing that we continue skipping it for now (which no-check-flag takes care of), but I figured I'd tag you in case you'd like to take a look.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was there an engine implementation that got removed or never got added? Seems strange.

testLLL = (m) -> (
-- Test 1:
remove(m.cache,symbol LLL);
Expand Down
16 changes: 4 additions & 12 deletions M2/Macaulay2/packages/Macaulay2Doc/functions/check-doc.m2
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,13 @@
doc ///
Node
Key
TEST
(TEST, String)
(TEST, List)
[TEST, FileName]
symbol TEST
mahrud marked this conversation as resolved.
Show resolved Hide resolved
Headline
add a test for a package
Usage
TEST s
Inputs
s:String
or list of strings, containing Macaulay2 code
FileName=>Boolean
if true, then @TT "s"@ (or each element of @TT "s"@, if it is a
list) is interpreted as the name of a file containing a test as
opposed to the test itself.
s:String -- containing Macaulay2 code
Consequences
Item
registers the string @TT "s"@ as a test of the @TO2 {"currentPackage", "current package"}@.
Expand Down Expand Up @@ -84,7 +76,7 @@ Node
Description
Text
It is important for package authors to provide tests to ensure that the package is functioning properly.
One provides tests using the @TO TEST@ function following the @TO beginDocumentation@ call in the source
One provides tests using the @TO symbol TEST@ function following the @TO beginDocumentation@ call in the source
of the package.

Optionally, one can store all tests in a @TT "tests.m2"@ directory under the auxiliary subdirectory of
Expand All @@ -109,7 +101,7 @@ Node
SeeAlso
"packages"
"creating a package"
TEST
symbol TEST
installPackage
loadPackage
///
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Node
exportMutable
beginDocumentation
document
TEST
symbol TEST

:Functions useful when debugging a package:
"debugging"
Expand Down
6 changes: 3 additions & 3 deletions M2/Macaulay2/packages/Macaulay2Doc/functions/tests-doc.m2
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ doc ///
i:ZZ
pkg:{Package, String}
Outputs
:{HashTable, TestInput}
:{NumberedVerticalList, TestInput}
Description
Text
Returns @ofClass HashTable@ containing the tests for the given
package. Each key of this hash table is an integer, which would
When an integer is not provided, this returns all the tests
for the given package. The position of each element would
be passed as the first argument of @TO check@ to run the test.
Each value is a @TT "TestInput"@ object. These are printed with
the location of the file so that you may quickly jump to the
Expand Down
2 changes: 1 addition & 1 deletion M2/Macaulay2/packages/Macaulay2Doc/overview_doc.m2
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,6 @@ Node
and @TO "Text :: Text"@.
SeeAlso
installPackage
TEST
symbol TEST
check
///
6 changes: 3 additions & 3 deletions M2/Macaulay2/packages/Macaulay2Doc/overview_packages.m2
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ Node
:a list of exported functions and variables, set via @TO export@ and @TO exportMutable@
:the code that constitutes the package
:the documentation for the package, which comes after @TO beginDocumentation@
:a number of tests for the new package, added using @TO TEST@
:a number of tests for the new package, added using @TO symbol TEST@

Text
See @TO "an example of a package"@ for the basic template for new packages, or
Expand Down Expand Up @@ -205,7 +205,7 @@ Node
exportFrom
exportMutable
beginDocumentation
TEST
symbol TEST
endPackage

Node
Expand Down Expand Up @@ -240,7 +240,7 @@ Node
exportMutable
beginDocumentation
"SimpleDoc :: doc"
TEST
symbol TEST
///

-- Subnodes
Expand Down
2 changes: 1 addition & 1 deletion M2/Macaulay2/packages/SimpleDoc/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Node
Example
check SimpleDoc
SeeAlso
TEST
symbol TEST
check
packageTemplate
"docExample"
Expand Down
1 change: 0 additions & 1 deletion M2/Macaulay2/tests/normal/names.m2
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,6 @@ assert( (toString SyzygyRows) === "SyzygyRows" )
assert( (toString T) === "T" )
assert( (toString TABLE) === "TABLE" )
assert( (toString TD) === "TD" )
assert( (toString TEST) === "TEST" )
assert( (toString TEX) === "TEX" )
assert( (toString TITLE) === "TITLE" )
assert( (toString TO) === "TO" )
Expand Down
19 changes: 11 additions & 8 deletions M2/Macaulay2/tests/normal/testing.m2
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@ loadPackage("TestPackage", FileName => testpkg)
check "TestPackage"
pkgtest = tests(0, "TestPackage")
assert instance(pkgtest, TestInput)
assert Equation(toSequence locate pkgtest, (testpkg, 3, 1, 4, 1,,))
assert Equation(toString pkgtest, testpkg | ":3:1-4:1")
assert Equation(net pkgtest, "TestInput[" | testpkg | ":3:1-4:1]")
expectedCode = " -- " | toAbsolutePath testpkg |
":4:1: location of test code" | newline | "assert Equation(1 + 1, 2)"
assert Equation(code pkgtest, expectedCode)
assert Equation(code 0, expectedCode)

assert Equation(toSequence locate pkgtest, (testpkg, 3, 5, 3, 32, 3, 5))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This happened in a brew build:

 -- running   check(357, "Core")              -- .380111s elapsed
/opt/homebrew/Cellar/macaulay2/1.24.11-rc1/share/doc/Macaulay2/Core/tests/testing.m2:1:1 error:
 -- i5 : pkgtest = tests(0, "TestPackage")
 -- 
 -- o5 = TestInput[../../M2-93313-0/0.m2:3:5-3:32]
 -- 
 -- o5 : TestInput
 -- 
 -- i6 : assert instance(pkgtest, TestInput)
 -- 
 -- i7 : assert Equation(toSequence locate pkgtest, (testpkg, 3, 5, 3, 32, 3, 5))
 -- stdio:10:6:(3): error: assertion failed:
 -- (../../M2-93313-0/0.m2, 3, 5, 3, 32, 3, 5) == (/private/tmp/M2-93313-0/0.m2, 3, 5, 3, 32, 3, 5) is false
 -- 
stdio:1:5:(3): error: test(s) #333 of package Core failed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, that makes sense. Calling minimizeFilename should fix it. I'll open a PR.

assert Equation(toString pkgtest, "assert Equation(1 + 1, 2)")
assert Equation(net pkgtest, "TestInput[" | testpkg | ":3:5-3:32]")
beginDocumentation()
expectedCode = DIV{
new FilePosition from (testpkg, 3, 5, 3, 32, 3, 5),
": --source code:",
PRE{CODE{"class" => "language-macaulay2",
"TEST \"assert Equation(1 + 1, 2)\""}}}
assert BinaryOperation(symbol ===, code pkgtest, expectedCode)
assert BinaryOperation(symbol ===, code 0, expectedCode)

assert( (for i from 1 to 2 list { for j from 1 to 2 do { if j == 2 then break 444; } }) === {{444}, {444}} ) -- see issue #2522

Expand Down
Loading