Skip to content

Commit 1233431

Browse files
authored
doc: improve docs & bump version (#224)
1 parent 772b90b commit 1233431

File tree

6 files changed

+145
-149
lines changed

6 files changed

+145
-149
lines changed

.github/workflows/ci.yml

+5
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ jobs:
5050
with:
5151
command: test
5252
args: --no-fail-fast
53+
- name: Doctest
54+
uses: actions-rs/cargo@v1
55+
with:
56+
command: test
57+
args: --doc
5358

5459
semver:
5560
runs-on: ubuntu-22.04

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10+
## [0.21.0] - 2024-06-28
11+
1012
**Breaking changes**:
1113
* runner: `RecordOutput` is now returned by `Runner::run` (or `Runner::run_async`). This allows users to access the output of each record, or check whether the record is skipped.
1214
* runner(substitution): add a special variable `__NOW__` which will be replaced with the current Unix timestamp in nanoseconds.

README.md

+103-40
Original file line numberDiff line numberDiff line change
@@ -14,46 +14,16 @@ This repository provides two crates:
1414

1515
## Use the library
1616

17-
To add the dependency to your project:
18-
19-
```sh
20-
cargo add sqllogictest
21-
```
22-
23-
Implement `DB` trait for your database structure:
24-
25-
```rust
26-
struct Database {...}
27-
28-
impl sqllogictest::DB for Database {
29-
type Error = ...;
30-
type ColumnType = ...;
31-
fn run(&mut self, sql: &str) -> Result<sqllogictest::DBOutput<Self::ColumnType>, Self::Error> {
32-
...
33-
}
34-
}
35-
```
36-
37-
Then create a `Runner` on your database instance, and run the tests:
38-
39-
```rust
40-
let db = Database {...};
41-
let mut tester = sqllogictest::Runner::new(db);
42-
tester.run_file("script.slt").unwrap();
43-
```
44-
45-
You can also parse the script and execute the records separately:
46-
47-
```rust
48-
let records = sqllogictest::parse_file("script.slt").unwrap();
49-
for record in records {
50-
tester.run(record).unwrap();
51-
}
52-
```
17+
Refer to the [rustdoc](https://docs.rs/sqllogictest/latest/sqllogictest/).
5318

5419
## Use the CLI tool
5520

56-
![demo](./docs/demo.gif)
21+
The CLI tool supports many useful features:
22+
- Colorful diff output
23+
- Automatically update test files according to the actual output
24+
- JUnit format test result report
25+
- Parallel execution isolated with different databases
26+
- ...
5727

5828
To install the binary:
5929

@@ -64,11 +34,12 @@ cargo install sqllogictest-bin
6434
You can use it as follows:
6535

6636
```sh
37+
# run scripts in `test` directory against postgres with default connection settings
6738
sqllogictest './test/**/*.slt'
39+
# run the tests, and update the test files with the actual output!
40+
sqllogictest './test/**/*.slt' --override
6841
```
6942

70-
This command will run scripts in `test` directory against postgres with default connection settings.
71-
7243
You can find more options in `sqllogictest --help` .
7344

7445
> **Note**
@@ -102,15 +73,107 @@ SELECT * FROM foo;
10273
4 5
10374
```
10475

105-
### Run a statement that should fail
76+
### Extension: Run a query/statement that should fail with the expacted error message
77+
78+
The syntax:
79+
- Do not check the error message: `[statement|query] error`
80+
- Single line error message (regexp match): `[statement|query] error <regex>`
81+
- Multiline error message (exact match): Use `----`.
10682

10783
```text
10884
# Ensure that the statement errors and that the error
10985
# message contains 'Multiple object drop not supported'
11086
statement error Multiple object drop not supported
11187
DROP VIEW foo, bar;
88+
89+
# The output error message must be the exact match of the expected one to pass the test,
90+
# except for the leading and trailing whitespaces.
91+
# Empty lines (not consecutive) are allowed in the expected error message. As a result, the message must end with 2 consecutive empty lines.
92+
query error
93+
SELECT 1/0;
94+
----
95+
db error: ERROR: Failed to execute query
96+
97+
Caused by these errors:
98+
1: Failed to evaluate expression: 1/0
99+
2: Division by zero
100+
101+
102+
# The next record begins here after 2 blank lines.
112103
```
113104

105+
### Extension: Run external shell commands
106+
107+
This is useful for manipulating some external resources during the test.
108+
109+
```text
110+
system ok
111+
exit 0
112+
113+
# The runner will check the exit code of the command, and this will fail.
114+
system ok
115+
exit 1
116+
117+
# Check the output of the command. Same as `error`, empty lines (not consecutive) are allowed, and 2 consecutive empty lines ends the result.
118+
system ok
119+
echo "Hello\n\nWorld"
120+
----
121+
Hello
122+
123+
World
124+
125+
126+
# The next record begins here after 2 blank lines.
127+
128+
# Environment variables are supported.
129+
system ok
130+
echo $USER
131+
----
132+
xxchan
133+
```
134+
135+
### Extension: Environment variable substituion in query and statement
136+
137+
It needs to be enabled by adding `control substitution on` to the test file.
138+
139+
```
140+
control substitution on
141+
142+
# see https://docs.rs/subst/latest/subst/ for all features
143+
query TTTT
144+
SELECT
145+
'$foo' -- short
146+
, '${foo}' -- long
147+
, '${bar:default}' -- default value
148+
, '${bar:$foo-default}' -- recursive default value
149+
FROM baz;
150+
----
151+
...
152+
```
153+
154+
Besides, there're some special variables supported:
155+
- `$__TEST_DIR__`: the path to a temporary directory specific to the current test case.
156+
This can be helpful if you need to manipulate some external resources during the test.
157+
- `$__NOW__`: the current Unix timestamp in nanoseconds.
158+
159+
```
160+
control substitution on
161+
162+
statement ok
163+
COPY (SELECT * FROM foo) TO '$__TEST_DIR__/foo.txt';
164+
165+
system ok
166+
echo "foo" > "$__TEST_DIR__/foo.txt"
167+
```
168+
169+
> [!NOTE]
170+
>
171+
> When substitution is on, special characters need to be excaped, e.g., `\$` and `\\`.
172+
>
173+
> `system` commands don't support the advanced substitution features of the [subst](https://docs.rs/subst/latest/subst/) crate,
174+
> and excaping is also not needed.
175+
> Environment variables are supported by the shell, and special variables are still supported by plain string substitution.
176+
114177
## Used by
115178

116179
- [RisingLight](https://github.com/risinglightdb/risinglight): An OLAP database system for educational purpose

docs/demo.gif

-319 KB
Binary file not shown.

docs/demo.tape

-89
This file was deleted.

sqllogictest/src/lib.rs

+35-20
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,51 @@
11
//! [Sqllogictest][Sqllogictest] parser and runner.
22
//!
3+
//! This crate supports multiple extensions beyond the original sqllogictest format.
4+
//! See the [README](https://github.com/risinglightdb/sqllogictest-rs#slt-test-file-format-cookbook) for more information.
5+
//!
36
//! [Sqllogictest]: https://www.sqlite.org/sqllogictest/doc/trunk/about.wiki
47
//!
58
//! # Usage
69
//!
7-
//! Implement [`DB`] trait for your database structure:
8-
//!
9-
//! ```ignore
10-
//! struct Database {...}
10+
//! For how to use the CLI tool backed by this library, see the [README](https://github.com/risinglightdb/sqllogictest-rs#use-the-cli-tool).
1111
//!
12-
//! impl sqllogictest::DB for Database {
13-
//! type Error = ...;
14-
//! fn run(&self, sql: &str) -> Result<String, Self::Error> {
15-
//! ...
16-
//! }
17-
//! }
18-
//! ```
12+
//! For using the crate as a lib, and implement your custom driver, see below.
1913
//!
20-
//! Create a [`Runner`] on your database instance, and then run the script:
14+
//! Implement [`DB`] trait for your database structure:
2115
//!
22-
//! ```ignore
23-
//! let mut tester = sqllogictest::Runner::new(Database::new());
24-
//! let script = std::fs::read_to_string("script.slt").unwrap();
25-
//! tester.run_script(&script);
2616
//! ```
17+
//! struct MyDatabase {
18+
//! // fields
19+
//! }
20+
//!
21+
//! #[derive(thiserror::Error, Debug, PartialEq, Eq, Clone)]
22+
//! enum MyError {
23+
//! // variants
24+
//! }
2725
//!
28-
//! You can also parse the script and execute the records separately:
26+
//! impl sqllogictest::DB for MyDatabase {
27+
//! type Error = MyError;
28+
//! // Or define your own column type
29+
//! type ColumnType = sqllogictest::DefaultColumnType;
30+
//! fn run(&mut self, sql: &str) -> Result<sqllogictest::DBOutput<Self::ColumnType>, Self::Error> {
31+
//! // TODO
32+
//! Ok(sqllogictest::DBOutput::StatementComplete(0))
33+
//! }
34+
//! }
2935
//!
30-
//! ```ignore
31-
//! let records = sqllogictest::parse(&script).unwrap();
36+
//! // Then create a `Runner` on your database instance, and run the tests:
37+
//! let mut tester = sqllogictest::Runner::new(|| async {
38+
//! let db = MyDatabase {
39+
//! // fields
40+
//! };
41+
//! Ok(db)
42+
//! });
43+
//! let _res = tester.run_file("../tests/slt/basic.slt");
44+
//!
45+
//! // You can also parse the script and execute the records separately:
46+
//! let records = sqllogictest::parse_file("../tests/slt/basic.slt").unwrap();
3247
//! for record in records {
33-
//! tester.run(record);
48+
//! let _res = tester.run(record);
3449
//! }
3550
//! ```
3651

0 commit comments

Comments
 (0)