Refactor and rename test macros (#415)
This commit is contained in:
parent
d065d1c54f
commit
415c84ea39
59
Cargo.lock
generated
59
Cargo.lock
generated
@ -96,6 +96,25 @@ dependencies = [
|
|||||||
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colored-diff"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ctor"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ctrlc"
|
name = "ctrlc"
|
||||||
version = "3.1.1"
|
version = "3.1.1"
|
||||||
@ -105,6 +124,11 @@ dependencies = [
|
|||||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "difference"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dotenv"
|
name = "dotenv"
|
||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
@ -180,6 +204,14 @@ dependencies = [
|
|||||||
"quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.7.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
@ -197,6 +229,7 @@ dependencies = [
|
|||||||
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"brev 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"brev 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"colored-diff 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"edit-distance 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"edit-distance 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -206,6 +239,7 @@ dependencies = [
|
|||||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"target 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"target 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -246,6 +280,25 @@ dependencies = [
|
|||||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "output_vt100"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pretty_assertions"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ctor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "0.4.27"
|
version = "0.4.27"
|
||||||
@ -499,7 +552,10 @@ dependencies = [
|
|||||||
"checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83"
|
"checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83"
|
||||||
"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
|
"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
|
||||||
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
||||||
|
"checksum colored-diff 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fcbd90537dc19162289fbce7e95c882dded30f4ed41044cf1470612528d7163"
|
||||||
|
"checksum ctor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3b4c17619643c1252b5f690084b82639dd7fac141c57c8e77a00e0148132092c"
|
||||||
"checksum ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "630391922b1b893692c6334369ff528dcc3a9d8061ccf4c803aa8f83cb13db5e"
|
"checksum ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "630391922b1b893692c6334369ff528dcc3a9d8061ccf4c803aa8f83cb13db5e"
|
||||||
|
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
|
||||||
"checksum dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d0a1279c96732bc6800ce6337b6a614697b0e74ae058dc03c62ebeb78b4d86"
|
"checksum dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d0a1279c96732bc6800ce6337b6a614697b0e74ae058dc03c62ebeb78b4d86"
|
||||||
"checksum edit-distance 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bbbaaaf38131deb9ca518a274a45bfdb8771f139517b073b16c2d3d32ae5037b"
|
"checksum edit-distance 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bbbaaaf38131deb9ca518a274a45bfdb8771f139517b073b16c2d3d32ae5037b"
|
||||||
"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
|
"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
|
||||||
@ -510,12 +566,15 @@ dependencies = [
|
|||||||
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||||
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
|
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
|
||||||
"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
|
"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
|
||||||
|
"checksum itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0d47946d458e94a1b7bcabbf6521ea7c037062c81f534615abcad76e84d4970d"
|
||||||
"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
|
"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
|
||||||
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
|
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
|
||||||
"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917"
|
"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917"
|
||||||
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
|
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
|
||||||
"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
|
"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
|
||||||
"checksum nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37e713a259ff641624b6cb20e3b12b2952313ba36b6823c0f16e6cfd9e5de17"
|
"checksum nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37e713a259ff641624b6cb20e3b12b2952313ba36b6823c0f16e6cfd9e5de17"
|
||||||
|
"checksum output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
|
||||||
|
"checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
|
||||||
"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
|
"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
|
||||||
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
|
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
|
||||||
"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
|
"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
|
||||||
|
@ -31,3 +31,5 @@ features = ["termination"]
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
executable-path = "1.0.0"
|
executable-path = "1.0.0"
|
||||||
|
pretty_assertions = "0.6.1"
|
||||||
|
colored-diff = "0.2.1"
|
||||||
|
@ -165,7 +165,7 @@ impl<'a, 'b> AssignmentEvaluator<'a, 'b> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::testing::parse_success;
|
use crate::testing::parse;
|
||||||
use brev::OutputError;
|
use brev::OutputError;
|
||||||
|
|
||||||
fn no_cwd_err() -> Result<PathBuf, String> {
|
fn no_cwd_err() -> Result<PathBuf, String> {
|
||||||
@ -174,7 +174,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn backtick_code() {
|
fn backtick_code() {
|
||||||
match parse_success("a:\n echo {{`f() { return 100; }; f`}}")
|
match parse("a:\n echo {{`f() { return 100; }; f`}}")
|
||||||
.run(&no_cwd_err(), &["a"], &Default::default())
|
.run(&no_cwd_err(), &["a"], &Default::default())
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
{
|
{
|
||||||
@ -203,7 +203,7 @@ recipe:
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
match parse_success(text)
|
match parse(text)
|
||||||
.run(&no_cwd_err(), &["recipe"], &configuration)
|
.run(&no_cwd_err(), &["recipe"], &configuration)
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
{
|
{
|
||||||
|
@ -93,7 +93,7 @@ impl<'a: 'b, 'b> AssignmentResolver<'a, 'b> {
|
|||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: circular_variable_dependency,
|
name: circular_variable_dependency,
|
||||||
input: "a = b\nb = a",
|
input: "a = b\nb = a",
|
||||||
offset: 0,
|
offset: 0,
|
||||||
@ -103,7 +103,7 @@ mod test {
|
|||||||
kind: CircularVariableDependency{variable: "a", circle: vec!["a", "b", "a"]},
|
kind: CircularVariableDependency{variable: "a", circle: vec!["a", "b", "a"]},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: self_variable_dependency,
|
name: self_variable_dependency,
|
||||||
input: "a = a",
|
input: "a = a",
|
||||||
offset: 0,
|
offset: 0,
|
||||||
@ -113,7 +113,7 @@ mod test {
|
|||||||
kind: CircularVariableDependency{variable: "a", circle: vec!["a", "a"]},
|
kind: CircularVariableDependency{variable: "a", circle: vec!["a", "a"]},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: unknown_expression_variable,
|
name: unknown_expression_variable,
|
||||||
input: "x = yy",
|
input: "x = yy",
|
||||||
offset: 4,
|
offset: 4,
|
||||||
@ -123,7 +123,7 @@ mod test {
|
|||||||
kind: UndefinedVariable{variable: "yy"},
|
kind: UndefinedVariable{variable: "yy"},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: unknown_function,
|
name: unknown_function,
|
||||||
input: "a = foo()",
|
input: "a = foo()",
|
||||||
offset: 4,
|
offset: 4,
|
||||||
|
@ -64,3 +64,6 @@ pub(crate) use crate::command_ext::CommandExt;
|
|||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
pub(crate) use crate::range_ext::RangeExt;
|
pub(crate) use crate::range_ext::RangeExt;
|
||||||
|
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
pub(crate) use crate::ordinal::Ordinal;
|
||||||
|
@ -118,8 +118,8 @@ impl<'a> Display for CompilationError<'a> {
|
|||||||
f,
|
f,
|
||||||
"Alias `{}` defined on `{}` shadows recipe defined on `{}`",
|
"Alias `{}` defined on `{}` shadows recipe defined on `{}`",
|
||||||
alias,
|
alias,
|
||||||
self.line + 1,
|
self.line.ordinal(),
|
||||||
recipe_line + 1,
|
recipe_line.ordinal(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
CircularRecipeDependency { recipe, ref circle } => {
|
CircularRecipeDependency { recipe, ref circle } => {
|
||||||
@ -181,8 +181,8 @@ impl<'a> Display for CompilationError<'a> {
|
|||||||
f,
|
f,
|
||||||
"Alias `{}` first defined on line `{}` is redefined on line `{}`",
|
"Alias `{}` first defined on line `{}` is redefined on line `{}`",
|
||||||
alias,
|
alias,
|
||||||
first + 1,
|
first.ordinal(),
|
||||||
self.line + 1,
|
self.line.ordinal(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
DuplicateDependency { recipe, dependency } => {
|
DuplicateDependency { recipe, dependency } => {
|
||||||
@ -197,8 +197,8 @@ impl<'a> Display for CompilationError<'a> {
|
|||||||
f,
|
f,
|
||||||
"Recipe `{}` first defined on line {} is redefined on line {}",
|
"Recipe `{}` first defined on line {} is redefined on line {}",
|
||||||
recipe,
|
recipe,
|
||||||
first + 1,
|
first.ordinal(),
|
||||||
self.line + 1
|
self.line.ordinal()
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
DependencyHasParameters { recipe, dependency } => {
|
DependencyHasParameters { recipe, dependency } => {
|
||||||
|
@ -205,7 +205,7 @@ mod test {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use crate::runtime_error::RuntimeError::*;
|
use crate::runtime_error::RuntimeError::*;
|
||||||
use crate::testing::parse_success;
|
use crate::testing::parse;
|
||||||
|
|
||||||
fn no_cwd_err() -> Result<PathBuf, String> {
|
fn no_cwd_err() -> Result<PathBuf, String> {
|
||||||
Err(String::from("no cwd in tests"))
|
Err(String::from("no cwd in tests"))
|
||||||
@ -213,7 +213,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn unknown_recipes() {
|
fn unknown_recipes() {
|
||||||
match parse_success("a:\nb:\nc:")
|
match parse("a:\nb:\nc:")
|
||||||
.run(&no_cwd_err(), &["a", "x", "y", "z"], &Default::default())
|
.run(&no_cwd_err(), &["a", "x", "y", "z"], &Default::default())
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
{
|
{
|
||||||
@ -246,7 +246,7 @@ a:
|
|||||||
x
|
x
|
||||||
";
|
";
|
||||||
|
|
||||||
match parse_success(text)
|
match parse(text)
|
||||||
.run(&no_cwd_err(), &["a"], &Default::default())
|
.run(&no_cwd_err(), &["a"], &Default::default())
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
{
|
{
|
||||||
@ -265,7 +265,7 @@ a:
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn code_error() {
|
fn code_error() {
|
||||||
match parse_success("fail:\n @exit 100")
|
match parse("fail:\n @exit 100")
|
||||||
.run(&no_cwd_err(), &["fail"], &Default::default())
|
.run(&no_cwd_err(), &["fail"], &Default::default())
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
{
|
{
|
||||||
@ -288,7 +288,7 @@ a:
|
|||||||
a return code:
|
a return code:
|
||||||
@x() { {{return}} {{code + "0"}}; }; x"#;
|
@x() { {{return}} {{code + "0"}}; }; x"#;
|
||||||
|
|
||||||
match parse_success(text)
|
match parse(text)
|
||||||
.run(&no_cwd_err(), &["a", "return", "15"], &Default::default())
|
.run(&no_cwd_err(), &["a", "return", "15"], &Default::default())
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
{
|
{
|
||||||
@ -307,7 +307,7 @@ a return code:
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn missing_some_arguments() {
|
fn missing_some_arguments() {
|
||||||
match parse_success("a b c d:")
|
match parse("a b c d:")
|
||||||
.run(&no_cwd_err(), &["a", "b", "c"], &Default::default())
|
.run(&no_cwd_err(), &["a", "b", "c"], &Default::default())
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
{
|
{
|
||||||
@ -331,7 +331,7 @@ a return code:
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn missing_some_arguments_variadic() {
|
fn missing_some_arguments_variadic() {
|
||||||
match parse_success("a b c +d:")
|
match parse("a b c +d:")
|
||||||
.run(&no_cwd_err(), &["a", "B", "C"], &Default::default())
|
.run(&no_cwd_err(), &["a", "B", "C"], &Default::default())
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
{
|
{
|
||||||
@ -355,7 +355,7 @@ a return code:
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn missing_all_arguments() {
|
fn missing_all_arguments() {
|
||||||
match parse_success("a b c d:\n echo {{b}}{{c}}{{d}}")
|
match parse("a b c d:\n echo {{b}}{{c}}{{d}}")
|
||||||
.run(&no_cwd_err(), &["a"], &Default::default())
|
.run(&no_cwd_err(), &["a"], &Default::default())
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
{
|
{
|
||||||
@ -379,7 +379,7 @@ a return code:
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn missing_some_defaults() {
|
fn missing_some_defaults() {
|
||||||
match parse_success("a b c d='hello':")
|
match parse("a b c d='hello':")
|
||||||
.run(&no_cwd_err(), &["a", "b"], &Default::default())
|
.run(&no_cwd_err(), &["a", "b"], &Default::default())
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
{
|
{
|
||||||
@ -403,7 +403,7 @@ a return code:
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn missing_all_defaults() {
|
fn missing_all_defaults() {
|
||||||
match parse_success("a b c='r' d='h':")
|
match parse("a b c='r' d='h':")
|
||||||
.run(&no_cwd_err(), &["a"], &Default::default())
|
.run(&no_cwd_err(), &["a"], &Default::default())
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
{
|
{
|
||||||
@ -430,7 +430,7 @@ a return code:
|
|||||||
let mut configuration: Configuration = Default::default();
|
let mut configuration: Configuration = Default::default();
|
||||||
configuration.overrides.insert("foo", "bar");
|
configuration.overrides.insert("foo", "bar");
|
||||||
configuration.overrides.insert("baz", "bob");
|
configuration.overrides.insert("baz", "bob");
|
||||||
match parse_success("a:\n echo {{`f() { return 100; }; f`}}")
|
match parse("a:\n echo {{`f() { return 100; }; f`}}")
|
||||||
.run(&no_cwd_err(), &["a"], &configuration)
|
.run(&no_cwd_err(), &["a"], &configuration)
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
{
|
{
|
||||||
@ -458,7 +458,7 @@ wut:
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
match parse_success(text)
|
match parse(text)
|
||||||
.run(&no_cwd_err(), &["wut"], &configuration)
|
.run(&no_cwd_err(), &["wut"], &configuration)
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
{
|
{
|
||||||
|
163
src/lexer.rs
163
src/lexer.rs
@ -626,9 +626,40 @@ impl<'a> Lexer<'a> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use crate::testing::token_summary;
|
fn summary(tokens: &[Token]) -> String {
|
||||||
|
use TokenKind::*;
|
||||||
|
|
||||||
macro_rules! summary_test {
|
tokens
|
||||||
|
.iter()
|
||||||
|
.map(|t| match t.kind {
|
||||||
|
At => "@",
|
||||||
|
Backtick => "`",
|
||||||
|
Colon => ":",
|
||||||
|
ColonEquals => ":=",
|
||||||
|
Comma => ",",
|
||||||
|
Comment => "#",
|
||||||
|
Dedent => "<",
|
||||||
|
Eof => ".",
|
||||||
|
Eol => "$",
|
||||||
|
Equals => "=",
|
||||||
|
Indent => ">",
|
||||||
|
InterpolationEnd => "}",
|
||||||
|
InterpolationStart => "{",
|
||||||
|
Line => "^",
|
||||||
|
Name => "N",
|
||||||
|
ParenL => "(",
|
||||||
|
ParenR => ")",
|
||||||
|
Plus => "+",
|
||||||
|
StringRaw => "'",
|
||||||
|
StringCooked => "\"",
|
||||||
|
Text => "_",
|
||||||
|
Whitespace => " ",
|
||||||
|
})
|
||||||
|
.collect::<Vec<&str>>()
|
||||||
|
.join("")
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! lex_test {
|
||||||
($name:ident, $input:expr, $expected:expr $(,)*) => {
|
($name:ident, $input:expr, $expected:expr $(,)*) => {
|
||||||
#[test]
|
#[test]
|
||||||
fn $name() {
|
fn $name() {
|
||||||
@ -640,116 +671,78 @@ mod tests {
|
|||||||
.map(Token::lexeme)
|
.map(Token::lexeme)
|
||||||
.collect::<Vec<&str>>()
|
.collect::<Vec<&str>>()
|
||||||
.join("");
|
.join("");
|
||||||
let actual = token_summary(&tokens);
|
let actual = summary(&tokens);
|
||||||
if actual != expected {
|
|
||||||
panic!(
|
use pretty_assertions::assert_eq;
|
||||||
"token summary mismatch:\nexpected: {}\ngot: {}\n",
|
|
||||||
expected, actual
|
assert_eq!(actual, expected, "token summary mismatch");
|
||||||
);
|
|
||||||
}
|
assert_eq!(input, roundtrip, "token round-trip not equal");
|
||||||
assert_eq!(input, roundtrip);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! error_test {
|
lex_test! {
|
||||||
(
|
|
||||||
name: $name:ident,
|
|
||||||
input: $input:expr,
|
|
||||||
offset: $offset:expr,
|
|
||||||
line: $line:expr,
|
|
||||||
column: $column:expr,
|
|
||||||
width: $width:expr,
|
|
||||||
kind: $kind:expr,
|
|
||||||
) => {
|
|
||||||
#[test]
|
|
||||||
fn $name() {
|
|
||||||
let input = $input;
|
|
||||||
|
|
||||||
let expected = CompilationError {
|
|
||||||
text: input,
|
|
||||||
offset: $offset,
|
|
||||||
line: $line,
|
|
||||||
column: $column,
|
|
||||||
width: $width,
|
|
||||||
kind: $kind,
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(error) = Lexer::lex(input) {
|
|
||||||
assert_eq!(error.text, expected.text);
|
|
||||||
assert_eq!(error.offset, expected.offset);
|
|
||||||
assert_eq!(error.line, expected.line);
|
|
||||||
assert_eq!(error.column, expected.column);
|
|
||||||
assert_eq!(error.kind, expected.kind);
|
|
||||||
assert_eq!(error, expected);
|
|
||||||
} else {
|
|
||||||
panic!("tokenize succeeded but expected: {}\n{}", expected, input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
summary_test! {
|
|
||||||
name,
|
name,
|
||||||
"foo",
|
"foo",
|
||||||
"N.",
|
"N.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
comment,
|
comment,
|
||||||
"# hello",
|
"# hello",
|
||||||
"#.",
|
"#.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
backtick,
|
backtick,
|
||||||
"`echo`",
|
"`echo`",
|
||||||
"`.",
|
"`.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
raw_string,
|
raw_string,
|
||||||
"'hello'",
|
"'hello'",
|
||||||
"'.",
|
"'.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
cooked_string,
|
cooked_string,
|
||||||
r#""hello""#,
|
r#""hello""#,
|
||||||
r#""."#,
|
r#""."#,
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
export_concatination,
|
export_concatination,
|
||||||
"export foo = 'foo' + 'bar'",
|
"export foo = 'foo' + 'bar'",
|
||||||
"N N = ' + '.",
|
"N N = ' + '.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
export_complex,
|
export_complex,
|
||||||
"export foo = ('foo' + 'bar') + `baz`",
|
"export foo = ('foo' + 'bar') + `baz`",
|
||||||
"N N = (' + ') + `.",
|
"N N = (' + ') + `.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
eol_linefeed,
|
eol_linefeed,
|
||||||
"\n",
|
"\n",
|
||||||
"$.",
|
"$.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
eol_carriage_return_linefeed,
|
eol_carriage_return_linefeed,
|
||||||
"\r\n",
|
"\r\n",
|
||||||
"$.",
|
"$.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
indented_line,
|
indented_line,
|
||||||
"foo:\n a",
|
"foo:\n a",
|
||||||
"N:$>^_<.",
|
"N:$>^_<.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
indented_block,
|
indented_block,
|
||||||
r##"foo:
|
r##"foo:
|
||||||
a
|
a
|
||||||
@ -759,7 +752,7 @@ mod tests {
|
|||||||
"N:$>^_$ ^_$ ^_$<.",
|
"N:$>^_$ ^_$ ^_$<.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
indented_block_followed_by_item,
|
indented_block_followed_by_item,
|
||||||
"foo:
|
"foo:
|
||||||
a
|
a
|
||||||
@ -767,7 +760,7 @@ b:",
|
|||||||
"N:$>^_$<N:.",
|
"N:$>^_$<N:.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
indented_block_followed_by_blank,
|
indented_block_followed_by_blank,
|
||||||
"foo:
|
"foo:
|
||||||
a
|
a
|
||||||
@ -776,13 +769,13 @@ b:",
|
|||||||
"N:$>^_$^$<N:.",
|
"N:$>^_$^$<N:.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
indented_line_containing_unpaired_carriage_return,
|
indented_line_containing_unpaired_carriage_return,
|
||||||
"foo:\n \r \n",
|
"foo:\n \r \n",
|
||||||
"N:$>^_$<.",
|
"N:$>^_$<.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
indented_blocks,
|
indented_blocks,
|
||||||
"
|
"
|
||||||
b: a
|
b: a
|
||||||
@ -800,19 +793,19 @@ c: b
|
|||||||
"$N: N$>^_$^$<N:$>^_$ ^_$^$<N: N$>^_$^$<N: N$>^_<.",
|
"$N: N$>^_$^$<N:$>^_$ ^_$^$<N: N$>^_$^$<N: N$>^_<.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
interpolation_empty,
|
interpolation_empty,
|
||||||
"hello:\n echo {{}}",
|
"hello:\n echo {{}}",
|
||||||
"N:$>^_{}<.",
|
"N:$>^_{}<.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
interpolation_expression,
|
interpolation_expression,
|
||||||
"hello:\n echo {{`echo hello` + `echo goodbye`}}",
|
"hello:\n echo {{`echo hello` + `echo goodbye`}}",
|
||||||
"N:$>^_{` + `}<.",
|
"N:$>^_{` + `}<.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
tokenize_names,
|
tokenize_names,
|
||||||
"\
|
"\
|
||||||
foo
|
foo
|
||||||
@ -822,13 +815,13 @@ test123",
|
|||||||
"N$N$N$N.",
|
"N$N$N$N.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
tokenize_indented_line,
|
tokenize_indented_line,
|
||||||
"foo:\n a",
|
"foo:\n a",
|
||||||
"N:$>^_<.",
|
"N:$>^_<.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
tokenize_indented_block,
|
tokenize_indented_block,
|
||||||
r##"foo:
|
r##"foo:
|
||||||
a
|
a
|
||||||
@ -838,13 +831,13 @@ test123",
|
|||||||
"N:$>^_$ ^_$ ^_$<.",
|
"N:$>^_$ ^_$ ^_$<.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
tokenize_strings,
|
tokenize_strings,
|
||||||
r#"a = "'a'" + '"b"' + "'c'" + '"d"'#echo hello"#,
|
r#"a = "'a'" + '"b"' + "'c'" + '"d"'#echo hello"#,
|
||||||
r#"N = " + ' + " + '#."#,
|
r#"N = " + ' + " + '#."#,
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
tokenize_recipe_interpolation_eol,
|
tokenize_recipe_interpolation_eol,
|
||||||
"foo: # some comment
|
"foo: # some comment
|
||||||
{{hello}}
|
{{hello}}
|
||||||
@ -852,7 +845,7 @@ test123",
|
|||||||
"N: #$>^{N}$<.",
|
"N: #$>^{N}$<.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
tokenize_recipe_interpolation_eof,
|
tokenize_recipe_interpolation_eof,
|
||||||
"foo: # more comments
|
"foo: # more comments
|
||||||
{{hello}}
|
{{hello}}
|
||||||
@ -861,19 +854,19 @@ test123",
|
|||||||
"N: #$>^{N}$<#$.",
|
"N: #$>^{N}$<#$.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
tokenize_recipe_complex_interpolation_expression,
|
tokenize_recipe_complex_interpolation_expression,
|
||||||
"foo: #lol\n {{a + b + \"z\" + blarg}}",
|
"foo: #lol\n {{a + b + \"z\" + blarg}}",
|
||||||
"N: #$>^{N + N + \" + N}<.",
|
"N: #$>^{N + N + \" + N}<.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
tokenize_recipe_multiple_interpolations,
|
tokenize_recipe_multiple_interpolations,
|
||||||
"foo:,#ok\n {{a}}0{{b}}1{{c}}",
|
"foo:,#ok\n {{a}}0{{b}}1{{c}}",
|
||||||
"N:,#$>^{N}_{N}_{N}<.",
|
"N:,#$>^{N}_{N}_{N}<.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
tokenize_junk,
|
tokenize_junk,
|
||||||
"bob
|
"bob
|
||||||
|
|
||||||
@ -882,7 +875,7 @@ hello blah blah blah : a b c #whatever
|
|||||||
"N$$N N N N : N N N #$ .",
|
"N$$N N N N : N N N #$ .",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
tokenize_empty_lines,
|
tokenize_empty_lines,
|
||||||
"
|
"
|
||||||
# this does something
|
# this does something
|
||||||
@ -899,7 +892,7 @@ hello:
|
|||||||
"$#$N:$>^_$ ^_$^$ ^_$^$ ^_$^$<#$ .",
|
"$#$N:$>^_$ ^_$^$ ^_$^$ ^_$^$<#$ .",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
tokenize_comment_before_variable,
|
tokenize_comment_before_variable,
|
||||||
"
|
"
|
||||||
#
|
#
|
||||||
@ -910,25 +903,25 @@ echo:
|
|||||||
"$#$N='$N:$>^_{N}$ <.",
|
"$#$N='$N:$>^_{N}$ <.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
tokenize_interpolation_backticks,
|
tokenize_interpolation_backticks,
|
||||||
"hello:\n echo {{`echo hello` + `echo goodbye`}}",
|
"hello:\n echo {{`echo hello` + `echo goodbye`}}",
|
||||||
"N:$>^_{` + `}<.",
|
"N:$>^_{` + `}<.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
tokenize_empty_interpolation,
|
tokenize_empty_interpolation,
|
||||||
"hello:\n echo {{}}",
|
"hello:\n echo {{}}",
|
||||||
"N:$>^_{}<.",
|
"N:$>^_{}<.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
tokenize_assignment_backticks,
|
tokenize_assignment_backticks,
|
||||||
"a = `echo hello` + `echo goodbye`",
|
"a = `echo hello` + `echo goodbye`",
|
||||||
"N = ` + `.",
|
"N = ` + `.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
tokenize_multiple,
|
tokenize_multiple,
|
||||||
"
|
"
|
||||||
hello:
|
hello:
|
||||||
@ -947,19 +940,19 @@ bob:
|
|||||||
"$N:$>^_$ ^_$^$ ^_$^$ ^_$^$<#$N:$>^_$ <.",
|
"$N:$>^_$ ^_$^$ ^_$^$ ^_$^$<#$N:$>^_$ <.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
tokenize_comment,
|
tokenize_comment,
|
||||||
"a:=#",
|
"a:=#",
|
||||||
"N:=#."
|
"N:=#."
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
tokenize_comment_with_bang,
|
tokenize_comment_with_bang,
|
||||||
"a:=#foo!",
|
"a:=#foo!",
|
||||||
"N:=#."
|
"N:=#."
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
tokenize_order,
|
tokenize_order,
|
||||||
r"
|
r"
|
||||||
b: a
|
b: a
|
||||||
@ -977,19 +970,19 @@ c: b
|
|||||||
"$N: N$>^_$^$<N:$>^_$ ^_$^$<N: N$>^_$^$<N: N$>^_<.",
|
"$N: N$>^_$^$<N:$>^_$ ^_$^$<N: N$>^_$^$<N: N$>^_<.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
tokenize_parens,
|
tokenize_parens,
|
||||||
r"((())) )abc(+",
|
r"((())) )abc(+",
|
||||||
"((())) )N(+.",
|
"((())) )N(+.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
crlf_newline,
|
crlf_newline,
|
||||||
"#\r\n#asdf\r\n",
|
"#\r\n#asdf\r\n",
|
||||||
"#$#$.",
|
"#$#$.",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
lex_test! {
|
||||||
multiple_recipes,
|
multiple_recipes,
|
||||||
"a:\n foo\nb:",
|
"a:\n foo\nb:",
|
||||||
"N:$>^_$<N:.",
|
"N:$>^_$<N:.",
|
||||||
|
@ -31,6 +31,7 @@ mod justfile;
|
|||||||
mod lexer;
|
mod lexer;
|
||||||
mod load_dotenv;
|
mod load_dotenv;
|
||||||
mod misc;
|
mod misc;
|
||||||
|
mod ordinal;
|
||||||
mod parameter;
|
mod parameter;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod platform;
|
mod platform;
|
||||||
|
@ -65,7 +65,7 @@ pub fn write_error_context(
|
|||||||
) -> Result<(), fmt::Error> {
|
) -> Result<(), fmt::Error> {
|
||||||
let width = if width == 0 { 1 } else { width };
|
let width = if width == 0 { 1 } else { width };
|
||||||
|
|
||||||
let line_number = line + 1;
|
let line_number = line.ordinal();
|
||||||
let red = Color::fmt(f).error();
|
let red = Color::fmt(f).error();
|
||||||
match text.lines().nth(line) {
|
match text.lines().nth(line) {
|
||||||
Some(line) => {
|
Some(line) => {
|
||||||
|
10
src/ordinal.rs
Normal file
10
src/ordinal.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
pub trait Ordinal {
|
||||||
|
/// Convert an index starting at 0 to an ordinal starting at 1
|
||||||
|
fn ordinal(self) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ordinal for usize {
|
||||||
|
fn ordinal(self) -> Self {
|
||||||
|
self + 1
|
||||||
|
}
|
||||||
|
}
|
135
src/parser.rs
135
src/parser.rs
@ -523,34 +523,27 @@ impl<'a> Parser<'a> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::testing::parse_success;
|
use crate::testing::parse;
|
||||||
|
|
||||||
macro_rules! summary_test {
|
macro_rules! parse_test {
|
||||||
($name:ident, $input:expr, $expected:expr $(,)*) => {
|
($name:ident, $input:expr, $expected:expr $(,)*) => {
|
||||||
#[test]
|
#[test]
|
||||||
fn $name() {
|
fn $name() {
|
||||||
let input = $input;
|
let input = $input;
|
||||||
let expected = $expected;
|
let expected = $expected;
|
||||||
let justfile = parse_success(input);
|
let justfile = parse(input);
|
||||||
let actual = format!("{:#}", justfile);
|
let actual = format!("{:#}", justfile);
|
||||||
if actual != expected {
|
use pretty_assertions::assert_eq;
|
||||||
println!("got:\n\"{}\"\n", actual);
|
|
||||||
println!("expected:\n\"{}\"", expected);
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
|
||||||
println!("Re-parsing...");
|
println!("Re-parsing...");
|
||||||
let reparsed = parse_success(&actual);
|
let reparsed = parse(&actual);
|
||||||
let redumped = format!("{:#}", reparsed);
|
let redumped = format!("{:#}", reparsed);
|
||||||
if redumped != actual {
|
|
||||||
println!("reparsed:\n\"{}\"\n", redumped);
|
|
||||||
println!("expected:\n\"{}\"", actual);
|
|
||||||
assert_eq!(redumped, actual);
|
assert_eq!(redumped, actual);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parse_empty,
|
parse_empty,
|
||||||
"
|
"
|
||||||
|
|
||||||
@ -561,7 +554,7 @@ mod test {
|
|||||||
"",
|
"",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parse_string_default,
|
parse_string_default,
|
||||||
r#"
|
r#"
|
||||||
|
|
||||||
@ -572,7 +565,7 @@ foo a="b\t":
|
|||||||
r#"foo a="b\t":"#,
|
r#"foo a="b\t":"#,
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parse_multiple,
|
parse_multiple,
|
||||||
r#"
|
r#"
|
||||||
a:
|
a:
|
||||||
@ -583,7 +576,7 @@ b:
|
|||||||
b:"#,
|
b:"#,
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parse_variadic,
|
parse_variadic,
|
||||||
r#"
|
r#"
|
||||||
|
|
||||||
@ -594,7 +587,7 @@ foo +a:
|
|||||||
r#"foo +a:"#,
|
r#"foo +a:"#,
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parse_variadic_string_default,
|
parse_variadic_string_default,
|
||||||
r#"
|
r#"
|
||||||
|
|
||||||
@ -605,7 +598,7 @@ foo +a="Hello":
|
|||||||
r#"foo +a="Hello":"#,
|
r#"foo +a="Hello":"#,
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parse_raw_string_default,
|
parse_raw_string_default,
|
||||||
r#"
|
r#"
|
||||||
|
|
||||||
@ -616,7 +609,7 @@ foo a='b\t':
|
|||||||
r#"foo a='b\t':"#,
|
r#"foo a='b\t':"#,
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parse_export,
|
parse_export,
|
||||||
r#"
|
r#"
|
||||||
export a := "hello"
|
export a := "hello"
|
||||||
@ -625,7 +618,7 @@ export a := "hello"
|
|||||||
r#"export a := "hello""#,
|
r#"export a := "hello""#,
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parse_alias_after_target,
|
parse_alias_after_target,
|
||||||
r#"
|
r#"
|
||||||
foo:
|
foo:
|
||||||
@ -638,7 +631,7 @@ foo:
|
|||||||
echo a"#
|
echo a"#
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parse_alias_before_target,
|
parse_alias_before_target,
|
||||||
r#"
|
r#"
|
||||||
alias f := foo
|
alias f := foo
|
||||||
@ -651,7 +644,7 @@ foo:
|
|||||||
echo a"#
|
echo a"#
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parse_alias_with_comment,
|
parse_alias_with_comment,
|
||||||
r#"
|
r#"
|
||||||
alias f := foo #comment
|
alias f := foo #comment
|
||||||
@ -664,7 +657,7 @@ foo:
|
|||||||
echo a"#
|
echo a"#
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parse_complex,
|
parse_complex,
|
||||||
"
|
"
|
||||||
x:
|
x:
|
||||||
@ -702,7 +695,7 @@ y:
|
|||||||
z:"
|
z:"
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parse_shebang,
|
parse_shebang,
|
||||||
"
|
"
|
||||||
practicum := 'hello'
|
practicum := 'hello'
|
||||||
@ -721,13 +714,13 @@ install:
|
|||||||
fi",
|
fi",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parse_simple_shebang,
|
parse_simple_shebang,
|
||||||
"a:\n #!\n print(1)",
|
"a:\n #!\n print(1)",
|
||||||
"a:\n #!\n print(1)",
|
"a:\n #!\n print(1)",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parse_assignments,
|
parse_assignments,
|
||||||
r#"a := "0"
|
r#"a := "0"
|
||||||
c := a + b + a + b
|
c := a + b + a + b
|
||||||
@ -740,7 +733,7 @@ b := "1"
|
|||||||
c := a + b + a + b"#,
|
c := a + b + a + b"#,
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parse_assignment_backticks,
|
parse_assignment_backticks,
|
||||||
"a := `echo hello`
|
"a := `echo hello`
|
||||||
c := a + b + a + b
|
c := a + b + a + b
|
||||||
@ -752,7 +745,7 @@ b := `echo goodbye`
|
|||||||
c := a + b + a + b",
|
c := a + b + a + b",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parse_interpolation_backticks,
|
parse_interpolation_backticks,
|
||||||
r#"a:
|
r#"a:
|
||||||
echo {{ `echo hello` + "blarg" }} {{ `echo bob` }}"#,
|
echo {{ `echo hello` + "blarg" }} {{ `echo bob` }}"#,
|
||||||
@ -760,25 +753,25 @@ c := a + b + a + b",
|
|||||||
echo {{`echo hello` + "blarg"}} {{`echo bob`}}"#,
|
echo {{`echo hello` + "blarg"}} {{`echo bob`}}"#,
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
eof_test,
|
eof_test,
|
||||||
"x:\ny:\nz:\na b c: x y z",
|
"x:\ny:\nz:\na b c: x y z",
|
||||||
"a b c: x y z\n\nx:\n\ny:\n\nz:",
|
"a b c: x y z\n\nx:\n\ny:\n\nz:",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
string_quote_escape,
|
string_quote_escape,
|
||||||
r#"a := "hello\"""#,
|
r#"a := "hello\"""#,
|
||||||
r#"a := "hello\"""#,
|
r#"a := "hello\"""#,
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
string_escapes,
|
string_escapes,
|
||||||
r#"a := "\n\t\r\"\\""#,
|
r#"a := "\n\t\r\"\\""#,
|
||||||
r#"a := "\n\t\r\"\\""#,
|
r#"a := "\n\t\r\"\\""#,
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parameters,
|
parameters,
|
||||||
"a b c:
|
"a b c:
|
||||||
{{b}} {{c}}",
|
{{b}} {{c}}",
|
||||||
@ -786,7 +779,7 @@ c := a + b + a + b",
|
|||||||
{{b}} {{c}}",
|
{{b}} {{c}}",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
unary_functions,
|
unary_functions,
|
||||||
"
|
"
|
||||||
x := arch()
|
x := arch()
|
||||||
@ -799,7 +792,7 @@ a:
|
|||||||
{{os()}} {{os_family()}}",
|
{{os()}} {{os_family()}}",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
env_functions,
|
env_functions,
|
||||||
r#"
|
r#"
|
||||||
x := env_var('foo',)
|
x := env_var('foo',)
|
||||||
@ -812,7 +805,7 @@ a:
|
|||||||
{{env_var_or_default('foo' + 'bar', 'baz')}} {{env_var(env_var("baz"))}}"#,
|
{{env_var_or_default('foo' + 'bar', 'baz')}} {{env_var(env_var("baz"))}}"#,
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parameter_default_string,
|
parameter_default_string,
|
||||||
r#"
|
r#"
|
||||||
f x="abc":
|
f x="abc":
|
||||||
@ -820,7 +813,7 @@ f x="abc":
|
|||||||
r#"f x="abc":"#,
|
r#"f x="abc":"#,
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parameter_default_raw_string,
|
parameter_default_raw_string,
|
||||||
r#"
|
r#"
|
||||||
f x='abc':
|
f x='abc':
|
||||||
@ -828,7 +821,7 @@ f x='abc':
|
|||||||
r#"f x='abc':"#,
|
r#"f x='abc':"#,
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parameter_default_backtick,
|
parameter_default_backtick,
|
||||||
r#"
|
r#"
|
||||||
f x=`echo hello`:
|
f x=`echo hello`:
|
||||||
@ -836,7 +829,7 @@ f x=`echo hello`:
|
|||||||
r#"f x=`echo hello`:"#,
|
r#"f x=`echo hello`:"#,
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parameter_default_concatination_string,
|
parameter_default_concatination_string,
|
||||||
r#"
|
r#"
|
||||||
f x=(`echo hello` + "foo"):
|
f x=(`echo hello` + "foo"):
|
||||||
@ -844,7 +837,7 @@ f x=(`echo hello` + "foo"):
|
|||||||
r#"f x=(`echo hello` + "foo"):"#,
|
r#"f x=(`echo hello` + "foo"):"#,
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parameter_default_concatination_variable,
|
parameter_default_concatination_variable,
|
||||||
r#"
|
r#"
|
||||||
x := "10"
|
x := "10"
|
||||||
@ -855,7 +848,7 @@ f y=(`echo hello` + x) +z="foo":
|
|||||||
f y=(`echo hello` + x) +z="foo":"#,
|
f y=(`echo hello` + x) +z="foo":"#,
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
parameter_default_multiple,
|
parameter_default_multiple,
|
||||||
r#"
|
r#"
|
||||||
x := "10"
|
x := "10"
|
||||||
@ -866,20 +859,20 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):
|
|||||||
f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
concatination_in_group,
|
concatination_in_group,
|
||||||
"x := ('0' + '1')",
|
"x := ('0' + '1')",
|
||||||
"x := ('0' + '1')",
|
"x := ('0' + '1')",
|
||||||
}
|
}
|
||||||
|
|
||||||
summary_test! {
|
parse_test! {
|
||||||
string_in_group,
|
string_in_group,
|
||||||
"x := ('0' )",
|
"x := ('0' )",
|
||||||
"x := ('0')",
|
"x := ('0')",
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
summary_test! {
|
parse_test! {
|
||||||
escaped_dos_newlines,
|
escaped_dos_newlines,
|
||||||
"@spam:\r
|
"@spam:\r
|
||||||
\t{ \\\r
|
\t{ \\\r
|
||||||
@ -896,7 +889,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
} | less",
|
} | less",
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: duplicate_alias,
|
name: duplicate_alias,
|
||||||
input: "alias foo = bar\nalias foo = baz",
|
input: "alias foo = bar\nalias foo = baz",
|
||||||
offset: 22,
|
offset: 22,
|
||||||
@ -906,7 +899,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: DuplicateAlias { alias: "foo", first: 0 },
|
kind: DuplicateAlias { alias: "foo", first: 0 },
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: alias_syntax_multiple_rhs,
|
name: alias_syntax_multiple_rhs,
|
||||||
input: "alias foo = bar baz",
|
input: "alias foo = bar baz",
|
||||||
offset: 16,
|
offset: 16,
|
||||||
@ -916,7 +909,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: UnexpectedToken { expected: vec![Eol, Eof], found: Name },
|
kind: UnexpectedToken { expected: vec![Eol, Eof], found: Name },
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: alias_syntax_no_rhs,
|
name: alias_syntax_no_rhs,
|
||||||
input: "alias foo = \n",
|
input: "alias foo = \n",
|
||||||
offset: 12,
|
offset: 12,
|
||||||
@ -926,7 +919,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: UnexpectedToken {expected: vec![Name], found:Eol},
|
kind: UnexpectedToken {expected: vec![Name], found:Eol},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: unknown_alias_target,
|
name: unknown_alias_target,
|
||||||
input: "alias foo = bar\n",
|
input: "alias foo = bar\n",
|
||||||
offset: 6,
|
offset: 6,
|
||||||
@ -936,7 +929,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: UnknownAliasTarget {alias: "foo", target: "bar"},
|
kind: UnknownAliasTarget {alias: "foo", target: "bar"},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: alias_shadows_recipe_before,
|
name: alias_shadows_recipe_before,
|
||||||
input: "bar: \n echo bar\nalias foo = bar\nfoo:\n echo foo",
|
input: "bar: \n echo bar\nalias foo = bar\nfoo:\n echo foo",
|
||||||
offset: 23,
|
offset: 23,
|
||||||
@ -946,7 +939,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: AliasShadowsRecipe {alias: "foo", recipe_line: 3},
|
kind: AliasShadowsRecipe {alias: "foo", recipe_line: 3},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: alias_shadows_recipe_after,
|
name: alias_shadows_recipe_after,
|
||||||
input: "foo:\n echo foo\nalias foo = bar\nbar:\n echo bar",
|
input: "foo:\n echo foo\nalias foo = bar\nbar:\n echo bar",
|
||||||
offset: 22,
|
offset: 22,
|
||||||
@ -956,7 +949,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: AliasShadowsRecipe { alias: "foo", recipe_line: 0 },
|
kind: AliasShadowsRecipe { alias: "foo", recipe_line: 0 },
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: missing_colon,
|
name: missing_colon,
|
||||||
input: "a b c\nd e f",
|
input: "a b c\nd e f",
|
||||||
offset: 5,
|
offset: 5,
|
||||||
@ -966,7 +959,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: UnexpectedToken{expected: vec![Name, Plus, Colon], found: Eol},
|
kind: UnexpectedToken{expected: vec![Name, Plus, Colon], found: Eol},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: missing_default_eol,
|
name: missing_default_eol,
|
||||||
input: "hello arg=\n",
|
input: "hello arg=\n",
|
||||||
offset: 10,
|
offset: 10,
|
||||||
@ -976,7 +969,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: UnexpectedToken{expected: vec![Name, StringCooked], found: Eol},
|
kind: UnexpectedToken{expected: vec![Name, StringCooked], found: Eol},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: missing_default_eof,
|
name: missing_default_eof,
|
||||||
input: "hello arg=",
|
input: "hello arg=",
|
||||||
offset: 10,
|
offset: 10,
|
||||||
@ -986,7 +979,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: UnexpectedToken{expected: vec![Name, StringCooked], found: Eof},
|
kind: UnexpectedToken{expected: vec![Name, StringCooked], found: Eof},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: parameter_after_variadic,
|
name: parameter_after_variadic,
|
||||||
input: "foo +a bbb:",
|
input: "foo +a bbb:",
|
||||||
offset: 7,
|
offset: 7,
|
||||||
@ -996,7 +989,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: ParameterFollowsVariadicParameter{parameter: "bbb"},
|
kind: ParameterFollowsVariadicParameter{parameter: "bbb"},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: required_after_default,
|
name: required_after_default,
|
||||||
input: "hello arg='foo' bar:",
|
input: "hello arg='foo' bar:",
|
||||||
offset: 16,
|
offset: 16,
|
||||||
@ -1006,7 +999,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: RequiredParameterFollowsDefaultParameter{parameter: "bar"},
|
kind: RequiredParameterFollowsDefaultParameter{parameter: "bar"},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: missing_eol,
|
name: missing_eol,
|
||||||
input: "a b c: z =",
|
input: "a b c: z =",
|
||||||
offset: 9,
|
offset: 9,
|
||||||
@ -1016,7 +1009,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: UnexpectedToken{expected: vec![Name, Eol, Eof], found: Equals},
|
kind: UnexpectedToken{expected: vec![Name, Eol, Eof], found: Equals},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: duplicate_parameter,
|
name: duplicate_parameter,
|
||||||
input: "a b b:",
|
input: "a b b:",
|
||||||
offset: 4,
|
offset: 4,
|
||||||
@ -1026,7 +1019,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: DuplicateParameter{recipe: "a", parameter: "b"},
|
kind: DuplicateParameter{recipe: "a", parameter: "b"},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: parameter_shadows_varible,
|
name: parameter_shadows_varible,
|
||||||
input: "foo = \"h\"\na foo:",
|
input: "foo = \"h\"\na foo:",
|
||||||
offset: 12,
|
offset: 12,
|
||||||
@ -1036,7 +1029,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: ParameterShadowsVariable{parameter: "foo"},
|
kind: ParameterShadowsVariable{parameter: "foo"},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: dependency_has_parameters,
|
name: dependency_has_parameters,
|
||||||
input: "foo arg:\nb: foo",
|
input: "foo arg:\nb: foo",
|
||||||
offset: 12,
|
offset: 12,
|
||||||
@ -1046,7 +1039,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: DependencyHasParameters{recipe: "b", dependency: "foo"},
|
kind: DependencyHasParameters{recipe: "b", dependency: "foo"},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: duplicate_dependency,
|
name: duplicate_dependency,
|
||||||
input: "a b c: b c z z",
|
input: "a b c: b c z z",
|
||||||
offset: 13,
|
offset: 13,
|
||||||
@ -1056,7 +1049,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: DuplicateDependency{recipe: "a", dependency: "z"},
|
kind: DuplicateDependency{recipe: "a", dependency: "z"},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: duplicate_recipe,
|
name: duplicate_recipe,
|
||||||
input: "a:\nb:\na:",
|
input: "a:\nb:\na:",
|
||||||
offset: 6,
|
offset: 6,
|
||||||
@ -1066,7 +1059,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: DuplicateRecipe{recipe: "a", first: 0},
|
kind: DuplicateRecipe{recipe: "a", first: 0},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: duplicate_variable,
|
name: duplicate_variable,
|
||||||
input: "a = \"0\"\na = \"0\"",
|
input: "a = \"0\"\na = \"0\"",
|
||||||
offset: 8,
|
offset: 8,
|
||||||
@ -1076,7 +1069,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: DuplicateVariable{variable: "a"},
|
kind: DuplicateVariable{variable: "a"},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: extra_whitespace,
|
name: extra_whitespace,
|
||||||
input: "a:\n blah\n blarg",
|
input: "a:\n blah\n blarg",
|
||||||
offset: 10,
|
offset: 10,
|
||||||
@ -1086,7 +1079,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: ExtraLeadingWhitespace,
|
kind: ExtraLeadingWhitespace,
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: interpolation_outside_of_recipe,
|
name: interpolation_outside_of_recipe,
|
||||||
input: "{{",
|
input: "{{",
|
||||||
offset: 0,
|
offset: 0,
|
||||||
@ -1096,7 +1089,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: UnexpectedToken{expected: vec![Name, At], found: InterpolationStart},
|
kind: UnexpectedToken{expected: vec![Name, At], found: InterpolationStart},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: unclosed_parenthesis_in_expression,
|
name: unclosed_parenthesis_in_expression,
|
||||||
input: "x = foo(",
|
input: "x = foo(",
|
||||||
offset: 8,
|
offset: 8,
|
||||||
@ -1106,7 +1099,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: UnexpectedToken{expected: vec![Name, StringCooked, ParenR], found: Eof},
|
kind: UnexpectedToken{expected: vec![Name, StringCooked, ParenR], found: Eof},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: unclosed_parenthesis_in_interpolation,
|
name: unclosed_parenthesis_in_interpolation,
|
||||||
input: "a:\n echo {{foo(}}",
|
input: "a:\n echo {{foo(}}",
|
||||||
offset: 15,
|
offset: 15,
|
||||||
@ -1116,7 +1109,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: UnexpectedToken{expected: vec![Name, StringCooked, ParenR], found: InterpolationEnd},
|
kind: UnexpectedToken{expected: vec![Name, StringCooked, ParenR], found: InterpolationEnd},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: plus_following_parameter,
|
name: plus_following_parameter,
|
||||||
input: "a b c+:",
|
input: "a b c+:",
|
||||||
offset: 5,
|
offset: 5,
|
||||||
@ -1126,7 +1119,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
kind: UnexpectedToken{expected: vec![Name], found: Plus},
|
kind: UnexpectedToken{expected: vec![Name], found: Plus},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: bad_export,
|
name: bad_export,
|
||||||
input: "export a",
|
input: "export a",
|
||||||
offset: 8,
|
offset: 8,
|
||||||
@ -1157,14 +1150,14 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for justfile in justfiles {
|
for justfile in justfiles {
|
||||||
parse_success(&justfile);
|
parse(&justfile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_recipe_lines() {
|
fn empty_recipe_lines() {
|
||||||
let text = "a:";
|
let text = "a:";
|
||||||
let justfile = parse_success(&text);
|
let justfile = parse(&text);
|
||||||
|
|
||||||
assert_eq!(justfile.recipes["a"].lines.len(), 0);
|
assert_eq!(justfile.recipes["a"].lines.len(), 0);
|
||||||
}
|
}
|
||||||
@ -1172,7 +1165,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
#[test]
|
#[test]
|
||||||
fn simple_recipe_lines() {
|
fn simple_recipe_lines() {
|
||||||
let text = "a:\n foo";
|
let text = "a:\n foo";
|
||||||
let justfile = parse_success(&text);
|
let justfile = parse(&text);
|
||||||
|
|
||||||
assert_eq!(justfile.recipes["a"].lines.len(), 1);
|
assert_eq!(justfile.recipes["a"].lines.len(), 1);
|
||||||
}
|
}
|
||||||
@ -1185,7 +1178,7 @@ f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
|
|||||||
b:
|
b:
|
||||||
";
|
";
|
||||||
|
|
||||||
let justfile = parse_success(&text);
|
let justfile = parse(&text);
|
||||||
|
|
||||||
assert_eq!(justfile.recipes["a"].lines.len(), 1);
|
assert_eq!(justfile.recipes["a"].lines.len(), 1);
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,7 @@ impl<'a, 'b> RecipeResolver<'a, 'b> {
|
|||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: circular_recipe_dependency,
|
name: circular_recipe_dependency,
|
||||||
input: "a: b\nb: a",
|
input: "a: b\nb: a",
|
||||||
offset: 8,
|
offset: 8,
|
||||||
@ -164,7 +164,7 @@ mod test {
|
|||||||
kind: CircularRecipeDependency{recipe: "b", circle: vec!["a", "b", "a"]},
|
kind: CircularRecipeDependency{recipe: "b", circle: vec!["a", "b", "a"]},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: self_recipe_dependency,
|
name: self_recipe_dependency,
|
||||||
input: "a: a",
|
input: "a: a",
|
||||||
offset: 3,
|
offset: 3,
|
||||||
@ -174,7 +174,7 @@ mod test {
|
|||||||
kind: CircularRecipeDependency{recipe: "a", circle: vec!["a", "a"]},
|
kind: CircularRecipeDependency{recipe: "a", circle: vec!["a", "a"]},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: unknown_dependency,
|
name: unknown_dependency,
|
||||||
input: "a: b",
|
input: "a: b",
|
||||||
offset: 3,
|
offset: 3,
|
||||||
@ -184,7 +184,7 @@ mod test {
|
|||||||
kind: UnknownDependency{recipe: "a", unknown: "b"},
|
kind: UnknownDependency{recipe: "a", unknown: "b"},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: unknown_interpolation_variable,
|
name: unknown_interpolation_variable,
|
||||||
input: "x:\n {{ hello}}",
|
input: "x:\n {{ hello}}",
|
||||||
offset: 9,
|
offset: 9,
|
||||||
@ -194,7 +194,7 @@ mod test {
|
|||||||
kind: UndefinedVariable{variable: "hello"},
|
kind: UndefinedVariable{variable: "hello"},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: unknown_second_interpolation_variable,
|
name: unknown_second_interpolation_variable,
|
||||||
input: "wtf=\"x\"\nx:\n echo\n foo {{wtf}} {{ lol }}",
|
input: "wtf=\"x\"\nx:\n echo\n foo {{wtf}} {{ lol }}",
|
||||||
offset: 33,
|
offset: 33,
|
||||||
@ -204,7 +204,7 @@ mod test {
|
|||||||
kind: UndefinedVariable{variable: "lol"},
|
kind: UndefinedVariable{variable: "lol"},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: unknown_function_in_interpolation,
|
name: unknown_function_in_interpolation,
|
||||||
input: "a:\n echo {{bar()}}",
|
input: "a:\n echo {{bar()}}",
|
||||||
offset: 11,
|
offset: 11,
|
||||||
@ -214,7 +214,7 @@ mod test {
|
|||||||
kind: UnknownFunction{function: "bar"},
|
kind: UnknownFunction{function: "bar"},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: unknown_function_in_default,
|
name: unknown_function_in_default,
|
||||||
input: "a f=baz():",
|
input: "a f=baz():",
|
||||||
offset: 4,
|
offset: 4,
|
||||||
@ -224,7 +224,7 @@ mod test {
|
|||||||
kind: UnknownFunction{function: "baz"},
|
kind: UnknownFunction{function: "baz"},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_error_test! {
|
error_test! {
|
||||||
name: unknown_variable_in_default,
|
name: unknown_variable_in_default,
|
||||||
input: "a f=foo:",
|
input: "a f=foo:",
|
||||||
offset: 4,
|
offset: 4,
|
||||||
|
@ -1,46 +1,13 @@
|
|||||||
use crate::common::*;
|
use crate::common::*;
|
||||||
|
|
||||||
pub fn parse_success(text: &str) -> Justfile {
|
pub fn parse(text: &str) -> Justfile {
|
||||||
match Parser::parse(text) {
|
match Parser::parse(text) {
|
||||||
Ok(justfile) => justfile,
|
Ok(justfile) => justfile,
|
||||||
Err(error) => panic!("Expected successful parse but got error:\n{}", error),
|
Err(error) => panic!("Expected successful parse but got error:\n {}", error),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn token_summary(tokens: &[Token]) -> String {
|
macro_rules! error_test {
|
||||||
use TokenKind::*;
|
|
||||||
|
|
||||||
tokens
|
|
||||||
.iter()
|
|
||||||
.map(|t| match t.kind {
|
|
||||||
At => "@",
|
|
||||||
Backtick => "`",
|
|
||||||
Colon => ":",
|
|
||||||
ColonEquals => ":=",
|
|
||||||
Comma => ",",
|
|
||||||
Comment => "#",
|
|
||||||
Dedent => "<",
|
|
||||||
Eof => ".",
|
|
||||||
Eol => "$",
|
|
||||||
Equals => "=",
|
|
||||||
Indent => ">",
|
|
||||||
InterpolationEnd => "}",
|
|
||||||
InterpolationStart => "{",
|
|
||||||
Line => "^",
|
|
||||||
Name => "N",
|
|
||||||
ParenL => "(",
|
|
||||||
ParenR => ")",
|
|
||||||
Plus => "+",
|
|
||||||
StringRaw => "'",
|
|
||||||
StringCooked => "\"",
|
|
||||||
Text => "_",
|
|
||||||
Whitespace => " ",
|
|
||||||
})
|
|
||||||
.collect::<Vec<&str>>()
|
|
||||||
.join("")
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! compilation_error_test {
|
|
||||||
(
|
(
|
||||||
name: $name:ident,
|
name: $name:ident,
|
||||||
input: $input:expr,
|
input: $input:expr,
|
||||||
@ -52,33 +19,28 @@ macro_rules! compilation_error_test {
|
|||||||
) => {
|
) => {
|
||||||
#[test]
|
#[test]
|
||||||
fn $name() {
|
fn $name() {
|
||||||
let input = $input;
|
let text: &str = $input;
|
||||||
|
let offset: usize = $offset;
|
||||||
|
let column: usize = $column;
|
||||||
|
let width: usize = $width;
|
||||||
|
let line: usize = $line;
|
||||||
|
let kind: CompilationErrorKind = $kind;
|
||||||
|
|
||||||
let expected = crate::compilation_error::CompilationError {
|
let expected = CompilationError {
|
||||||
text: input,
|
text,
|
||||||
offset: $offset,
|
offset,
|
||||||
line: $line,
|
line,
|
||||||
column: $column,
|
column,
|
||||||
width: $width,
|
width,
|
||||||
kind: $kind,
|
kind,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut tokens = Lexer::lex(input).unwrap();
|
match Parser::parse(text) {
|
||||||
|
Ok(_) => panic!("Compilation succeeded but expected: {}\n{}", expected, text),
|
||||||
tokens.retain(|token| token.kind != TokenKind::Whitespace);
|
Err(actual) => {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
let parser = crate::parser::Parser::new(input, tokens);
|
assert_eq!(actual, expected);
|
||||||
|
}
|
||||||
if let Err(error) = parser.justfile() {
|
|
||||||
assert_eq!(error.text, expected.text);
|
|
||||||
assert_eq!(error.offset, expected.offset);
|
|
||||||
assert_eq!(error.line, expected.line);
|
|
||||||
assert_eq!(error.column, expected.column);
|
|
||||||
assert_eq!(error.width, expected.width);
|
|
||||||
assert_eq!(error.kind, expected.kind);
|
|
||||||
assert_eq!(error, expected);
|
|
||||||
} else {
|
|
||||||
panic!("parse succeeded but expected: {}\n{}", expected, input);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use colored_diff::PrettyDifference;
|
||||||
use executable_path::executable_path;
|
use executable_path::executable_path;
|
||||||
use libc::{EXIT_FAILURE, EXIT_SUCCESS};
|
use libc::{EXIT_FAILURE, EXIT_SUCCESS};
|
||||||
use std::{
|
use std::{
|
||||||
@ -93,10 +94,14 @@ fn integration_test(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let stdout = str::from_utf8(&output.stdout).unwrap();
|
let stdout = str::from_utf8(&output.stdout).unwrap();
|
||||||
|
|
||||||
if stdout != expected_stdout {
|
if stdout != expected_stdout {
|
||||||
println!(
|
println!(
|
||||||
"bad stdout:\ngot:\n{}\n\nexpected:\n{}",
|
"bad stdout:\n {}",
|
||||||
stdout, expected_stdout
|
PrettyDifference {
|
||||||
|
expected: expected_stdout,
|
||||||
|
actual: stdout
|
||||||
|
},
|
||||||
);
|
);
|
||||||
failure = true;
|
failure = true;
|
||||||
}
|
}
|
||||||
@ -104,8 +109,11 @@ fn integration_test(
|
|||||||
let stderr = str::from_utf8(&output.stderr).unwrap();
|
let stderr = str::from_utf8(&output.stderr).unwrap();
|
||||||
if stderr != expected_stderr {
|
if stderr != expected_stderr {
|
||||||
println!(
|
println!(
|
||||||
"bad stderr:\ngot:\n{}\n\nexpected:\n{}",
|
"bad stderr: {}",
|
||||||
stderr, expected_stderr
|
PrettyDifference {
|
||||||
|
expected: expected_stderr,
|
||||||
|
actual: stderr
|
||||||
|
},
|
||||||
);
|
);
|
||||||
failure = true;
|
failure = true;
|
||||||
}
|
}
|
||||||
@ -148,9 +156,13 @@ fn integration_test(
|
|||||||
let reparsed = String::from_utf8(output.stdout).unwrap();
|
let reparsed = String::from_utf8(output.stdout).unwrap();
|
||||||
|
|
||||||
if reparsed != dumped {
|
if reparsed != dumped {
|
||||||
print!("expected:\n{}", reparsed);
|
println!(
|
||||||
print!("got:\n{}", dumped);
|
"reparse mismatch:\n {}",
|
||||||
assert_eq!(reparsed, dumped);
|
PrettyDifference {
|
||||||
|
expected: &dumped,
|
||||||
|
actual: &reparsed
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user