-
Notifications
You must be signed in to change notification settings - Fork 239
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
Allow lazily-evaluated code as argument to TEST #3490
base: development
Are you sure you want to change the base?
Conversation
I understand wanting it to behave the same as before, but is there a reason why the previous behavior was better? |
This is maybe pretty artificial, but this is the current behavior, which seems wrong: i1 : Nothing + Nothing := x -> "foo";
i2 : TEST "a" + TEST "b"
stdio:2:9:(3): error: no method for binary operator + applied to objects:
"a" (of class String)
+ null (of class Nothing) It seems like we should get "foo" here. |
I can't imagine any use for the output of TEST. I can, however, imagine setting up TEST to act as a delayed execution keyword, so we could do: TEST 1 + 1 == 2 Without bothering with strings or parentheses. |
You've convinced me! I may try and implement writing tests w/o strings like this in this PR... |
Yes, exactly, construct a By the way, I'd like |
I have a very early draft where
Tests defined in this way are very fast: i1 : TEST "assert true"
i2 : TEST assert true
i3 : check User
-- capturing check(0, "User") -- .0741398s elapsed
-- calling check(1, "User") -- .000079301s elapsed |
Interesting .. because we've front loaded the parsing. That might make benchmarking easier also (maybe We should be careful that locality of symbols doesn't change in a bad way.
Then maybe rename it |
It seems to work pretty well -- it's really no different than writing a function in a package. I adapted the tests in The only breaking change to existing tests that I've encountered is the handful of tests that use One thing I haven't quite figured out how to deal with is the |
One strange thing I haven't figured out how to fix yet: i1 : TEST (f := x -> x^2)
i2 : TEST (f := x -> x^3)
stdio:2:6:(3): warning: local declaration of f shields variable with same name |
I think you need to define a local dictionary for each TestClosure. |
I think this is not just testing that you can read the file, without loading it, so probably it should be changed to Also, I think now looking at the code of the test just shows the |
I don't think we want to call i1 : TEST load "foo.m2"
o1 = TestClosure[stdio:1:5-1:18]
o1 : TestClosure
i2 : check User
-- calling check(0, "User") -- .000138457s elapsed
i3 : x
o3 = 2 But with i1 : TEST get "foo.m2"
o1 = TestClosure[stdio:1:5-1:17]
o1 : TestClosure
i2 : check User
-- capturing check(0, "User") -- .0358661s elapsed
i3 : x
o3 = x
o3 : Symbol
That's exactly what However, there's currently not a way to tell a package to put any files there, and the autotools/cmake builds have to manually do this for Core. I've toyed with the idea of implementing this -- maybe a |
ab8e968
to
bc8ee42
Compare
This way, we can recognize when when is a test
TEST will be one. Parsed as an Arrow with a dummy lhs
Now creates a nullary function containing the test's code rather than just computing the location of the string.
We get most of the desired methods for free via inheritance. We keep TestInput around as a synonym for now
We call each test, and if it returns a string, then it's a traditional test that we should try to capture. Otherwise, we're done! A couple things: - Tests run this way don't produce any output, so debugging is harder. In particular, Verbose => true doesn't do anything. - We print "calling" *after* we're done running the test, since we don't know if it returns a string or not.
Run a test, and if it returns a string (i.e., it's a traditional test), then capture that string.
currentFileDirectory will no likely no longer be the correct path to the test files, so we use the packages' "auxiliary files" keys to find them.
Also bump package to version 0.2
Otherwise we'll actually add a test to the current package.
Also add "tests" to SeeAlso section
List of files to install in package test directory when running installPackage.
Also bump the version number of JSON
I've added a I also figured out how to give each TestClosure object its own local dictionary -- the |
@@ -271,6 +271,7 @@ Node | |||
[newPackage, PackageExports] | |||
[newPackage, PackageImports] | |||
[newPackage, Reload] | |||
[newPackage, TestFiles] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is complicating the testing system rather than simplifying it, and I would personally rather not add yet another option to newPackage
(e.g. should we also add DocumentationFiles
next?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough -- I wasn't that excited about this idea either.
Another possibility would be to change currentLayout#"packagetests"
to point to a subdirectory of the auxiliary files directory (say test
or tests
) instead of the current behavior, where it's a subdirectory of the package's documentation directory. Then any files in that directory would automatically get loaded as tests, as currently happens for Core
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Polyhedra/tests
might get in the way, but in principle that's fine with me.
seq(eval(c), locate(codePosition(c)))); | ||
when r is Error do r else nullE); | ||
setupop(TestS, testfun); | ||
addTestFromFile(e:Expr):Expr := ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why this is better. It's much more complicated than before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current behavior is to store a test's location in a hash table, which is easy to do at top level. But with this proposal, tests are becoming functions, and so unless we want all the tests that have been loaded from files to have testing.m2
as their location, we need to fake it somehow in the interpreter. This function was my attempt at doing that. I figured we should try to find out the ending position so that code
will work.
@@ -518,7 +525,10 @@ export treePosition(e:ParseTree):Position := ( | |||
is s:Parentheses do combinePositionL(s.left.position, s.right.position) | |||
is s:EmptyParentheses do combinePositionL(s.left.position, s.right.position) | |||
is a:Adjacent do combinePositionM(treePosition(a.lhs), treePosition(a.rhs)) | |||
is a:Arrow do combinePositionL(treePosition(a.lhs), treePosition(a.rhs)) | |||
is a:Arrow do ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Treating TEST
as ->
is kludgy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it is a little strange. We need to call bind
when things are still ParseTree
objects in order to create a local dictionary, which is why I went this route. And Arrow
is already set up for creating functions.
I also considered creating another member of ParseTree
. Then we could avoid all the when lhs is dummy
cases.
I don't like this approach, and I don't think it needs to be this complicated. I think we should keep export TestClosure := {+ frame:Frame, model:functionCode, hash:hash_t }; In particular, the model can be a normal |
Could you make a branch on your fork with the last commit before you changed the behavior to act as an arrow? I see the commit before force pushes but I can't retrieve them because github doesn't allow fetch orphaned commits. See here. I also can't easily tell which one I want, because i can't view history of an orphaned commit. I can try adding a local dictionary in a simpler way from there. |
Sure thing! |
Remind me, what is wrong with the version on your |
No local dictionaries for the tests, e.g., #3490 (comment) |
I think it's going to take me more time than I have before November. Is it okay with you if we postpone this for the next release? |
Yes, that's totally fine! |
This is a quick followup to #3419, which changed
TEST
from a method to a keyword so that we could do a better job of keeping track of the location of tests.In that PR, I gave it a very low binding strength (the same as
elapsedTime
, etc.) But this means that it behaves much differently than it did than it was a method, e.g.,:In M2 1.24.05, when
TEST
was still a method, we got an error:This is because
SPACE
has higher binding strength than|
.We increase the binding strength of
TEST
to just belowSPACE
so that it behaves essentially the same as it did when it was a method. We keep it a bit below to mimic the right associativity ofSPACE
, i.e., we wantTEST f x
to parse asTEST (f x)
, not(TEST f) x
.