-
Notifications
You must be signed in to change notification settings - Fork 18
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
Generators: Allow hardcoding testcases input/answer #272
Conversation
Related to (/ supersedes?) #220 🙂 |
This turned out to be quite easy to implement. @mpsijm @mzuenni @thorehusfeldt who wants to give it a try? todo:
What I implemented now:
Most of the code in the PR is actually to get the caching and info messages and such correct. |
53966c2
to
3e340e0
Compare
3e340e0
to
7c0ce31
Compare
7c0ce31
to
a06af92
Compare
53db57d
to
e549177
Compare
I like this a lot. If I understand correctly, we are at something like this: generator :: command | {
input: command
in: string
ans: string
desc: string
hint: string
file_config
directory_reserved
...
} where the new fields are ( I can’t see a use-case for having both ( |
Should the option of supplying the my_testcase: Or should we now insist on
(I prefer the latter, it’s more explicit.) |
A bigger change could be to not allow any manually provided files but I think that's too much. |
My only uneasiness are manually provided files that are not explictly listed. But I admit that I no longer have a consistent model for what “absence of value” means in |
I expect the following to be used a lot: data:
sample:
data:
- '':
in: |
123 32
foo
bar baz
- '':
in: |
2 45
eki eki
ptang (And this is excellent! Finally a good way to specify samples.) The indentation seems excessive, but this is proper yaml. (It looks weird because Nag: If the user (understandably) forgets one level of indentation, as in data:
sample:
data:
- '':
in: |
123 32
foo
bar baz
- '':
in: |
2 45
eki eki
ptang the
|
Consider being more explicit by adding the key foo:
path: manual/foo.in
bar:
in: 34 64
baz:
command: random {seed}
bum:
path: null # same as path/to/bum.in, deprecated Setting exactly one of When the value is yaml-string (instead of yaml-dictionary), it is interpreted as a shorthand for either a : manual/foo.in # end in .in and contains no whitespace: interpreted as a path
b : random {seed} # a command
c : null # same as "path/to/c.in"
d : # same as null The introduction of
which look wrong to me.
|
After some thinking (and actually writing a specification): path-to-infile should have the same syntax as path-to-ansfile, and the above proposal breaks that. Alternatives: tc-a:
in: 34 643 # string specifies contents
ans: 54 # string specifies contents
tc-b:
in-path: manual/sample/foo.in # string specifies path
ans-path: manual/sample/foo.ans # string specifies path Arguably, Alternative is to be lenient in the value specification: tc-c:
in: 34 54 # string specifies contents of `tc-c.in`
tc-d:
in: manual/secret/group4/foo.in # string looks like a path, so it's a path That gives me gray hairs but is close in spirit to what The third, possibly cleanest suggestion would be the field tc-e:
in: 54 12 # string specifies contents
path: manual/sample/foo # copy whatever `.in`, `.ans`. `.whatever` is found at that path The order might be:
|
I think this is what I would prefer the specification to be: package problemformat
import "struct"
#command: !="" & (=~"^[^{}]*(\\{(name|seed(:[0-9]+)?)\\}[^{}]*)*$")
#file_config: {
solution?: #command // null disallowed (specify #testcase.ans instead)
visualizer?: #command | null // null means: skip visualisation
random_salt?: string
}
#testcase: null | #command | { // null means: expect file in <problemname>/data/...
command?: #command // invocation of a generator
path?: #path // copy <problemname>/generators/path.in etc.
in?: string // explicitly given
ans?: string
desc?: string
hint?: string
#file_config
}
#data_dict: [string]: #testgroup | #testcase
#testgroup: {
#file_config
testdata_settings?: #testdata_settings
data: #data_dict | [...{#data_dict & struct.MaxFields(1)} ] // list of singleton dicts
}
#Generators: {
generators?: [string]: [...string]
#testgroup
... // do allow unknown_key at top level for tooling
} & { data: close({ // top level data dict has keys {sample, secret}
sample: #testgroup
secret: #testgroup
})
} (I have now a CUE package |
ok, many new ideas here to reply to. I really like your 'order of steps' proposal, and think that that corresponds exactly to my mental model of this. Also the CUE spec looks good to me. Some more thoughts: 'inline' testcasesI call testcases for which
'manual'/'copied' testcasesThere are testcases currently given as I like your testcase:
path: manual/testcase where the semantics are that all files Regarding the name:
Then again, Hardcoded casesI think we're clear on this: Maybe we can dissallow this to be empty. (But see below.) Unlisted filesI think by default, we should warn for every file in However, there is still one case that would be nice to have a proper solution for: manual visualizations for the samples, that are not generated using a Some options:
With this last option, |
I like option 2 and 3 (explicit) more than 1 and 4 (weird semantics of |
Specific feedback for option 4: I think that the key should not be named To fix that, here's a proposal that is in some way a mix between options 3 and 4 (let's call it option 5): We could allow keys like - '':
in: 2 4 # Content of a testcase, copied to `1.in`
ans:
path: manual/sample/1.ans # Path to the answer, copied to `1.ans`
- '':
in: 2 4 # Content of a testcase, copied to `2.in`
ans: 6 # Content copied to `2.ans`
visualizer:
path: manual/sample/2.png # Path to the PNG, instead of a command to run |
|
Oh yes, anywhere I wrote |
@thorehusfeldt I agree with you that "conceptually cheap" specifications are to be preferred. In practice, I do not think we need the granular control that option 5 provides (why would we ever want not all files matching a prefix to be copied?). The way how option 3 copies all manual files matching the prefix given in the global-for-the-testcase I also like options 2 and 3 best, in that case, but I also think we should keep maintaining option 1 (but with an empty value instead of an explicit |
My understanding is that |
Ok so:
Thus, you can either keep your testcase completely inline, or move all of it into generators.yaml. |
…file from sample case this is already mentioned at the top of the file
1886d90
to
9f2e29e
Compare
Currently we do
Would be nice to instead do
Then, we can directly include samples and other small manual cases. This should support keys for some more extensions (corresponding to text files):
(images probably shouldn't be made this way.)
Note that this would prevent future overriding of these keys by commands.
input
(rename togen
),solution
, andvisualizer
are used for that currently.Result
Generating
See doc/generators.yaml for the result. In brief:
indicates
testcase.{in,ans,...}
are given directly in the target directory (discouraged).indicates the generator to run
copies
manual_cases/sample/3.*
totestcase.*
Priorities:
Numbering:
g1-<name>
,g2-<name>
.Including
Testgroups can contain a
include:
key that maps to a list of strings, each the name of a testcase or testgroup. (For numbered cases, the non-numbered dictionary key as written ingenerators.yaml
must be used.) The referred-to testcases/testgroups must have a unique name within the problem.