Support # as comment syntax and \# escaping
This commit is contained in:
parent
c9dba93f7f
commit
09f1852044
|
|
@ -36,7 +36,9 @@ Transcript-based shell integration test runner. Rust.
|
||||||
- `...` inline = matches any characters on that line
|
- `...` inline = matches any characters on that line
|
||||||
- `[N]` on last line of expected output = assert exit code N
|
- `[N]` on last line of expected output = assert exit code N
|
||||||
- `[*]` = assert any non-zero exit code; default expects 0
|
- `[*]` = assert any non-zero exit code; default expects 0
|
||||||
- `$#` comment line = not executed, no output expected (e.g. `$# start the server`)
|
- `#` at start of line = comment (not executed, no output expected)
|
||||||
|
- `$#` also works as comment (legacy syntax)
|
||||||
|
- `\#` in expected output = literal line starting with `#`
|
||||||
- `#` after a command = comment (stripped); `#` in expected output is literal
|
- `#` after a command = comment (stripped); `#` in expected output is literal
|
||||||
- `@env KEY=VALUE` before first command = set environment variable
|
- `@env KEY=VALUE` before first command = set environment variable
|
||||||
- `@teardown <command>` before first command = run command after all test commands
|
- `@teardown <command>` before first command = run command after all test commands
|
||||||
|
|
|
||||||
15
README.md
15
README.md
|
|
@ -30,16 +30,25 @@ ls: missing: No such file or directory
|
||||||
|
|
||||||
`[1]` after the expected output matches the exit code.
|
`[1]` after the expected output matches the exit code.
|
||||||
|
|
||||||
`$#` is a comment line — not executed, no output expected:
|
`#` at the start of a line is a comment — not executed, no output expected:
|
||||||
|
|
||||||
```
|
```
|
||||||
$# start the server
|
# start the server
|
||||||
$ my-server &
|
$ my-server &
|
||||||
$# now test it
|
# now test it
|
||||||
$ curl localhost:8080
|
$ curl localhost:8080
|
||||||
OK
|
OK
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If expected output starts with `#`, escape it with `\#`:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ echo "#hashtag"
|
||||||
|
\#hashtag
|
||||||
|
```
|
||||||
|
|
||||||
|
`#` elsewhere in expected output is literal (not a comment).
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
||||||
15
src/parse.rs
15
src/parse.rs
|
|
@ -68,9 +68,10 @@ fn strip_comment(line: &str) -> &str {
|
||||||
line
|
line
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A line like `$# ...` or `$ # ...` — a comment, not a real command.
|
/// A line like `$# ...`, `$ # ...`, or `# ...` — a comment, not a real command.
|
||||||
pub fn is_comment_line(line: &str) -> bool {
|
pub fn is_comment_line(line: &str) -> bool {
|
||||||
line.starts_with("$#")
|
line.starts_with('#')
|
||||||
|
|| line.starts_with("$#")
|
||||||
|| (line.starts_with("$ ") && strip_comment(&line[2..]).is_empty())
|
|| (line.starts_with("$ ") && strip_comment(&line[2..]).is_empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -269,6 +270,16 @@ pub fn parse(path: &str, content: &str) -> Result<ShoutFile, ParseError> {
|
||||||
} else if line.starts_with("\\$ ") && current.is_some() {
|
} else if line.starts_with("\\$ ") && current.is_some() {
|
||||||
// Escaped dollar-space: literal expected output starting with "$ "
|
// Escaped dollar-space: literal expected output starting with "$ "
|
||||||
current.as_mut().unwrap().expected.push(line[1..].to_string());
|
current.as_mut().unwrap().expected.push(line[1..].to_string());
|
||||||
|
} else if line.starts_with("\\#") && current.is_some() {
|
||||||
|
// Escaped hash: literal expected output starting with "#"
|
||||||
|
current.as_mut().unwrap().expected.push(line[1..].to_string());
|
||||||
|
} else if line.starts_with('#') {
|
||||||
|
// Comment line
|
||||||
|
if let Some(ref mut cmd) = current {
|
||||||
|
finalize_command(cmd);
|
||||||
|
commands.push(cmd.clone());
|
||||||
|
current = None;
|
||||||
|
}
|
||||||
} else if line.starts_with("$ ") {
|
} else if line.starts_with("$ ") {
|
||||||
seen_command = true;
|
seen_command = true;
|
||||||
if let Some(ref mut cmd) = current {
|
if let Some(ref mut cmd) = current {
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ use crate::matching::match_output;
|
||||||
use crate::parse::{ShoutFile, is_comment_line, trim_trailing_empty};
|
use crate::parse::{ShoutFile, is_comment_line, trim_trailing_empty};
|
||||||
use crate::run::CommandResult;
|
use crate::run::CommandResult;
|
||||||
|
|
||||||
fn escape_dollar(line: &str) -> String {
|
fn escape_output(line: &str) -> String {
|
||||||
if line.starts_with("$ ") {
|
if line.starts_with("$ ") || line.starts_with('#') {
|
||||||
format!("\\{line}")
|
format!("\\{line}")
|
||||||
} else {
|
} else {
|
||||||
line.to_string()
|
line.to_string()
|
||||||
|
|
@ -44,7 +44,7 @@ pub fn rewrite_file(
|
||||||
// Skip past old expected output lines in the original
|
// Skip past old expected output lines in the original
|
||||||
let mut j = i + 1;
|
let mut j = i + 1;
|
||||||
while j < lines.len()
|
while j < lines.len()
|
||||||
&& !is_comment_line(lines[j])
|
&& !(is_comment_line(lines[j]) && !lines[j].starts_with("\\#"))
|
||||||
&& !(lines[j].starts_with("$ ") && !lines[j].starts_with("\\$ "))
|
&& !(lines[j].starts_with("$ ") && !lines[j].starts_with("\\$ "))
|
||||||
{
|
{
|
||||||
j += 1;
|
j += 1;
|
||||||
|
|
@ -88,7 +88,7 @@ pub fn rewrite_file(
|
||||||
} else {
|
} else {
|
||||||
// Replace with actual output
|
// Replace with actual output
|
||||||
for al in &result.actual {
|
for al in &result.actual {
|
||||||
output.push(escape_dollar(al));
|
output.push(escape_output(al));
|
||||||
}
|
}
|
||||||
// Re-add exit code marker if it existed
|
// Re-add exit code marker if it existed
|
||||||
if let Some(marker) = old_exit_marker {
|
if let Some(marker) = old_exit_marker {
|
||||||
|
|
|
||||||
|
|
@ -3,3 +3,13 @@ hello
|
||||||
|
|
||||||
$ echo "keep # this"
|
$ echo "keep # this"
|
||||||
keep # this
|
keep # this
|
||||||
|
|
||||||
|
# this is a comment
|
||||||
|
$ echo "after comment"
|
||||||
|
after comment
|
||||||
|
|
||||||
|
$ echo "#hashtag"
|
||||||
|
\#hashtag
|
||||||
|
|
||||||
|
$ echo "https://google.com/#autoload"
|
||||||
|
https://google.com/#autoload
|
||||||
|
|
|
||||||
|
|
@ -34,11 +34,12 @@ ln -s /path/to/shout/vim ~/.local/share/nvim/site/pack/shout/start/shout
|
||||||
| Pattern | Highlight |
|
| Pattern | Highlight |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `$ command` | Statement (prompt as Special) |
|
| `$ command` | Statement (prompt as Special) |
|
||||||
| `$# comment` | Comment |
|
| `# comment` | Comment |
|
||||||
| `@env KEY=VALUE` | PreProc / Identifier / String |
|
| `@env KEY=VALUE` | PreProc / Identifier / String |
|
||||||
| `@setup`, `@teardown` | PreProc |
|
| `@setup`, `@teardown` | PreProc |
|
||||||
| Expected output | String |
|
| Expected output | String |
|
||||||
| `...` (wildcard) | WarningMsg |
|
| `...` (wildcard) | WarningMsg |
|
||||||
| `[N]`, `[*]` (exit code) | Constant |
|
| `[N]`, `[*]` (exit code) | Constant |
|
||||||
| `\$ ...` (escaped dollar) | SpecialChar + String |
|
| `\$ ...` (escaped dollar) | SpecialChar + String |
|
||||||
|
| `\# ...` (escaped hash) | SpecialChar + String |
|
||||||
| `# inline comment` | Comment |
|
| `# inline comment` | Comment |
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
-- Buffer-local settings for .shout files
|
-- Buffer-local settings for .shout files
|
||||||
vim.bo.commentstring = "$# %s"
|
vim.bo.commentstring = "# %s"
|
||||||
vim.bo.shiftwidth = 0
|
vim.bo.shiftwidth = 0
|
||||||
vim.bo.tabstop = 2
|
vim.bo.tabstop = 2
|
||||||
vim.bo.expandtab = true
|
vim.bo.expandtab = true
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@ syn match shoutEnvValue /.*$/ contained
|
||||||
syn match shoutSetupDirective /^@setup\s\+.*$/ contains=shoutDirectiveKey
|
syn match shoutSetupDirective /^@setup\s\+.*$/ contains=shoutDirectiveKey
|
||||||
syn match shoutTeardownDirective /^@teardown\s\+.*$/ contains=shoutDirectiveKey
|
syn match shoutTeardownDirective /^@teardown\s\+.*$/ contains=shoutDirectiveKey
|
||||||
|
|
||||||
" Comment commands: $# ... or $ # ...
|
" Comment lines: # ..., $# ..., or $ # ...
|
||||||
|
syn match shoutCommentCommand /^#.*$/
|
||||||
syn match shoutCommentCommand /^\$#.*$/
|
syn match shoutCommentCommand /^\$#.*$/
|
||||||
syn match shoutCommentCommand /^\$\s\+#.*$/
|
syn match shoutCommentCommand /^\$\s\+#.*$/
|
||||||
|
|
||||||
|
|
@ -25,9 +26,11 @@ syn match shoutPrompt /^\$\s/ contained
|
||||||
syn match shoutCommand /^\$\s.\+/ contains=shoutPrompt,shoutInlineComment
|
syn match shoutCommand /^\$\s.\+/ contains=shoutPrompt,shoutInlineComment
|
||||||
syn match shoutInlineComment /\s\+#[^"']*$/ contained
|
syn match shoutInlineComment /\s\+#[^"']*$/ contained
|
||||||
|
|
||||||
" Escaped dollar in expected output
|
" Escaped dollar/hash in expected output
|
||||||
syn match shoutEscapedDollar /^\\\$/ contained
|
syn match shoutEscapedChar /^\\\$/ contained
|
||||||
syn match shoutEscapedLine /^\\\$.*$/ contains=shoutEscapedDollar
|
syn match shoutEscapedChar /^\\#/ contained
|
||||||
|
syn match shoutEscapedLine /^\\\$.*$/ contains=shoutEscapedChar
|
||||||
|
syn match shoutEscapedLine /^\\#.*$/ contains=shoutEscapedChar
|
||||||
|
|
||||||
" Wildcards
|
" Wildcards
|
||||||
syn match shoutWildcardLine /^\.\.\.$/
|
syn match shoutWildcardLine /^\.\.\.$/
|
||||||
|
|
@ -55,7 +58,7 @@ hi def link shoutPrompt Special
|
||||||
hi def link shoutCommand Statement
|
hi def link shoutCommand Statement
|
||||||
hi def link shoutInlineComment Comment
|
hi def link shoutInlineComment Comment
|
||||||
|
|
||||||
hi def link shoutEscapedDollar SpecialChar
|
hi def link shoutEscapedChar SpecialChar
|
||||||
hi def link shoutEscapedLine String
|
hi def link shoutEscapedLine String
|
||||||
|
|
||||||
hi def link shoutWildcardLine WarningMsg
|
hi def link shoutWildcardLine WarningMsg
|
||||||
|
|
|
||||||
|
|
@ -196,12 +196,13 @@
|
||||||
<span class="output">Homebrew 5</span><span class="wildcard">...</span></code></pre>
|
<span class="output">Homebrew 5</span><span class="wildcard">...</span></code></pre>
|
||||||
<p><code class="wildcard">...</code> matches anything — inline or across lines.</p>
|
<p><code class="wildcard">...</code> matches anything — inline or across lines.</p>
|
||||||
<p><code class="exit-code">[1]</code> asserts the exit code.</p>
|
<p><code class="exit-code">[1]</code> asserts the exit code.</p>
|
||||||
<p><code class="dim">$#</code> starts a comment line — not executed, no output expected.</p>
|
<p><code class="dim">#</code> at the start of a line is a comment — not executed, no output expected.</p>
|
||||||
<pre><code><span class="prompt">$</span><span class="comment"># start the server</span>
|
<pre><code><span class="comment"># start the server</span>
|
||||||
<span class="prompt">$</span> <span class="cmd">my-server &</span>
|
<span class="prompt">$</span> <span class="cmd">my-server &</span>
|
||||||
<span class="prompt">$</span><span class="comment"># now test it</span>
|
<span class="comment"># now test it</span>
|
||||||
<span class="prompt">$</span> <span class="cmd">curl localhost:8080</span>
|
<span class="prompt">$</span> <span class="cmd">curl localhost:8080</span>
|
||||||
<span class="output">OK</span></code></pre>
|
<span class="output">OK</span></code></pre>
|
||||||
|
<p>If expected output starts with <code>#</code>, escape it with <code>\#</code>. <code>#</code> elsewhere in output is literal.</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user