Contains helpers for specifying behavior at the very lowest level of Nucleus.
Should only be available if the environment is configured in an implementation-specific way (for example, a command line switch or a compile time option).
Call-pattern:
- Caller.
- A label (the
name
). - An execution (the
test
).
Clones the locals of the caller to the test
, as well as the pair objects
within locals, then stages the test
with the name
as the response. (Most
likely the execution is pristine, anyway, so this doesn't really matter.)
If specification signal
receives a label matching the name
, the test
is
considered to have passed and the caller is restaged with its own, original
(non-cloned) locals. Otherwise, if the implementation determines that no further
action could possibly occur (i.e., not waiting on any I/O or anything like that
and nothing in the queue), the test
is considered to have failed.
The implementation SHOULD log the result of the test
, most likely including
the name
.
Rationale for the 2nd argument being a label: It's the easiest comparison to define. Object identity might not be the simplest starting point in some languages. It's also useful for logging.
Rationale for defining pass/fail in terms of 'no further action': Many operations in Nucleus don't restage the caller in the event of some kind of failure. This is the simplest way to test that behavior.
Rationale for cloning locals and its pair objects: Isolation, basically. We shouldn't need to add teardown logic to the tests before we can assume that the machine is safe enough to do so!
Rationale for returning the caller's locals: So that we don't need to rely
on something like implementation void
. Not so sure about this one.
specification assert[] "label compare foo with foo" {
infrastructure label compare[] foo foo
[specification signal "label compare foo with foo"]
}
If the compare
returns, the signal
will be staged, so the test will pass.
The compare
doesn't have to be able to take the result of signal
, since
signal
doesn't ever return.
Call-pattern:
- Caller.
- A label (the
name
). - An execution (the
test
).
Same behavior as specification assert
, except instead of considering a signal
a pass, it considers a signal a failure. If no signal is received before
the implementation determines no further action could occur, the test
is a
pass.
Rationale: Makes it very easy to assert that something will not return. For example, a failed lookup.
specification refute[] "label compare foo with bar" {
infrastructure label compare[] foo bar
[specification signal "label compare foo with bar"]
}
If the compare
doesn't return (which it shouldn't), the signal
will never be
staged, and that's considered a pass.
Call-pattern:
- A label (the
name
).
Signals a pass to the specification assert
invocation of the same name
,
or a fail to the specification refute
invocation of the same name
.
Doesn't take a caller or return, so make sure you're ready to exit your test before you call this.
Rationale: Super simple, and allows nested tests, which is necessary when dealing with so little available to us, at least at first.
specification assert[] "infrastructure compare [] with []" {
infrastructure compare[] [] []
[specification signal "infrastructure compare [] with []"]
}
specification refute[] "infrastructure compare empty with empty" {
infrastructure compare[] [infrastructure empty[]]
[infrastructure empty[]]
[specification signal "infrastructure compare empty with empty"]
}