Skip to content

Initial experiments with serialized testing #593

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

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
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
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ members=[
"lrpar/examples/clone_param",
"lrtable",
"nimbleparse",
"grammar_testing",
]
resolver = "2"

Expand Down Expand Up @@ -48,3 +49,4 @@ proc-macro2 = "1.0"
prettyplease = "0.2.31"
syn = "2.0"
yaml-rust2 = "0.10.1"
ron = "0.10"
2 changes: 2 additions & 0 deletions doc/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@
- [grmtools parsing idioms](parsing_idioms.md)
- [Error recovery](errorrecovery.md)
- [An AST evaluator](ast_example.md)
- [Testing](testing.md)
- [Rust Editions](editions.md)
- [The individual libraries and tools](libsandtools.md)
- [lrpar](lrpar.md)
- [lrlex](lrlex.md)
- [nimbleparse](nimbleparse.md)
- [cfgrammar](cfgrammar.md)
- [lrtable](lrtable.md)
- [grammar_testing](grammar_testing.md)
- [third party](thirdparty.md)
- [Other Rust parsing tools](othertools.md)
6 changes: 6 additions & 0 deletions doc/src/grammar_testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# `grammar_testing`

`grammar_testing` ([crate](https://crates.io/crates/grammar_testing);
[source](https://github.com/softdevteam/grmtools/tree/master/grammar_testing)) is a library
that facilitates testing of grammars. It's primary purpose is to define an standardize serialization formats
so tests can be performed from tools like `nimbleparse` as well as user specified build scripts.
165 changes: 165 additions & 0 deletions doc/src/testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
# Testing (experimental)

grmtools testing facilities are currently experimental, under development, and subject to change.
Not all features described in this are section currently implemented (in fact most are incomplete).
Currently this text primarily serves as a design document for testing features and feedback is welcome.

## Testing raw input

### Example lexer
🚀
```lex
%%
[a-z] "character"
\" '"'
[ \n\t] ;
```


### Example grammar
🚀
```yacc
%grmtools{
yacckind: Original(NoAction),
test_files: "input*.txt"
}

%%
start: "character";
```


### Input text
🚀
Contents specified via `test_files`:
```text
a
```

## Specifying multiple globs
🚧
It would be nice if you could specify multiple globs:
```
test_files: ["*.txt", "*.grmtest"],
```

## Testing with serialized formats

🚧
When specifying `test_files` the `grmtest` extension is treated specially.

### Example Grammar for serializated test data.
🚧
By specifying the `grmtest` extension for the `test_files` value you enable serialized
test data including output expectations for abstract syntax trees and error text.

```yacc
test_files "*.grmtest"
```


### Serialized test input
🚧
The `grmtest` file deserializes to a struct with many optional fields.
It is a [`ron`](https://crates.io/crates/ron) using the [Implicit Some](https://github.com/ron-rs/ron/blob/master/docs/extensions.md#implicit_some) extension.
This allows you to omit most of the values, but has the downside that typos may fall back to default values.

#### Fields
🚧
* `input: String` field is required, and specifies the input to the parser.
* `pass: bool` defaults to None, only Some if explicitly specified.
* `ast: Option<grammar_testing::ASTRepr>` if present specifies the expected output see [Serializing with nimbleparse] for generating ast output.
* `errors: Option<Vec<String>>` if present specifies the expected error text, without error recovery.

#### Methods
* `should_pass(&self)` Returns the value of the `pass` field when it is `Some` otherwise returns whether the `errors` field is `None` or it's inner value is empty.

#### Example .grmtest file
🚧
```grmtest
(
input: "a",
ast: ("start", [
("character", "a"),
]),
)
```


### Serializing with nimbleparse

#### ast output
* 🚀 Using the `-s` option to nimbleparse to produce a serialized ast.
* 🚧 `-s ast`

```console
$ echo "a" | nimbleparse -s testing.l testing.y -
("start", [
("character", "a"),
])
```


#### grmtest output
🚧 `-s grmtest`

```console
$ echo "a" | nimbleparse -s grmtest testing.l testing.y -
(
input: "a\n",
ast: ("start", [
("character", "a"),
])
)
```


## Testing multiple inputs
🚧
Specify a plural extension `test_files: "*.grmtests` to allow a vector of test inputs.

```grmtests
[
(input: "a"),
(input: "b"),
(input: "a", ast: ("start", [("character", "a")])),
(input: "abc", pass: false),
]
```


## Escaping and raw strings

Because grammars often contain quotation marks, it is convenient to support rusts `raw string` format.
By default the serializer outputs raw strings.

🚀
```grmtest
$ echo "\"" | ./target/debug/nimbleparse -s testing.{l,y} -
("start", [
(r#"""#, r#"""#),
])
```

🚧
```
[
// Raw strings, and escaped characters are usable interchangably.
( input: r#"""#, ast:("start", [(r#"""#, "\"")])),
( input: "\"", ast:("start", [("\"", r#"""#)])),
]
```


## Running tests
🚀

If using build.rs/`CTParserBuilder` just cargo build.
If no arguments are specified `nimbleparse testing.l testing.y` then if `test_files` is specified it will be used by default.

## Manual Lexer limitations
🚧

Currently grmtools testing facilities are limited to being used with the combination of `lrlex`,
and `lrpar`. There currently isn't any mechanism in place for testing when using a manual lexer.
Doing so requires using unstable/hidden/undocumented aspects of the API.
8 changes: 8 additions & 0 deletions grammar_testing/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "grammar_testing"
version = "0.0.1"
edition = "2024"

[dependencies]
ron.workspace = true
serde = { workspace = true, features = ["derive"] }
Loading