mirror of
https://github.com/nushell/nushell.git
synced 2024-11-24 17:34:00 +01:00
Add initial nu-test-support port (#913)
* Add initial nu-test-support port * finish changing binary name * Oops, these aren't Windows-safe tests
This commit is contained in:
parent
cbdc0e2010
commit
cc1b784e3d
222
Cargo.lock
generated
222
Cargo.lock
generated
@ -246,6 +246,18 @@ version = "0.13.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bigdecimal"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6aaf33151a6429fe9211d1b276eafdf70cdff28b071e76c0b0e1503221ea3744"
|
||||||
|
dependencies = [
|
||||||
|
"num-bigint 0.4.3",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
@ -908,40 +920,6 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "engine-q"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"assert_cmd",
|
|
||||||
"crossterm",
|
|
||||||
"crossterm_winapi",
|
|
||||||
"ctrlc",
|
|
||||||
"log",
|
|
||||||
"miette",
|
|
||||||
"nu-ansi-term",
|
|
||||||
"nu-cli",
|
|
||||||
"nu-color-config",
|
|
||||||
"nu-command",
|
|
||||||
"nu-engine",
|
|
||||||
"nu-json",
|
|
||||||
"nu-parser",
|
|
||||||
"nu-path",
|
|
||||||
"nu-plugin",
|
|
||||||
"nu-pretty-hex",
|
|
||||||
"nu-protocol",
|
|
||||||
"nu-system",
|
|
||||||
"nu-table",
|
|
||||||
"nu-term-grid",
|
|
||||||
"nu_plugin_example",
|
|
||||||
"nu_plugin_gstat",
|
|
||||||
"nu_plugin_inc",
|
|
||||||
"nu_plugin_query",
|
|
||||||
"pretty_assertions",
|
|
||||||
"pretty_env_logger",
|
|
||||||
"reedline",
|
|
||||||
"tempfile",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "env_logger"
|
name = "env_logger"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
@ -955,6 +933,16 @@ dependencies = [
|
|||||||
"termcolor",
|
"termcolor",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_logger"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "erased-serde"
|
name = "erased-serde"
|
||||||
version = "0.3.16"
|
version = "0.3.16"
|
||||||
@ -1212,6 +1200,18 @@ dependencies = [
|
|||||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getset"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ghost"
|
name = "ghost"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
@ -1275,6 +1275,16 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hamcrest2"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49f837c62de05dc9cc71ff6486cd85de8856a330395ae338a04bfcefe5e91075"
|
||||||
|
dependencies = [
|
||||||
|
"num 0.2.1",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hash32"
|
name = "hash32"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@ -2020,6 +2030,45 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nu"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"assert_cmd",
|
||||||
|
"crossterm",
|
||||||
|
"crossterm_winapi",
|
||||||
|
"ctrlc",
|
||||||
|
"hamcrest2",
|
||||||
|
"itertools",
|
||||||
|
"log",
|
||||||
|
"miette",
|
||||||
|
"nu-ansi-term",
|
||||||
|
"nu-cli",
|
||||||
|
"nu-color-config",
|
||||||
|
"nu-command",
|
||||||
|
"nu-engine",
|
||||||
|
"nu-json",
|
||||||
|
"nu-parser",
|
||||||
|
"nu-path",
|
||||||
|
"nu-plugin",
|
||||||
|
"nu-pretty-hex",
|
||||||
|
"nu-protocol",
|
||||||
|
"nu-system",
|
||||||
|
"nu-table",
|
||||||
|
"nu-term-grid",
|
||||||
|
"nu-test-support",
|
||||||
|
"nu_plugin_example",
|
||||||
|
"nu_plugin_gstat",
|
||||||
|
"nu_plugin_inc",
|
||||||
|
"nu_plugin_query",
|
||||||
|
"pretty_assertions",
|
||||||
|
"pretty_env_logger",
|
||||||
|
"reedline",
|
||||||
|
"rstest",
|
||||||
|
"serial_test",
|
||||||
|
"tempfile",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-ansi-term"
|
name = "nu-ansi-term"
|
||||||
version = "0.42.0"
|
version = "0.42.0"
|
||||||
@ -2073,10 +2122,12 @@ dependencies = [
|
|||||||
"csv",
|
"csv",
|
||||||
"dialoguer",
|
"dialoguer",
|
||||||
"digest 0.10.0",
|
"digest 0.10.0",
|
||||||
|
"dirs-next",
|
||||||
"dtparse",
|
"dtparse",
|
||||||
"eml-parser",
|
"eml-parser",
|
||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
"glob",
|
"glob",
|
||||||
|
"hamcrest2",
|
||||||
"htmlescape",
|
"htmlescape",
|
||||||
"ical",
|
"ical",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
@ -2098,10 +2149,13 @@ dependencies = [
|
|||||||
"nu-system",
|
"nu-system",
|
||||||
"nu-table",
|
"nu-table",
|
||||||
"nu-term-grid",
|
"nu-term-grid",
|
||||||
|
"nu-test-support",
|
||||||
"num 0.4.0",
|
"num 0.4.0",
|
||||||
"pathdiff",
|
"pathdiff",
|
||||||
"polars",
|
"polars",
|
||||||
"quick-xml 0.22.0",
|
"quick-xml 0.22.0",
|
||||||
|
"quickcheck",
|
||||||
|
"quickcheck_macros",
|
||||||
"rand 0.8.4",
|
"rand 0.8.4",
|
||||||
"rayon",
|
"rayon",
|
||||||
"regex",
|
"regex",
|
||||||
@ -2251,6 +2305,22 @@ dependencies = [
|
|||||||
"unicode-width",
|
"unicode-width",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nu-test-support"
|
||||||
|
version = "0.43.0"
|
||||||
|
dependencies = [
|
||||||
|
"bigdecimal",
|
||||||
|
"chrono",
|
||||||
|
"getset",
|
||||||
|
"glob",
|
||||||
|
"hamcrest2",
|
||||||
|
"indexmap",
|
||||||
|
"nu-path",
|
||||||
|
"nu-protocol",
|
||||||
|
"num-bigint 0.4.3",
|
||||||
|
"tempfile",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu_plugin_example"
|
name = "nu_plugin_example"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -2339,6 +2409,7 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2875,7 +2946,7 @@ version = "0.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d"
|
checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"env_logger",
|
"env_logger 0.7.1",
|
||||||
"log",
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2893,6 +2964,30 @@ dependencies = [
|
|||||||
"unicode-width",
|
"unicode-width",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error-attr",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"version_check 0.9.3",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error-attr"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"version_check 0.9.3",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-hack"
|
name = "proc-macro-hack"
|
||||||
version = "0.5.19"
|
version = "0.5.19"
|
||||||
@ -2948,6 +3043,28 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quickcheck"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6"
|
||||||
|
dependencies = [
|
||||||
|
"env_logger 0.8.4",
|
||||||
|
"log",
|
||||||
|
"rand 0.8.4",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quickcheck_macros"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b22a693222d716a9587786f37ac3f6b4faedb5b80c23914e7303ff5a1d8016e9"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.10"
|
version = "1.0.10"
|
||||||
@ -3224,6 +3341,19 @@ dependencies = [
|
|||||||
"xmlparser",
|
"xmlparser",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rstest"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d912f35156a3f99a66ee3e11ac2e0b3f34ac85a07e05263d05a7e2c8810d616f"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustc_version",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-argon2"
|
name = "rust-argon2"
|
||||||
version = "0.8.3"
|
version = "0.8.3"
|
||||||
@ -3487,6 +3617,28 @@ dependencies = [
|
|||||||
"yaml-rust",
|
"yaml-rust",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serial_test"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e0bccbcf40c8938196944a3da0e133e031a33f4d6b72db3bda3cc556e361905d"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"parking_lot",
|
||||||
|
"serial_test_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serial_test_derive"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2acd6defeddb41eb60bb468f8825d0cfd0c2a76bc03bfd235b6a1dc4f6a1ad5"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "servo_arc"
|
name = "servo_arc"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
14
Cargo.toml
14
Cargo.toml
@ -1,8 +1,8 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "engine-q"
|
name = "nu"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
default-run = "engine-q"
|
default-run = "nu"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
@ -36,6 +36,7 @@ nu-plugin = { path = "./crates/nu-plugin", optional = true }
|
|||||||
nu-system = { path = "./crates/nu-system"}
|
nu-system = { path = "./crates/nu-system"}
|
||||||
nu-table = { path = "./crates/nu-table" }
|
nu-table = { path = "./crates/nu-table" }
|
||||||
nu-term-grid = { path = "./crates/nu-term-grid" }
|
nu-term-grid = { path = "./crates/nu-term-grid" }
|
||||||
|
|
||||||
nu-ansi-term = "0.42.0"
|
nu-ansi-term = "0.42.0"
|
||||||
nu-color-config = { path = "./crates/nu-color-config" }
|
nu-color-config = { path = "./crates/nu-color-config" }
|
||||||
miette = "3.0.0"
|
miette = "3.0.0"
|
||||||
@ -52,11 +53,14 @@ nu_plugin_gstat = { version = "0.1.0", path = "./crates/nu_plugin_gstat", option
|
|||||||
nu_plugin_query = { version = "0.1.0", path = "./crates/nu_plugin_query", optional = true }
|
nu_plugin_query = { version = "0.1.0", path = "./crates/nu_plugin_query", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
nu-test-support = { path="./crates/nu-test-support" }
|
||||||
tempfile = "3.2.0"
|
tempfile = "3.2.0"
|
||||||
assert_cmd = "2.0.2"
|
assert_cmd = "2.0.2"
|
||||||
pretty_assertions = "1.0.0"
|
pretty_assertions = "1.0.0"
|
||||||
|
serial_test = "0.5.1"
|
||||||
[build-dependencies]
|
hamcrest2 = "0.3.0"
|
||||||
|
rstest = "0.12.0"
|
||||||
|
itertools = "0.10.3"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
plugin = ["nu-plugin", "nu-parser/plugin", "nu-command/plugin", "nu-protocol/plugin", "nu-engine/plugin"]
|
plugin = ["nu-plugin", "nu-parser/plugin", "nu-command/plugin", "nu-protocol/plugin", "nu-engine/plugin"]
|
||||||
@ -119,5 +123,5 @@ required-features = ["query"]
|
|||||||
|
|
||||||
# Main nu binary
|
# Main nu binary
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "engine-q"
|
name = "nu"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
@ -15,6 +15,7 @@ nu-pretty-hex = { path = "../nu-pretty-hex" }
|
|||||||
nu-protocol = { path = "../nu-protocol" }
|
nu-protocol = { path = "../nu-protocol" }
|
||||||
nu-table = { path = "../nu-table" }
|
nu-table = { path = "../nu-table" }
|
||||||
nu-term-grid = { path = "../nu-term-grid" }
|
nu-term-grid = { path = "../nu-term-grid" }
|
||||||
|
nu-test-support = { path = "../nu-test-support" }
|
||||||
nu-parser = { path = "../nu-parser" }
|
nu-parser = { path = "../nu-parser" }
|
||||||
nu-system = { path = "../nu-system" }
|
nu-system = { path = "../nu-system" }
|
||||||
# nu-ansi-term = { path = "../nu-ansi-term" }
|
# nu-ansi-term = { path = "../nu-ansi-term" }
|
||||||
@ -95,3 +96,9 @@ dataframe = ["polars", "num"]
|
|||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
shadow-rs = "0.8.1"
|
shadow-rs = "0.8.1"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
hamcrest2 = "0.3.0"
|
||||||
|
dirs-next = "2.0.0"
|
||||||
|
quickcheck = "1.0.3"
|
||||||
|
quickcheck_macros = "1.0.0"
|
@ -1028,13 +1028,25 @@ fn compute(size: i64, unit: Unit, span: Span) -> Value {
|
|||||||
val: size * 1000 * 1000 * 1000 * 60 * 60,
|
val: size * 1000 * 1000 * 1000 * 60 * 60,
|
||||||
span,
|
span,
|
||||||
},
|
},
|
||||||
Unit::Day => Value::Duration {
|
Unit::Day => match size.checked_mul(1000 * 1000 * 1000 * 60 * 60 * 24) {
|
||||||
val: size * 1000 * 1000 * 1000 * 60 * 60 * 24,
|
Some(val) => Value::Duration { val, span },
|
||||||
span,
|
None => Value::Error {
|
||||||
|
error: ShellError::SpannedLabeledError(
|
||||||
|
"duration too large".into(),
|
||||||
|
"duration too large".into(),
|
||||||
|
span,
|
||||||
|
),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Unit::Week => Value::Duration {
|
Unit::Week => match size.checked_mul(1000 * 1000 * 1000 * 60 * 60 * 24 * 7) {
|
||||||
val: size * 1000 * 1000 * 1000 * 60 * 60 * 24 * 7,
|
Some(val) => Value::Duration { val, span },
|
||||||
span,
|
None => Value::Error {
|
||||||
|
error: ShellError::SpannedLabeledError(
|
||||||
|
"duration too large".into(),
|
||||||
|
"duration too large".into(),
|
||||||
|
span,
|
||||||
|
),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,34 @@ pub fn math_result_type(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Operator::Multiply | Operator::Pow => match (&lhs.ty, &rhs.ty) {
|
Operator::Multiply => match (&lhs.ty, &rhs.ty) {
|
||||||
|
(Type::Int, Type::Int) => (Type::Int, None),
|
||||||
|
(Type::Float, Type::Int) => (Type::Float, None),
|
||||||
|
(Type::Int, Type::Float) => (Type::Float, None),
|
||||||
|
(Type::Float, Type::Float) => (Type::Float, None),
|
||||||
|
|
||||||
|
(Type::Filesize, Type::Int) => (Type::Filesize, None),
|
||||||
|
(Type::Int, Type::Filesize) => (Type::Filesize, None),
|
||||||
|
(Type::Duration, Type::Int) => (Type::Filesize, None),
|
||||||
|
(Type::Int, Type::Duration) => (Type::Filesize, None),
|
||||||
|
|
||||||
|
(Type::Unknown, _) => (Type::Unknown, None),
|
||||||
|
(_, Type::Unknown) => (Type::Unknown, None),
|
||||||
|
_ => {
|
||||||
|
*op = Expression::garbage(op.span);
|
||||||
|
(
|
||||||
|
Type::Unknown,
|
||||||
|
Some(ParseError::UnsupportedOperation(
|
||||||
|
op.span,
|
||||||
|
lhs.span,
|
||||||
|
lhs.ty.clone(),
|
||||||
|
rhs.span,
|
||||||
|
rhs.ty.clone(),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Operator::Pow => match (&lhs.ty, &rhs.ty) {
|
||||||
(Type::Int, Type::Int) => (Type::Int, None),
|
(Type::Int, Type::Int) => (Type::Int, None),
|
||||||
(Type::Float, Type::Int) => (Type::Float, None),
|
(Type::Float, Type::Int) => (Type::Float, None),
|
||||||
(Type::Int, Type::Float) => (Type::Float, None),
|
(Type::Int, Type::Float) => (Type::Float, None),
|
||||||
@ -118,6 +145,9 @@ pub fn math_result_type(
|
|||||||
(Type::Filesize, Type::Filesize) => (Type::Float, None),
|
(Type::Filesize, Type::Filesize) => (Type::Float, None),
|
||||||
(Type::Duration, Type::Duration) => (Type::Float, None),
|
(Type::Duration, Type::Duration) => (Type::Float, None),
|
||||||
|
|
||||||
|
(Type::Filesize, Type::Int) => (Type::Filesize, None),
|
||||||
|
(Type::Duration, Type::Int) => (Type::Duration, None),
|
||||||
|
|
||||||
(Type::Unknown, _) => (Type::Unknown, None),
|
(Type::Unknown, _) => (Type::Unknown, None),
|
||||||
(_, Type::Unknown) => (Type::Unknown, None),
|
(_, Type::Unknown) => (Type::Unknown, None),
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -7,9 +7,7 @@ use super::{EngineState, Stack};
|
|||||||
pub trait Command: Send + Sync + CommandClone {
|
pub trait Command: Send + Sync + CommandClone {
|
||||||
fn name(&self) -> &str;
|
fn name(&self) -> &str;
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature;
|
||||||
Signature::new(self.name()).desc(self.usage()).filter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str;
|
fn usage(&self) -> &str;
|
||||||
|
|
||||||
|
@ -1122,6 +1122,30 @@ impl Value {
|
|||||||
val: lhs * rhs,
|
val: lhs * rhs,
|
||||||
span,
|
span,
|
||||||
}),
|
}),
|
||||||
|
(Value::Int { val: lhs, .. }, Value::Filesize { val: rhs, .. }) => {
|
||||||
|
Ok(Value::Filesize {
|
||||||
|
val: *lhs * *rhs,
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
(Value::Filesize { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
|
||||||
|
Ok(Value::Filesize {
|
||||||
|
val: *lhs * *rhs,
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
(Value::Int { val: lhs, .. }, Value::Duration { val: rhs, .. }) => {
|
||||||
|
Ok(Value::Duration {
|
||||||
|
val: *lhs * *rhs,
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
(Value::Duration { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
|
||||||
|
Ok(Value::Duration {
|
||||||
|
val: *lhs * *rhs,
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
}
|
||||||
(Value::CustomValue { val: lhs, span }, rhs) => {
|
(Value::CustomValue { val: lhs, span }, rhs) => {
|
||||||
lhs.operation(*span, Operator::Multiply, op, rhs)
|
lhs.operation(*span, Operator::Multiply, op, rhs)
|
||||||
}
|
}
|
||||||
@ -1220,6 +1244,26 @@ impl Value {
|
|||||||
Err(ShellError::DivisionByZero(op))
|
Err(ShellError::DivisionByZero(op))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(Value::Filesize { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
|
||||||
|
if *rhs != 0 {
|
||||||
|
Ok(Value::Filesize {
|
||||||
|
val: lhs / rhs,
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(ShellError::DivisionByZero(op))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Value::Duration { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
|
||||||
|
if *rhs != 0 {
|
||||||
|
Ok(Value::Duration {
|
||||||
|
val: lhs / rhs,
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(ShellError::DivisionByZero(op))
|
||||||
|
}
|
||||||
|
}
|
||||||
(Value::CustomValue { val: lhs, span }, rhs) => {
|
(Value::CustomValue { val: lhs, span }, rhs) => {
|
||||||
lhs.operation(*span, Operator::Divide, op, rhs)
|
lhs.operation(*span, Operator::Divide, op, rhs)
|
||||||
}
|
}
|
||||||
|
23
crates/nu-test-support/Cargo.toml
Normal file
23
crates/nu-test-support/Cargo.toml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
[package]
|
||||||
|
authors = ["The Nu Project Contributors"]
|
||||||
|
description = "Support for writing Nushell tests"
|
||||||
|
edition = "2018"
|
||||||
|
license = "MIT"
|
||||||
|
name = "nu-test-support"
|
||||||
|
version = "0.43.0"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
doctest = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
nu-path = { path="../nu-path" }
|
||||||
|
nu-protocol = { path="../nu-protocol" }
|
||||||
|
|
||||||
|
bigdecimal = { package = "bigdecimal", version = "0.3.0", features = ["serde"] }
|
||||||
|
chrono = "0.4.19"
|
||||||
|
getset = "0.1.1"
|
||||||
|
glob = "0.3.0"
|
||||||
|
indexmap = { version="1.6.1", features=["serde-1"] }
|
||||||
|
num-bigint = { version="0.4.3", features=["serde"] }
|
||||||
|
tempfile = "3.2.0"
|
||||||
|
hamcrest2 = "0.3.0"
|
53
crates/nu-test-support/src/commands.rs
Normal file
53
crates/nu-test-support/src/commands.rs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// use nu_protocol::{
|
||||||
|
// ast::{Expr, Expression},
|
||||||
|
// Span, Spanned, Type,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// pub struct ExternalBuilder {
|
||||||
|
// name: String,
|
||||||
|
// args: Vec<String>,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl ExternalBuilder {
|
||||||
|
// pub fn for_name(name: &str) -> ExternalBuilder {
|
||||||
|
// ExternalBuilder {
|
||||||
|
// name: name.to_string(),
|
||||||
|
// args: vec![],
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn arg(&mut self, value: &str) -> &mut Self {
|
||||||
|
// self.args.push(value.to_string());
|
||||||
|
// self
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn build(&mut self) -> ExternalCommand {
|
||||||
|
// let mut path = crate::fs::binaries();
|
||||||
|
// path.push(&self.name);
|
||||||
|
|
||||||
|
// let name = Spanned {
|
||||||
|
// item: path.to_string_lossy().to_string(),
|
||||||
|
// span: Span::new(0, 0),
|
||||||
|
// };
|
||||||
|
|
||||||
|
// let args = self
|
||||||
|
// .args
|
||||||
|
// .iter()
|
||||||
|
// .map(|arg| Expression {
|
||||||
|
// expr: Expr::String(arg.to_string()),
|
||||||
|
// span: Span::new(0, 0),
|
||||||
|
// ty: Type::Unknown,
|
||||||
|
// custom_completion: None,
|
||||||
|
// })
|
||||||
|
// .collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// ExternalCommand {
|
||||||
|
// name: name.to_string(),
|
||||||
|
// name_tag: Tag::unknown(),
|
||||||
|
// args: ExternalArgs {
|
||||||
|
// list: args,
|
||||||
|
// span: name.span,
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
277
crates/nu-test-support/src/fs.rs
Normal file
277
crates/nu-test-support/src/fs.rs
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
use std::io::Read;
|
||||||
|
use std::ops::Div;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
pub struct AbsoluteFile {
|
||||||
|
inner: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AbsoluteFile {
|
||||||
|
pub fn new(path: impl AsRef<Path>) -> AbsoluteFile {
|
||||||
|
let path = path.as_ref();
|
||||||
|
|
||||||
|
if !path.is_absolute() {
|
||||||
|
panic!(
|
||||||
|
"AbsoluteFile::new must take an absolute path :: {}",
|
||||||
|
path.display()
|
||||||
|
)
|
||||||
|
} else if path.is_dir() {
|
||||||
|
// At the moment, this is not an invariant, but rather a way to catch bugs
|
||||||
|
// in tests.
|
||||||
|
panic!(
|
||||||
|
"AbsoluteFile::new must not take a directory :: {}",
|
||||||
|
path.display()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
AbsoluteFile {
|
||||||
|
inner: path.to_path_buf(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dir(&self) -> AbsolutePath {
|
||||||
|
AbsolutePath::new(if let Some(parent) = self.inner.parent() {
|
||||||
|
parent
|
||||||
|
} else {
|
||||||
|
unreachable!("Internal error: could not get parent in dir")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<AbsoluteFile> for PathBuf {
|
||||||
|
fn from(file: AbsoluteFile) -> Self {
|
||||||
|
file.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AbsolutePath {
|
||||||
|
pub inner: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AbsolutePath {
|
||||||
|
pub fn new(path: impl AsRef<Path>) -> AbsolutePath {
|
||||||
|
let path = path.as_ref();
|
||||||
|
|
||||||
|
if path.is_absolute() {
|
||||||
|
AbsolutePath {
|
||||||
|
inner: path.to_path_buf(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("AbsolutePath::new must take an absolute path")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div<&str> for &AbsolutePath {
|
||||||
|
type Output = AbsolutePath;
|
||||||
|
|
||||||
|
fn div(self, rhs: &str) -> Self::Output {
|
||||||
|
let parts = rhs.split('/');
|
||||||
|
let mut result = self.inner.clone();
|
||||||
|
|
||||||
|
for part in parts {
|
||||||
|
result = result.join(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
AbsolutePath::new(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<Path> for AbsolutePath {
|
||||||
|
fn as_ref(&self) -> &Path {
|
||||||
|
self.inner.as_path()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RelativePath {
|
||||||
|
inner: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RelativePath {
|
||||||
|
pub fn new(path: impl Into<PathBuf>) -> RelativePath {
|
||||||
|
let path = path.into();
|
||||||
|
|
||||||
|
if path.is_relative() {
|
||||||
|
RelativePath { inner: path }
|
||||||
|
} else {
|
||||||
|
panic!("RelativePath::new must take a relative path")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: AsRef<str>> Div<T> for &RelativePath {
|
||||||
|
type Output = RelativePath;
|
||||||
|
|
||||||
|
fn div(self, rhs: T) -> Self::Output {
|
||||||
|
let parts = rhs.as_ref().split('/');
|
||||||
|
let mut result = self.inner.clone();
|
||||||
|
|
||||||
|
for part in parts {
|
||||||
|
result = result.join(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
RelativePath::new(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub trait DisplayPath {
|
||||||
|
fn display_path(&self) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayPath for AbsolutePath {
|
||||||
|
fn display_path(&self) -> String {
|
||||||
|
self.inner.display().to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayPath for PathBuf {
|
||||||
|
fn display_path(&self) -> String {
|
||||||
|
self.display().to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayPath for str {
|
||||||
|
fn display_path(&self) -> String {
|
||||||
|
self.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayPath for &str {
|
||||||
|
fn display_path(&self) -> String {
|
||||||
|
(*self).to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayPath for String {
|
||||||
|
fn display_path(&self) -> String {
|
||||||
|
self.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayPath for &String {
|
||||||
|
fn display_path(&self) -> String {
|
||||||
|
(*self).to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub enum Stub<'a> {
|
||||||
|
FileWithContent(&'a str, &'a str),
|
||||||
|
FileWithContentToBeTrimmed(&'a str, &'a str),
|
||||||
|
EmptyFile(&'a str),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn file_contents(full_path: impl AsRef<Path>) -> String {
|
||||||
|
let mut file = std::fs::File::open(full_path.as_ref()).expect("can not open file");
|
||||||
|
let mut contents = String::new();
|
||||||
|
file.read_to_string(&mut contents)
|
||||||
|
.expect("can not read file");
|
||||||
|
contents
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn file_contents_binary(full_path: impl AsRef<Path>) -> Vec<u8> {
|
||||||
|
let mut file = std::fs::File::open(full_path.as_ref()).expect("can not open file");
|
||||||
|
let mut contents = Vec::new();
|
||||||
|
file.read_to_end(&mut contents).expect("can not read file");
|
||||||
|
contents
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn line_ending() -> String {
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
String::from("\r\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
{
|
||||||
|
String::from("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete_file_at(full_path: impl AsRef<Path>) {
|
||||||
|
let full_path = full_path.as_ref();
|
||||||
|
|
||||||
|
if full_path.exists() {
|
||||||
|
std::fs::remove_file(full_path).expect("can not delete file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_file_at(full_path: impl AsRef<Path>) -> Result<(), std::io::Error> {
|
||||||
|
let full_path = full_path.as_ref();
|
||||||
|
|
||||||
|
if full_path.parent().is_some() {
|
||||||
|
panic!("path exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fs::write(full_path, b"fake data")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn copy_file_to(source: &str, destination: &str) {
|
||||||
|
std::fs::copy(source, destination).expect("can not copy file");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn files_exist_at(files: Vec<impl AsRef<Path>>, path: impl AsRef<Path>) -> bool {
|
||||||
|
files.iter().all(|f| {
|
||||||
|
let mut loc = PathBuf::from(path.as_ref());
|
||||||
|
loc.push(f);
|
||||||
|
loc.exists()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete_directory_at(full_path: &str) {
|
||||||
|
std::fs::remove_dir_all(PathBuf::from(full_path)).expect("can not remove directory");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn executable_path() -> PathBuf {
|
||||||
|
let mut path = binaries();
|
||||||
|
path.push("nu");
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn root() -> PathBuf {
|
||||||
|
let manifest_dir = if let Ok(manifest_dir) = std::env::var("CARGO_MANIFEST_DIR") {
|
||||||
|
PathBuf::from(manifest_dir)
|
||||||
|
} else {
|
||||||
|
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||||
|
};
|
||||||
|
|
||||||
|
let test_path = manifest_dir.join("Cargo.lock");
|
||||||
|
if test_path.exists() {
|
||||||
|
manifest_dir
|
||||||
|
} else {
|
||||||
|
manifest_dir
|
||||||
|
.parent()
|
||||||
|
.expect("Couldn't find the debug binaries directory")
|
||||||
|
.parent()
|
||||||
|
.expect("Couldn't find the debug binaries directory")
|
||||||
|
.to_path_buf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn binaries() -> PathBuf {
|
||||||
|
let mut build_type = "debug";
|
||||||
|
if !cfg!(debug_assertions) {
|
||||||
|
build_type = "release"
|
||||||
|
}
|
||||||
|
|
||||||
|
std::env::var("CARGO_TARGET_DIR")
|
||||||
|
.ok()
|
||||||
|
.map(|target_dir| PathBuf::from(target_dir).join(&build_type))
|
||||||
|
.unwrap_or_else(|| root().join(format!("target/{}", &build_type)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fixtures() -> PathBuf {
|
||||||
|
root().join("tests/fixtures")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn assets() -> PathBuf {
|
||||||
|
root().join("tests/assets")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn in_directory(str: impl AsRef<Path>) -> String {
|
||||||
|
let path = str.as_ref();
|
||||||
|
let path = if path.is_relative() {
|
||||||
|
root().join(path)
|
||||||
|
} else {
|
||||||
|
path.to_path_buf()
|
||||||
|
};
|
||||||
|
|
||||||
|
path.display().to_string()
|
||||||
|
}
|
70
crates/nu-test-support/src/lib.rs
Normal file
70
crates/nu-test-support/src/lib.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
pub mod commands;
|
||||||
|
pub mod fs;
|
||||||
|
pub mod macros;
|
||||||
|
pub mod playground;
|
||||||
|
|
||||||
|
pub struct Outcome {
|
||||||
|
pub out: String,
|
||||||
|
pub err: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub const NATIVE_PATH_ENV_VAR: &str = "Path";
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
pub const NATIVE_PATH_ENV_VAR: &str = "PATH";
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub const NATIVE_PATH_ENV_SEPARATOR: char = ';';
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
pub const NATIVE_PATH_ENV_SEPARATOR: char = ':';
|
||||||
|
|
||||||
|
impl Outcome {
|
||||||
|
pub fn new(out: String, err: String) -> Outcome {
|
||||||
|
Outcome { out, err }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pipeline(commands: &str) -> String {
|
||||||
|
commands
|
||||||
|
.lines()
|
||||||
|
.skip(1)
|
||||||
|
.map(|line| line.trim())
|
||||||
|
.collect::<Vec<&str>>()
|
||||||
|
.join(" ")
|
||||||
|
.trim_end()
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shell_os_paths() -> Vec<std::path::PathBuf> {
|
||||||
|
let mut original_paths = vec![];
|
||||||
|
|
||||||
|
if let Some(paths) = std::env::var_os(NATIVE_PATH_ENV_VAR) {
|
||||||
|
original_paths = std::env::split_paths(&paths).collect::<Vec<_>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
original_paths
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::pipeline;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn constructs_a_pipeline() {
|
||||||
|
let actual = pipeline(
|
||||||
|
r#"
|
||||||
|
open los_tres_amigos.txt
|
||||||
|
| from-csv
|
||||||
|
| get rusty_luck
|
||||||
|
| str to-int
|
||||||
|
| math sum
|
||||||
|
| echo "$it"
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
actual,
|
||||||
|
r#"open los_tres_amigos.txt | from-csv | get rusty_luck | str to-int | math sum | echo "$it""#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
170
crates/nu-test-support/src/macros.rs
Normal file
170
crates/nu-test-support/src/macros.rs
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
#[macro_export]
|
||||||
|
macro_rules! nu {
|
||||||
|
(cwd: $cwd:expr, $path:expr, $($part:expr),*) => {{
|
||||||
|
use $crate::fs::DisplayPath;
|
||||||
|
|
||||||
|
let path = format!($path, $(
|
||||||
|
$part.display_path()
|
||||||
|
),*);
|
||||||
|
|
||||||
|
nu!($cwd, &path)
|
||||||
|
}};
|
||||||
|
|
||||||
|
(cwd: $cwd:expr, $path:expr) => {{
|
||||||
|
nu!($cwd, $path)
|
||||||
|
}};
|
||||||
|
|
||||||
|
($cwd:expr, $path:expr) => {{
|
||||||
|
pub use itertools::Itertools;
|
||||||
|
pub use std::error::Error;
|
||||||
|
pub use std::io::prelude::*;
|
||||||
|
pub use std::process::{Command, Stdio};
|
||||||
|
pub use $crate::NATIVE_PATH_ENV_VAR;
|
||||||
|
|
||||||
|
// let commands = &*format!(
|
||||||
|
// "
|
||||||
|
// cd \"{}\"
|
||||||
|
// {}
|
||||||
|
// exit",
|
||||||
|
// $crate::fs::in_directory($cwd),
|
||||||
|
// $crate::fs::DisplayPath::display_path(&$path)
|
||||||
|
// );
|
||||||
|
|
||||||
|
let test_bins = $crate::fs::binaries();
|
||||||
|
|
||||||
|
let cwd = std::env::current_dir().expect("Could not get current working directory.");
|
||||||
|
let test_bins = nu_path::canonicalize_with(&test_bins, cwd).unwrap_or_else(|e| {
|
||||||
|
panic!(
|
||||||
|
"Couldn't canonicalize dummy binaries path {}: {:?}",
|
||||||
|
test_bins.display(),
|
||||||
|
e
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut paths = $crate::shell_os_paths();
|
||||||
|
paths.insert(0, test_bins);
|
||||||
|
|
||||||
|
let path = $path.lines().collect::<Vec<_>>().join("; ");
|
||||||
|
|
||||||
|
let paths_joined = match std::env::join_paths(paths) {
|
||||||
|
Ok(all) => all,
|
||||||
|
Err(_) => panic!("Couldn't join paths for PATH var."),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut process = match Command::new($crate::fs::executable_path())
|
||||||
|
.env(NATIVE_PATH_ENV_VAR, paths_joined)
|
||||||
|
// .arg("--skip-plugins")
|
||||||
|
// .arg("--no-history")
|
||||||
|
// .arg("--config-file")
|
||||||
|
// .arg($crate::fs::DisplayPath::display_path(&$crate::fs::fixtures().join("playground/config/default.toml")))
|
||||||
|
.arg(format!("-c 'cd {}; {}'", $crate::fs::in_directory($cwd), $crate::fs::DisplayPath::display_path(&path)))
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
// .stdin(Stdio::piped())
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
{
|
||||||
|
Ok(child) => child,
|
||||||
|
Err(why) => panic!("Can't run test {:?} {}", $crate::fs::executable_path(), why.to_string()),
|
||||||
|
};
|
||||||
|
|
||||||
|
// let stdin = process.stdin.as_mut().expect("couldn't open stdin");
|
||||||
|
// stdin
|
||||||
|
// .write_all(b"exit\n")
|
||||||
|
// .expect("couldn't write to stdin");
|
||||||
|
|
||||||
|
let output = process
|
||||||
|
.wait_with_output()
|
||||||
|
.expect("couldn't read from stdout/stderr");
|
||||||
|
|
||||||
|
let out = $crate::macros::read_std(&output.stdout);
|
||||||
|
let err = String::from_utf8_lossy(&output.stderr);
|
||||||
|
|
||||||
|
println!("=== stderr\n{}", err);
|
||||||
|
|
||||||
|
$crate::Outcome::new(out,err.into_owned())
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! nu_with_plugins {
|
||||||
|
(cwd: $cwd:expr, $path:expr, $($part:expr),*) => {{
|
||||||
|
use $crate::fs::DisplayPath;
|
||||||
|
|
||||||
|
let path = format!($path, $(
|
||||||
|
$part.display_path()
|
||||||
|
),*);
|
||||||
|
|
||||||
|
nu_with_plugins!($cwd, &path)
|
||||||
|
}};
|
||||||
|
|
||||||
|
(cwd: $cwd:expr, $path:expr) => {{
|
||||||
|
nu_with_plugins!($cwd, $path)
|
||||||
|
}};
|
||||||
|
|
||||||
|
($cwd:expr, $path:expr) => {{
|
||||||
|
pub use std::error::Error;
|
||||||
|
pub use std::io::prelude::*;
|
||||||
|
pub use std::process::{Command, Stdio};
|
||||||
|
pub use crate::NATIVE_PATH_ENV_VAR;
|
||||||
|
|
||||||
|
let commands = &*format!(
|
||||||
|
"
|
||||||
|
cd \"{}\"
|
||||||
|
{}
|
||||||
|
exit",
|
||||||
|
$crate::fs::in_directory($cwd),
|
||||||
|
$crate::fs::DisplayPath::display_path(&$path)
|
||||||
|
);
|
||||||
|
|
||||||
|
let test_bins = $crate::fs::binaries();
|
||||||
|
let test_bins = nu_path::canonicalize(&test_bins).unwrap_or_else(|e| {
|
||||||
|
panic!(
|
||||||
|
"Couldn't canonicalize dummy binaries path {}: {:?}",
|
||||||
|
test_bins.display(),
|
||||||
|
e
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut paths = $crate::shell_os_paths();
|
||||||
|
paths.insert(0, test_bins);
|
||||||
|
|
||||||
|
let paths_joined = match std::env::join_paths(paths) {
|
||||||
|
Ok(all) => all,
|
||||||
|
Err(_) => panic!("Couldn't join paths for PATH var."),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut process = match Command::new($crate::fs::executable_path())
|
||||||
|
.env(NATIVE_PATH_ENV_VAR, paths_joined)
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
{
|
||||||
|
Ok(child) => child,
|
||||||
|
Err(why) => panic!("Can't run test {}", why.to_string()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let stdin = process.stdin.as_mut().expect("couldn't open stdin");
|
||||||
|
stdin
|
||||||
|
.write_all(commands.as_bytes())
|
||||||
|
.expect("couldn't write to stdin");
|
||||||
|
|
||||||
|
let output = process
|
||||||
|
.wait_with_output()
|
||||||
|
.expect("couldn't read from stdout/stderr");
|
||||||
|
|
||||||
|
let out = $crate::macros::read_std(&output.stdout);
|
||||||
|
let err = String::from_utf8_lossy(&output.stderr);
|
||||||
|
|
||||||
|
println!("=== stderr\n{}", err);
|
||||||
|
|
||||||
|
$crate::Outcome::new(out,err.into_owned())
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_std(std: &[u8]) -> String {
|
||||||
|
let out = String::from_utf8_lossy(std);
|
||||||
|
let out = out.lines().collect::<Vec<_>>().join("\n");
|
||||||
|
let out = out.replace("\r\n", "");
|
||||||
|
out.replace("\n", "")
|
||||||
|
}
|
12
crates/nu-test-support/src/playground.rs
Normal file
12
crates/nu-test-support/src/playground.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
mod director;
|
||||||
|
pub mod matchers;
|
||||||
|
pub mod nu_process;
|
||||||
|
mod play;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
|
pub use director::Director;
|
||||||
|
pub use matchers::says;
|
||||||
|
pub use nu_process::{Executable, NuProcess, NuResult, Outcome};
|
||||||
|
pub use play::{Dirs, EnvironmentVariable, Playground};
|
163
crates/nu-test-support/src/playground/director.rs
Normal file
163
crates/nu-test-support/src/playground/director.rs
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
use super::nu_process::*;
|
||||||
|
use super::EnvironmentVariable;
|
||||||
|
use std::ffi::OsString;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub struct Director {
|
||||||
|
pub cwd: Option<OsString>,
|
||||||
|
pub environment_vars: Vec<EnvironmentVariable>,
|
||||||
|
pub config: Option<OsString>,
|
||||||
|
pub pipeline: Option<Vec<String>>,
|
||||||
|
pub executable: Option<NuProcess>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Director {
|
||||||
|
pub fn cococo(&self, arg: &str) -> Self {
|
||||||
|
let mut process = NuProcess {
|
||||||
|
environment_vars: self.environment_vars.clone(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
process.args(&["--testbin", "cococo", arg]);
|
||||||
|
Director {
|
||||||
|
config: self.config.clone(),
|
||||||
|
executable: Some(process),
|
||||||
|
environment_vars: self.environment_vars.clone(),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn and_then(&mut self, commands: &str) -> &mut Self {
|
||||||
|
let commands = commands.to_string();
|
||||||
|
|
||||||
|
if let Some(ref mut pipeline) = self.pipeline {
|
||||||
|
pipeline.push(commands);
|
||||||
|
} else {
|
||||||
|
self.pipeline = Some(vec![commands]);
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pipeline(&self, commands: &str) -> Self {
|
||||||
|
let mut director = Director {
|
||||||
|
pipeline: if commands.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(vec![commands.to_string()])
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut process = NuProcess {
|
||||||
|
environment_vars: self.environment_vars.clone(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(working_directory) = &self.cwd {
|
||||||
|
process.cwd(working_directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
process.arg("--skip-plugins");
|
||||||
|
process.arg("--no-history");
|
||||||
|
if let Some(config_file) = self.config.as_ref() {
|
||||||
|
process.args(&[
|
||||||
|
"--config-file",
|
||||||
|
config_file.to_str().expect("failed to convert."),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
process.arg("--perf");
|
||||||
|
|
||||||
|
director.executable = Some(process);
|
||||||
|
director
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn executable(&self) -> Option<&NuProcess> {
|
||||||
|
if let Some(binary) = &self.executable {
|
||||||
|
Some(binary)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Executable for Director {
|
||||||
|
fn execute(&mut self) -> NuResult {
|
||||||
|
use std::io::Write;
|
||||||
|
use std::process::Stdio;
|
||||||
|
|
||||||
|
match self.executable() {
|
||||||
|
Some(binary) => {
|
||||||
|
let mut process = match binary
|
||||||
|
.construct()
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
{
|
||||||
|
Ok(child) => child,
|
||||||
|
Err(why) => panic!("Can't run test {}", why),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(pipelines) = &self.pipeline {
|
||||||
|
let child = process.stdin.as_mut().expect("Failed to open stdin");
|
||||||
|
|
||||||
|
for pipeline in pipelines {
|
||||||
|
child
|
||||||
|
.write_all(format!("{}\n", pipeline).as_bytes())
|
||||||
|
.expect("Could not write to");
|
||||||
|
}
|
||||||
|
|
||||||
|
child.write_all(b"exit\n").expect("Could not write to");
|
||||||
|
}
|
||||||
|
|
||||||
|
process
|
||||||
|
.wait_with_output()
|
||||||
|
.map_err(|_| {
|
||||||
|
let reason = format!(
|
||||||
|
"could not execute process {} ({})",
|
||||||
|
binary, "No execution took place"
|
||||||
|
);
|
||||||
|
|
||||||
|
NuError {
|
||||||
|
desc: reason,
|
||||||
|
exit: None,
|
||||||
|
output: None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.and_then(|process| {
|
||||||
|
let out =
|
||||||
|
Outcome::new(&read_std(&process.stdout), &read_std(&process.stderr));
|
||||||
|
|
||||||
|
match process.status.success() {
|
||||||
|
true => Ok(out),
|
||||||
|
false => Err(NuError {
|
||||||
|
desc: String::new(),
|
||||||
|
exit: Some(process.status),
|
||||||
|
output: Some(out),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
None => Err(NuError {
|
||||||
|
desc: String::from("err"),
|
||||||
|
exit: None,
|
||||||
|
output: None,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Director {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "director")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_std(std: &[u8]) -> Vec<u8> {
|
||||||
|
let out = String::from_utf8_lossy(std);
|
||||||
|
let out = out.lines().collect::<Vec<_>>().join("\n");
|
||||||
|
let out = out.replace("\r\n", "");
|
||||||
|
out.replace("\n", "").into_bytes()
|
||||||
|
}
|
105
crates/nu-test-support/src/playground/matchers.rs
Normal file
105
crates/nu-test-support/src/playground/matchers.rs
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
use hamcrest2::core::{MatchResult, Matcher};
|
||||||
|
use std::fmt;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
use super::nu_process::Outcome;
|
||||||
|
use super::{Director, Executable};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Play {
|
||||||
|
stdout_expectation: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Play {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "play")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Play {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "play")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn says() -> Play {
|
||||||
|
Play {
|
||||||
|
stdout_expectation: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait CheckerMatchers {
|
||||||
|
fn output(&self, actual: &Outcome) -> MatchResult;
|
||||||
|
fn std(&self, actual: &[u8], expected: Option<&String>, description: &str) -> MatchResult;
|
||||||
|
fn stdout(&self, actual: &Outcome) -> MatchResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CheckerMatchers for Play {
|
||||||
|
fn output(&self, actual: &Outcome) -> MatchResult {
|
||||||
|
self.stdout(actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stdout(&self, actual: &Outcome) -> MatchResult {
|
||||||
|
self.std(&actual.out, self.stdout_expectation.as_ref(), "stdout")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn std(&self, actual: &[u8], expected: Option<&String>, description: &str) -> MatchResult {
|
||||||
|
let out = match expected {
|
||||||
|
Some(out) => out,
|
||||||
|
None => return Ok(()),
|
||||||
|
};
|
||||||
|
let actual = match str::from_utf8(actual) {
|
||||||
|
Err(..) => return Err(format!("{} was not utf8 encoded", description)),
|
||||||
|
Ok(actual) => actual,
|
||||||
|
};
|
||||||
|
|
||||||
|
if actual != *out {
|
||||||
|
return Err(format!(
|
||||||
|
"not equal:\n actual: {}\n expected: {}\n\n",
|
||||||
|
actual, out
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Matcher<Outcome> for Play {
|
||||||
|
fn matches(&self, output: Outcome) -> MatchResult {
|
||||||
|
self.output(&output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Matcher<Director> for Play {
|
||||||
|
fn matches(&self, mut director: Director) -> MatchResult {
|
||||||
|
self.matches(&mut director)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Matcher<&'a mut Director> for Play {
|
||||||
|
fn matches(&self, director: &'a mut Director) -> MatchResult {
|
||||||
|
if director.executable().is_none() {
|
||||||
|
return Err(format!("no such process {}", director));
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = director.execute();
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(out) => self.output(&out),
|
||||||
|
Err(err) => {
|
||||||
|
if let Some(out) = &err.output {
|
||||||
|
return self.output(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(format!("could not exec process {}: {:?}", director, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Play {
|
||||||
|
pub fn stdout(mut self, expected: &str) -> Self {
|
||||||
|
self.stdout_expectation = Some(expected.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
104
crates/nu-test-support/src/playground/nu_process.rs
Normal file
104
crates/nu-test-support/src/playground/nu_process.rs
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
use super::EnvironmentVariable;
|
||||||
|
use crate::fs::{binaries as test_bins_path, executable_path};
|
||||||
|
use std::ffi::{OsStr, OsString};
|
||||||
|
use std::fmt;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::process::{Command, ExitStatus};
|
||||||
|
|
||||||
|
pub trait Executable {
|
||||||
|
fn execute(&mut self) -> NuResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Outcome {
|
||||||
|
pub out: Vec<u8>,
|
||||||
|
pub err: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Outcome {
|
||||||
|
pub fn new(out: &[u8], err: &[u8]) -> Outcome {
|
||||||
|
Outcome {
|
||||||
|
out: out.to_vec(),
|
||||||
|
err: err.to_vec(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type NuResult = Result<Outcome, NuError>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct NuError {
|
||||||
|
pub desc: String,
|
||||||
|
pub exit: Option<ExitStatus>,
|
||||||
|
pub output: Option<Outcome>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct NuProcess {
|
||||||
|
pub arguments: Vec<OsString>,
|
||||||
|
pub environment_vars: Vec<EnvironmentVariable>,
|
||||||
|
pub cwd: Option<OsString>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for NuProcess {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "`nu")?;
|
||||||
|
|
||||||
|
for arg in &self.arguments {
|
||||||
|
write!(f, " {}", arg.to_string_lossy())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, "`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NuProcess {
|
||||||
|
pub fn arg<T: AsRef<OsStr>>(&mut self, arg: T) -> &mut Self {
|
||||||
|
self.arguments.push(arg.as_ref().to_os_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn args<T: AsRef<OsStr>>(&mut self, arguments: &[T]) -> &mut NuProcess {
|
||||||
|
self.arguments
|
||||||
|
.extend(arguments.iter().map(|t| t.as_ref().to_os_string()));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cwd<T: AsRef<OsStr>>(&mut self, path: T) -> &mut NuProcess {
|
||||||
|
self.cwd = Some(path.as_ref().to_os_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_cwd(&self) -> Option<&Path> {
|
||||||
|
self.cwd.as_ref().map(Path::new)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn construct(&self) -> Command {
|
||||||
|
let mut command = Command::new(&executable_path());
|
||||||
|
|
||||||
|
if let Some(cwd) = self.get_cwd() {
|
||||||
|
command.current_dir(cwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
command.env_clear();
|
||||||
|
|
||||||
|
let paths = vec![test_bins_path()];
|
||||||
|
|
||||||
|
let paths_joined = match std::env::join_paths(&paths) {
|
||||||
|
Ok(all) => all,
|
||||||
|
Err(_) => panic!("Couldn't join paths for PATH var."),
|
||||||
|
};
|
||||||
|
|
||||||
|
command.env(crate::NATIVE_PATH_ENV_VAR, paths_joined);
|
||||||
|
|
||||||
|
for env_var in &self.environment_vars {
|
||||||
|
command.env(&env_var.name, &env_var.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
for arg in &self.arguments {
|
||||||
|
command.arg(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
command
|
||||||
|
}
|
||||||
|
}
|
248
crates/nu-test-support/src/playground/play.rs
Normal file
248
crates/nu-test-support/src/playground/play.rs
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
use super::Director;
|
||||||
|
use crate::fs;
|
||||||
|
use crate::fs::Stub;
|
||||||
|
use getset::Getters;
|
||||||
|
use glob::glob;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::str;
|
||||||
|
use tempfile::{tempdir, TempDir};
|
||||||
|
|
||||||
|
#[derive(Default, Clone, Debug)]
|
||||||
|
pub struct EnvironmentVariable {
|
||||||
|
pub name: String,
|
||||||
|
pub value: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EnvironmentVariable {
|
||||||
|
fn new(name: &str, value: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
value: value.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Playground<'a> {
|
||||||
|
root: TempDir,
|
||||||
|
tests: String,
|
||||||
|
cwd: PathBuf,
|
||||||
|
config: PathBuf,
|
||||||
|
environment_vars: Vec<EnvironmentVariable>,
|
||||||
|
dirs: &'a Dirs,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Getters, Clone)]
|
||||||
|
#[get = "pub"]
|
||||||
|
pub struct Dirs {
|
||||||
|
pub root: PathBuf,
|
||||||
|
pub test: PathBuf,
|
||||||
|
pub fixtures: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dirs {
|
||||||
|
pub fn formats(&self) -> PathBuf {
|
||||||
|
self.fixtures.join("formats")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn config_fixtures(&self) -> PathBuf {
|
||||||
|
self.fixtures.join("playground/config")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Playground<'a> {
|
||||||
|
pub fn root(&self) -> &Path {
|
||||||
|
self.root.path()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cwd(&self) -> &Path {
|
||||||
|
&self.cwd
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn back_to_playground(&mut self) -> &mut Self {
|
||||||
|
self.cwd = PathBuf::from(self.root()).join(self.tests.clone());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn play(&mut self) -> &mut Self {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup(topic: &str, block: impl FnOnce(Dirs, &mut Playground)) {
|
||||||
|
let root = tempdir().expect("Couldn't create a tempdir");
|
||||||
|
let nuplay_dir = root.path().join(topic);
|
||||||
|
|
||||||
|
if PathBuf::from(&nuplay_dir).exists() {
|
||||||
|
std::fs::remove_dir_all(PathBuf::from(&nuplay_dir)).expect("can not remove directory");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fs::create_dir(PathBuf::from(&nuplay_dir)).expect("can not create directory");
|
||||||
|
|
||||||
|
let fixtures = fs::fixtures();
|
||||||
|
let cwd = std::env::current_dir().expect("Could not get current working directory.");
|
||||||
|
let fixtures = nu_path::canonicalize_with(fixtures.clone(), cwd).unwrap_or_else(|e| {
|
||||||
|
panic!(
|
||||||
|
"Couldn't canonicalize fixtures path {}: {:?}",
|
||||||
|
fixtures.display(),
|
||||||
|
e
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut playground = Playground {
|
||||||
|
root,
|
||||||
|
tests: topic.to_string(),
|
||||||
|
cwd: nuplay_dir,
|
||||||
|
config: fixtures.join("playground/config/default.toml"),
|
||||||
|
environment_vars: Vec::default(),
|
||||||
|
dirs: &Dirs::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let playground_root = playground.root.path();
|
||||||
|
|
||||||
|
let cwd = std::env::current_dir().expect("Could not get current working directory.");
|
||||||
|
let test =
|
||||||
|
nu_path::canonicalize_with(playground_root.join(topic), cwd).unwrap_or_else(|e| {
|
||||||
|
panic!(
|
||||||
|
"Couldn't canonicalize test path {}: {:?}",
|
||||||
|
playground_root.join(topic).display(),
|
||||||
|
e
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let cwd = std::env::current_dir().expect("Could not get current working directory.");
|
||||||
|
let root = nu_path::canonicalize_with(playground_root, cwd).unwrap_or_else(|e| {
|
||||||
|
panic!(
|
||||||
|
"Couldn't canonicalize tests root path {}: {:?}",
|
||||||
|
playground_root.display(),
|
||||||
|
e
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let dirs = Dirs {
|
||||||
|
root,
|
||||||
|
test,
|
||||||
|
fixtures,
|
||||||
|
};
|
||||||
|
|
||||||
|
playground.dirs = &dirs;
|
||||||
|
|
||||||
|
block(dirs.clone(), &mut playground);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_config(&mut self, source_file: impl AsRef<Path>) -> &mut Self {
|
||||||
|
self.config = source_file.as_ref().to_path_buf();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_env(&mut self, name: &str, value: &str) -> &mut Self {
|
||||||
|
self.environment_vars
|
||||||
|
.push(EnvironmentVariable::new(name, value));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_config(&self) -> &str {
|
||||||
|
self.config.to_str().expect("could not convert path.")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(&mut self) -> Director {
|
||||||
|
Director {
|
||||||
|
cwd: Some(self.dirs.test().into()),
|
||||||
|
config: Some(self.config.clone().into()),
|
||||||
|
environment_vars: self.environment_vars.clone(),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cococo(&mut self, arg: &str) -> Director {
|
||||||
|
self.build().cococo(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pipeline(&mut self, commands: &str) -> Director {
|
||||||
|
self.build().pipeline(commands)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mkdir(&mut self, directory: &str) -> &mut Self {
|
||||||
|
self.cwd.push(directory);
|
||||||
|
std::fs::create_dir_all(&self.cwd).expect("can not create directory");
|
||||||
|
self.back_to_playground();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
pub fn symlink(&mut self, from: impl AsRef<Path>, to: impl AsRef<Path>) -> &mut Self {
|
||||||
|
let from = self.cwd.join(from);
|
||||||
|
let to = self.cwd.join(to);
|
||||||
|
|
||||||
|
let create_symlink = {
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
std::os::unix::fs::symlink
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
if from.is_file() {
|
||||||
|
std::os::windows::fs::symlink_file
|
||||||
|
} else if from.is_dir() {
|
||||||
|
std::os::windows::fs::symlink_dir
|
||||||
|
} else {
|
||||||
|
panic!("symlink from must be a file or dir")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
create_symlink(from, to).expect("can not create symlink");
|
||||||
|
self.back_to_playground();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_files(&mut self, files: Vec<Stub>) -> &mut Self {
|
||||||
|
let endl = fs::line_ending();
|
||||||
|
|
||||||
|
files
|
||||||
|
.iter()
|
||||||
|
.map(|f| {
|
||||||
|
let mut path = PathBuf::from(&self.cwd);
|
||||||
|
|
||||||
|
let (file_name, contents) = match *f {
|
||||||
|
Stub::EmptyFile(name) => (name, "fake data".to_string()),
|
||||||
|
Stub::FileWithContent(name, content) => (name, content.to_string()),
|
||||||
|
Stub::FileWithContentToBeTrimmed(name, content) => (
|
||||||
|
name,
|
||||||
|
content
|
||||||
|
.lines()
|
||||||
|
.skip(1)
|
||||||
|
.map(|line| line.trim())
|
||||||
|
.collect::<Vec<&str>>()
|
||||||
|
.join(&endl),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
path.push(file_name);
|
||||||
|
|
||||||
|
std::fs::write(path, contents.as_bytes()).expect("can not create file");
|
||||||
|
})
|
||||||
|
.for_each(drop);
|
||||||
|
self.back_to_playground();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn within(&mut self, directory: &str) -> &mut Self {
|
||||||
|
self.cwd.push(directory);
|
||||||
|
std::fs::create_dir(&self.cwd).expect("can not create directory");
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn glob_vec(pattern: &str) -> Vec<PathBuf> {
|
||||||
|
let glob = glob(pattern);
|
||||||
|
|
||||||
|
glob.expect("invalid pattern")
|
||||||
|
.map(|path| {
|
||||||
|
if let Ok(path) = path {
|
||||||
|
path
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
41
crates/nu-test-support/src/playground/tests.rs
Normal file
41
crates/nu-test-support/src/playground/tests.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
use crate::playground::Playground;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use super::matchers::says;
|
||||||
|
use hamcrest2::assert_that;
|
||||||
|
use hamcrest2::prelude::*;
|
||||||
|
|
||||||
|
fn path(p: &Path) -> PathBuf {
|
||||||
|
let cwd = std::env::current_dir().expect("Could not get current working directory.");
|
||||||
|
nu_path::canonicalize_with(p, cwd)
|
||||||
|
.unwrap_or_else(|e| panic!("Couldn't canonicalize path {}: {:?}", p.display(), e))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn asserts_standard_out_expectation_from_nu_executable() {
|
||||||
|
Playground::setup("topic", |_, nu| {
|
||||||
|
assert_that!(nu.cococo("andres"), says().stdout("andres"));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn current_working_directory_in_sandbox_directory_created() {
|
||||||
|
Playground::setup("topic", |dirs, nu| {
|
||||||
|
let original_cwd = dirs.test();
|
||||||
|
nu.within("some_directory_within");
|
||||||
|
|
||||||
|
assert_eq!(path(nu.cwd()), original_cwd.join("some_directory_within"));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn current_working_directory_back_to_root_from_anywhere() {
|
||||||
|
Playground::setup("topic", |dirs, nu| {
|
||||||
|
let original_cwd = dirs.test();
|
||||||
|
|
||||||
|
nu.within("some_directory_within");
|
||||||
|
nu.back_to_playground();
|
||||||
|
|
||||||
|
assert_eq!(path(nu.cwd()), *original_cwd);
|
||||||
|
})
|
||||||
|
}
|
@ -39,7 +39,7 @@ pub(crate) fn read_config_file(engine_state: &mut EngineState, stack: &mut Stack
|
|||||||
|
|
||||||
if config_path.exists() {
|
if config_path.exists() {
|
||||||
// FIXME: remove this message when we're ready
|
// FIXME: remove this message when we're ready
|
||||||
println!("Loading config from: {:?}", config_path);
|
//println!("Loading config from: {:?}", config_path);
|
||||||
let config_filename = config_path.to_string_lossy().to_owned();
|
let config_filename = config_path.to_string_lossy().to_owned();
|
||||||
|
|
||||||
if let Ok(contents) = std::fs::read_to_string(&config_path) {
|
if let Ok(contents) = std::fs::read_to_string(&config_path) {
|
||||||
|
48
src/main.rs
48
src/main.rs
@ -10,6 +10,8 @@ mod utils;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
|
mod test_bins;
|
||||||
|
|
||||||
use miette::Result;
|
use miette::Result;
|
||||||
use nu_command::{create_default_context, BufferedReader};
|
use nu_command::{create_default_context, BufferedReader};
|
||||||
use nu_engine::get_full_help;
|
use nu_engine::get_full_help;
|
||||||
@ -21,7 +23,7 @@ use nu_protocol::{
|
|||||||
Spanned, SyntaxShape, Value, CONFIG_VARIABLE_ID,
|
Spanned, SyntaxShape, Value, CONFIG_VARIABLE_ID,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
io::BufReader,
|
io::{BufReader, Write},
|
||||||
path::Path,
|
path::Path,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicBool, Ordering},
|
atomic::{AtomicBool, Ordering},
|
||||||
@ -92,6 +94,7 @@ fn main() -> Result<()> {
|
|||||||
// Cool, it's a flag
|
// Cool, it's a flag
|
||||||
if arg == "-c"
|
if arg == "-c"
|
||||||
|| arg == "--commands"
|
|| arg == "--commands"
|
||||||
|
|| arg == "--testbin"
|
||||||
|| arg == "--develop"
|
|| arg == "--develop"
|
||||||
|| arg == "--debug"
|
|| arg == "--debug"
|
||||||
|| arg == "--loglevel"
|
|| arg == "--loglevel"
|
||||||
@ -115,6 +118,21 @@ fn main() -> Result<()> {
|
|||||||
|
|
||||||
match nushell_config {
|
match nushell_config {
|
||||||
Ok(nushell_config) => {
|
Ok(nushell_config) => {
|
||||||
|
if let Some(testbin) = &nushell_config.testbin {
|
||||||
|
// Call out to the correct testbin
|
||||||
|
match testbin.item.as_str() {
|
||||||
|
"echo_env" => test_bins::echo_env(),
|
||||||
|
"cococo" => test_bins::cococo(),
|
||||||
|
"meow" => test_bins::meow(),
|
||||||
|
"iecho" => test_bins::iecho(),
|
||||||
|
"fail" => test_bins::fail(),
|
||||||
|
"nonu" => test_bins::nonu(),
|
||||||
|
"chop" => test_bins::chop(),
|
||||||
|
"repeater" => test_bins::repeater(),
|
||||||
|
_ => std::process::exit(1),
|
||||||
|
}
|
||||||
|
std::process::exit(0)
|
||||||
|
}
|
||||||
let input = if let Some(redirect_stdin) = &nushell_config.redirect_stdin {
|
let input = if let Some(redirect_stdin) = &nushell_config.redirect_stdin {
|
||||||
let stdin = std::io::stdin();
|
let stdin = std::io::stdin();
|
||||||
let buf_reader = BufReader::new(stdin);
|
let buf_reader = BufReader::new(stdin);
|
||||||
@ -193,6 +211,7 @@ fn parse_commandline_args(
|
|||||||
let login_shell = call.get_named_arg("login");
|
let login_shell = call.get_named_arg("login");
|
||||||
let interactive_shell = call.get_named_arg("interactive");
|
let interactive_shell = call.get_named_arg("interactive");
|
||||||
let commands: Option<Expression> = call.get_flag_expr("commands");
|
let commands: Option<Expression> = call.get_flag_expr("commands");
|
||||||
|
let testbin: Option<Expression> = call.get_flag_expr("testbin");
|
||||||
|
|
||||||
let commands = if let Some(expression) = commands {
|
let commands = if let Some(expression) = commands {
|
||||||
let contents = engine_state.get_span_contents(&expression.span);
|
let contents = engine_state.get_span_contents(&expression.span);
|
||||||
@ -205,12 +224,29 @@ fn parse_commandline_args(
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let testbin = if let Some(expression) = testbin {
|
||||||
|
let contents = engine_state.get_span_contents(&expression.span);
|
||||||
|
|
||||||
|
Some(Spanned {
|
||||||
|
item: String::from_utf8_lossy(contents).to_string(),
|
||||||
|
span: expression.span,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let help = call.has_flag("help");
|
let help = call.has_flag("help");
|
||||||
|
|
||||||
if help {
|
if help {
|
||||||
let full_help =
|
let full_help =
|
||||||
get_full_help(&Nu.signature(), &Nu.examples(), engine_state, &mut stack);
|
get_full_help(&Nu.signature(), &Nu.examples(), engine_state, &mut stack);
|
||||||
print!("{}", full_help);
|
|
||||||
|
let _ = std::panic::catch_unwind(move || {
|
||||||
|
let stdout = std::io::stdout();
|
||||||
|
let mut stdout = stdout.lock();
|
||||||
|
let _ = stdout.write_all(full_help.as_bytes());
|
||||||
|
});
|
||||||
|
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,6 +255,7 @@ fn parse_commandline_args(
|
|||||||
login_shell,
|
login_shell,
|
||||||
interactive_shell,
|
interactive_shell,
|
||||||
commands,
|
commands,
|
||||||
|
testbin,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -235,6 +272,7 @@ struct NushellConfig {
|
|||||||
login_shell: Option<Spanned<String>>,
|
login_shell: Option<Spanned<String>>,
|
||||||
interactive_shell: Option<Spanned<String>>,
|
interactive_shell: Option<Spanned<String>>,
|
||||||
commands: Option<Spanned<String>>,
|
commands: Option<Spanned<String>>,
|
||||||
|
testbin: Option<Spanned<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -251,6 +289,12 @@ impl Command for Nu {
|
|||||||
.switch("stdin", "redirect the stdin", None)
|
.switch("stdin", "redirect the stdin", None)
|
||||||
.switch("login", "start as a login shell", Some('l'))
|
.switch("login", "start as a login shell", Some('l'))
|
||||||
.switch("interactive", "start as an interactive shell", Some('i'))
|
.switch("interactive", "start as an interactive shell", Some('i'))
|
||||||
|
.named(
|
||||||
|
"testbin",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"run internal test binary",
|
||||||
|
None,
|
||||||
|
)
|
||||||
.named(
|
.named(
|
||||||
"commands",
|
"commands",
|
||||||
SyntaxShape::String,
|
SyntaxShape::String,
|
||||||
|
123
src/test_bins.rs
Normal file
123
src/test_bins.rs
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
use std::io::{self, BufRead, Write};
|
||||||
|
|
||||||
|
/// Echo's value of env keys from args
|
||||||
|
/// Example: nu --testbin env_echo FOO BAR
|
||||||
|
/// If it it's not present echo's nothing
|
||||||
|
pub fn echo_env() {
|
||||||
|
let args = args();
|
||||||
|
for arg in args {
|
||||||
|
if let Ok(v) = std::env::var(arg) {
|
||||||
|
println!("{}", v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cococo() {
|
||||||
|
let args: Vec<String> = args();
|
||||||
|
|
||||||
|
if args.len() > 1 {
|
||||||
|
// Write back out all the arguments passed
|
||||||
|
// if given at least 1 instead of chickens
|
||||||
|
// speaking co co co.
|
||||||
|
println!("{}", &args[1..].join(" "));
|
||||||
|
} else {
|
||||||
|
println!("cococo");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn meow() {
|
||||||
|
let args: Vec<String> = args();
|
||||||
|
|
||||||
|
for arg in args.iter().skip(1) {
|
||||||
|
let contents = std::fs::read_to_string(arg).expect("Expected a filepath");
|
||||||
|
println!("{}", contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nonu() {
|
||||||
|
args().iter().skip(1).for_each(|arg| print!("{}", arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn repeater() {
|
||||||
|
let mut stdout = io::stdout();
|
||||||
|
let args = args();
|
||||||
|
let mut args = args.iter().skip(1);
|
||||||
|
let letter = args.next().expect("needs a character to iterate");
|
||||||
|
let count = args.next().expect("need the number of times to iterate");
|
||||||
|
|
||||||
|
let count: u64 = count.parse().expect("can't convert count to number");
|
||||||
|
|
||||||
|
for _ in 0..count {
|
||||||
|
let _ = write!(stdout, "{}", letter);
|
||||||
|
}
|
||||||
|
let _ = stdout.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iecho() {
|
||||||
|
// println! panics if stdout gets closed, whereas writeln gives us an error
|
||||||
|
let mut stdout = io::stdout();
|
||||||
|
let _ = args()
|
||||||
|
.iter()
|
||||||
|
.skip(1)
|
||||||
|
.cycle()
|
||||||
|
.try_for_each(|v| writeln!(stdout, "{}", v));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fail() {
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn chop() {
|
||||||
|
if did_chop_arguments() {
|
||||||
|
// we are done and don't care about standard input.
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no arguments given, chop from standard input and exit.
|
||||||
|
let stdin = io::stdin();
|
||||||
|
let mut stdout = io::stdout();
|
||||||
|
|
||||||
|
for given in stdin.lock().lines().flatten() {
|
||||||
|
let chopped = if given.is_empty() {
|
||||||
|
&given
|
||||||
|
} else {
|
||||||
|
let to = given.len() - 1;
|
||||||
|
&given[..to]
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(_e) = writeln!(stdout, "{}", chopped) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn did_chop_arguments() -> bool {
|
||||||
|
let args: Vec<String> = args();
|
||||||
|
|
||||||
|
if args.len() > 1 {
|
||||||
|
let mut arguments = args.iter();
|
||||||
|
arguments.next();
|
||||||
|
|
||||||
|
for arg in arguments {
|
||||||
|
let chopped = if arg.is_empty() {
|
||||||
|
&arg
|
||||||
|
} else {
|
||||||
|
let to = arg.len() - 1;
|
||||||
|
&arg[..to]
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("{}", chopped);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn args() -> Vec<String> {
|
||||||
|
// skip (--testbin bin_name args)
|
||||||
|
std::env::args().skip(2).collect()
|
||||||
|
}
|
@ -26,7 +26,7 @@ pub fn run_test(input: &str, expected: &str) -> TestResult {
|
|||||||
let mut file = NamedTempFile::new()?;
|
let mut file = NamedTempFile::new()?;
|
||||||
let name = file.path();
|
let name = file.path();
|
||||||
|
|
||||||
let mut cmd = Command::cargo_bin("engine-q")?;
|
let mut cmd = Command::cargo_bin("nu")?;
|
||||||
cmd.arg(name);
|
cmd.arg(name);
|
||||||
|
|
||||||
writeln!(file, "{}", input)?;
|
writeln!(file, "{}", input)?;
|
||||||
@ -51,7 +51,7 @@ pub fn run_test_contains(input: &str, expected: &str) -> TestResult {
|
|||||||
let mut file = NamedTempFile::new()?;
|
let mut file = NamedTempFile::new()?;
|
||||||
let name = file.path();
|
let name = file.path();
|
||||||
|
|
||||||
let mut cmd = Command::cargo_bin("engine-q")?;
|
let mut cmd = Command::cargo_bin("nu")?;
|
||||||
cmd.arg(name);
|
cmd.arg(name);
|
||||||
|
|
||||||
writeln!(file, "{}", input)?;
|
writeln!(file, "{}", input)?;
|
||||||
@ -76,7 +76,7 @@ pub fn fail_test(input: &str, expected: &str) -> TestResult {
|
|||||||
let mut file = NamedTempFile::new()?;
|
let mut file = NamedTempFile::new()?;
|
||||||
let name = file.path();
|
let name = file.path();
|
||||||
|
|
||||||
let mut cmd = Command::cargo_bin("engine-q")?;
|
let mut cmd = Command::cargo_bin("nu")?;
|
||||||
cmd.arg(name);
|
cmd.arg(name);
|
||||||
cmd.env(
|
cmd.env(
|
||||||
"PWD",
|
"PWD",
|
||||||
|
5
tests/assets/nu_json/charset_result.hjson
Normal file
5
tests/assets/nu_json/charset_result.hjson
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
ql-ascii: ! "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
|
||||||
|
js-ascii: ! "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
|
||||||
|
ml-ascii: ! "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
|
||||||
|
}
|
5
tests/assets/nu_json/charset_result.json
Normal file
5
tests/assets/nu_json/charset_result.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"ql-ascii": "! \"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~",
|
||||||
|
"js-ascii": "! \"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~",
|
||||||
|
"ml-ascii": "! \"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
|
||||||
|
}
|
6
tests/assets/nu_json/charset_test.hjson
Normal file
6
tests/assets/nu_json/charset_test.hjson
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
ql-ascii: ! "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
|
||||||
|
js-ascii: "! \"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
|
||||||
|
ml-ascii:
|
||||||
|
'''
|
||||||
|
! "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
|
||||||
|
'''
|
26
tests/assets/nu_json/comments_result.hjson
Normal file
26
tests/assets/nu_json/comments_result.hjson
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
foo1: This is a string value. # part of the string
|
||||||
|
foo2: This is a string value.
|
||||||
|
bar1: This is a string value. // part of the string
|
||||||
|
bar2: This is a string value.
|
||||||
|
foobar1: This is a string value./* part of the string */
|
||||||
|
foobar2: This is a string value.
|
||||||
|
rem1: "# test"
|
||||||
|
rem2: "// test"
|
||||||
|
rem3: "/* test */"
|
||||||
|
num1: 0
|
||||||
|
num2: 0
|
||||||
|
num3: 2
|
||||||
|
true1: true
|
||||||
|
true2: true
|
||||||
|
true3: true
|
||||||
|
false1: false
|
||||||
|
false2: false
|
||||||
|
false3: false
|
||||||
|
null1: null
|
||||||
|
null2: null
|
||||||
|
null3: null
|
||||||
|
str1: 00 # part of the string
|
||||||
|
str2: 00.0 // part of the string
|
||||||
|
str3: 02 /* part of the string */
|
||||||
|
}
|
26
tests/assets/nu_json/comments_result.json
Normal file
26
tests/assets/nu_json/comments_result.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"foo1": "This is a string value. # part of the string",
|
||||||
|
"foo2": "This is a string value.",
|
||||||
|
"bar1": "This is a string value. // part of the string",
|
||||||
|
"bar2": "This is a string value.",
|
||||||
|
"foobar1": "This is a string value./* part of the string */",
|
||||||
|
"foobar2": "This is a string value.",
|
||||||
|
"rem1": "# test",
|
||||||
|
"rem2": "// test",
|
||||||
|
"rem3": "/* test */",
|
||||||
|
"num1": 0,
|
||||||
|
"num2": 0,
|
||||||
|
"num3": 2,
|
||||||
|
"true1": true,
|
||||||
|
"true2": true,
|
||||||
|
"true3": true,
|
||||||
|
"false1": false,
|
||||||
|
"false2": false,
|
||||||
|
"false3": false,
|
||||||
|
"null1": null,
|
||||||
|
"null2": null,
|
||||||
|
"null3": null,
|
||||||
|
"str1": "00 # part of the string",
|
||||||
|
"str2": "00.0 // part of the string",
|
||||||
|
"str3": "02 /* part of the string */"
|
||||||
|
}
|
48
tests/assets/nu_json/comments_test.hjson
Normal file
48
tests/assets/nu_json/comments_test.hjson
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// test
|
||||||
|
# all
|
||||||
|
// comment
|
||||||
|
/*
|
||||||
|
styles
|
||||||
|
*/
|
||||||
|
# with lf
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# !
|
||||||
|
|
||||||
|
{
|
||||||
|
# hjson style comment
|
||||||
|
foo1: This is a string value. # part of the string
|
||||||
|
foo2: "This is a string value." # a comment
|
||||||
|
|
||||||
|
// js style comment
|
||||||
|
bar1: This is a string value. // part of the string
|
||||||
|
bar2: "This is a string value." // a comment
|
||||||
|
|
||||||
|
/* js block style comments */foobar1:/* more */This is a string value./* part of the string */
|
||||||
|
/* js block style comments */foobar2:/* more */"This is a string value."/* a comment */
|
||||||
|
|
||||||
|
rem1: "# test"
|
||||||
|
rem2: "// test"
|
||||||
|
rem3: "/* test */"
|
||||||
|
|
||||||
|
num1: 0 # comment
|
||||||
|
num2: 0.0 // comment
|
||||||
|
num3: 2 /* comment */
|
||||||
|
|
||||||
|
true1: true # comment
|
||||||
|
true2: true // comment
|
||||||
|
true3: true /* comment */
|
||||||
|
|
||||||
|
false1: false # comment
|
||||||
|
false2: false // comment
|
||||||
|
false3: false /* comment */
|
||||||
|
|
||||||
|
null1: null # comment
|
||||||
|
null2: null // comment
|
||||||
|
null3: null /* comment */
|
||||||
|
|
||||||
|
str1: 00 # part of the string
|
||||||
|
str2: 00.0 // part of the string
|
||||||
|
str3: 02 /* part of the string */
|
||||||
|
}
|
3
tests/assets/nu_json/empty_result.hjson
Normal file
3
tests/assets/nu_json/empty_result.hjson
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"": empty
|
||||||
|
}
|
3
tests/assets/nu_json/empty_result.json
Normal file
3
tests/assets/nu_json/empty_result.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"": "empty"
|
||||||
|
}
|
3
tests/assets/nu_json/empty_test.hjson
Normal file
3
tests/assets/nu_json/empty_test.hjson
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"": empty
|
||||||
|
}
|
4
tests/assets/nu_json/failCharset1_test.hjson
Normal file
4
tests/assets/nu_json/failCharset1_test.hjson
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
# invalid \u char
|
||||||
|
char: "\uxxxx"
|
||||||
|
}
|
1
tests/assets/nu_json/failJSON02_test.json
Normal file
1
tests/assets/nu_json/failJSON02_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["Unclosed array"
|
1
tests/assets/nu_json/failJSON05_test.json
Normal file
1
tests/assets/nu_json/failJSON05_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["double extra comma",,]
|
1
tests/assets/nu_json/failJSON06_test.json
Normal file
1
tests/assets/nu_json/failJSON06_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[ , "<-- missing value"]
|
1
tests/assets/nu_json/failJSON07_test.json
Normal file
1
tests/assets/nu_json/failJSON07_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["Comma after the close"],
|
1
tests/assets/nu_json/failJSON08_test.json
Normal file
1
tests/assets/nu_json/failJSON08_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["Extra close"]]
|
1
tests/assets/nu_json/failJSON10_test.json
Normal file
1
tests/assets/nu_json/failJSON10_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"Extra value after close": true} "misplaced quoted value"
|
1
tests/assets/nu_json/failJSON11_test.json
Normal file
1
tests/assets/nu_json/failJSON11_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"Illegal expression": 1 + 2}
|
1
tests/assets/nu_json/failJSON12_test.json
Normal file
1
tests/assets/nu_json/failJSON12_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"Illegal invocation": alert()}
|
1
tests/assets/nu_json/failJSON13_test.json
Normal file
1
tests/assets/nu_json/failJSON13_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"Numbers cannot have leading zeroes": 013}
|
1
tests/assets/nu_json/failJSON14_test.json
Normal file
1
tests/assets/nu_json/failJSON14_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"Numbers cannot be hex": 0x14}
|
1
tests/assets/nu_json/failJSON15_test.json
Normal file
1
tests/assets/nu_json/failJSON15_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["Illegal backslash escape: \x15"]
|
1
tests/assets/nu_json/failJSON16_test.json
Normal file
1
tests/assets/nu_json/failJSON16_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[\naked]
|
1
tests/assets/nu_json/failJSON17_test.json
Normal file
1
tests/assets/nu_json/failJSON17_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["Illegal backslash escape: \017"]
|
1
tests/assets/nu_json/failJSON19_test.json
Normal file
1
tests/assets/nu_json/failJSON19_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"Missing colon" null}
|
1
tests/assets/nu_json/failJSON20_test.json
Normal file
1
tests/assets/nu_json/failJSON20_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"Double colon":: null}
|
1
tests/assets/nu_json/failJSON21_test.json
Normal file
1
tests/assets/nu_json/failJSON21_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"Comma instead of colon", null}
|
1
tests/assets/nu_json/failJSON22_test.json
Normal file
1
tests/assets/nu_json/failJSON22_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["Colon instead of comma": false]
|
1
tests/assets/nu_json/failJSON23_test.json
Normal file
1
tests/assets/nu_json/failJSON23_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["Bad value", truth]
|
1
tests/assets/nu_json/failJSON24_test.json
Normal file
1
tests/assets/nu_json/failJSON24_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
['single quote']
|
1
tests/assets/nu_json/failJSON26_test.json
Normal file
1
tests/assets/nu_json/failJSON26_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["tab\ character\ in\ string\ "]
|
2
tests/assets/nu_json/failJSON28_test.json
Normal file
2
tests/assets/nu_json/failJSON28_test.json
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
["line\
|
||||||
|
break"]
|
1
tests/assets/nu_json/failJSON29_test.json
Normal file
1
tests/assets/nu_json/failJSON29_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[0e]
|
1
tests/assets/nu_json/failJSON30_test.json
Normal file
1
tests/assets/nu_json/failJSON30_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[0e+]
|
1
tests/assets/nu_json/failJSON31_test.json
Normal file
1
tests/assets/nu_json/failJSON31_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[0e+-1]
|
1
tests/assets/nu_json/failJSON32_test.json
Normal file
1
tests/assets/nu_json/failJSON32_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"Comma instead if closing brace": true,
|
1
tests/assets/nu_json/failJSON33_test.json
Normal file
1
tests/assets/nu_json/failJSON33_test.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["mismatch"}
|
2
tests/assets/nu_json/failJSON34_test.json
Normal file
2
tests/assets/nu_json/failJSON34_test.json
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
A quoteless string is OK,
|
||||||
|
but two must be contained in an array.
|
4
tests/assets/nu_json/failKey1_test.hjson
Normal file
4
tests/assets/nu_json/failKey1_test.hjson
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
# invalid name
|
||||||
|
wrong name: 0
|
||||||
|
}
|
4
tests/assets/nu_json/failKey2_test.hjson
Normal file
4
tests/assets/nu_json/failKey2_test.hjson
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
# invalid name
|
||||||
|
{name: 0
|
||||||
|
}
|
4
tests/assets/nu_json/failKey3_test.hjson
Normal file
4
tests/assets/nu_json/failKey3_test.hjson
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
# invalid name
|
||||||
|
key,name: 0
|
||||||
|
}
|
4
tests/assets/nu_json/failKey4_test.hjson
Normal file
4
tests/assets/nu_json/failKey4_test.hjson
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
# invalid name
|
||||||
|
: 0
|
||||||
|
}
|
3
tests/assets/nu_json/failMLStr1_test.hjson
Normal file
3
tests/assets/nu_json/failMLStr1_test.hjson
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
# invalid multiline string
|
||||||
|
ml: '''
|
6
tests/assets/nu_json/failObj1_test.hjson
Normal file
6
tests/assets/nu_json/failObj1_test.hjson
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
# invalid obj
|
||||||
|
noDelimiter
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
6
tests/assets/nu_json/failObj2_test.hjson
Normal file
6
tests/assets/nu_json/failObj2_test.hjson
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
# invalid obj
|
||||||
|
noEnd
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
7
tests/assets/nu_json/failObj3_test.hjson
Normal file
7
tests/assets/nu_json/failObj3_test.hjson
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
# missing key
|
||||||
|
|
||||||
|
[
|
||||||
|
test
|
||||||
|
]
|
||||||
|
}
|
4
tests/assets/nu_json/failStr1a_test.hjson
Normal file
4
tests/assets/nu_json/failStr1a_test.hjson
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
# invalid quoteless string
|
||||||
|
ql: ]
|
||||||
|
}
|
4
tests/assets/nu_json/failStr1b_test.hjson
Normal file
4
tests/assets/nu_json/failStr1b_test.hjson
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
# invalid quoteless string
|
||||||
|
ql: ]x
|
||||||
|
}
|
5
tests/assets/nu_json/failStr1c_test.hjson
Normal file
5
tests/assets/nu_json/failStr1c_test.hjson
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[
|
||||||
|
foo
|
||||||
|
# invalid quoteless string
|
||||||
|
]
|
||||||
|
]
|
5
tests/assets/nu_json/failStr1d_test.hjson
Normal file
5
tests/assets/nu_json/failStr1d_test.hjson
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[
|
||||||
|
foo
|
||||||
|
# invalid quoteless string
|
||||||
|
]x
|
||||||
|
]
|
4
tests/assets/nu_json/failStr2a_test.hjson
Normal file
4
tests/assets/nu_json/failStr2a_test.hjson
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
# invalid quoteless string
|
||||||
|
ql: }
|
||||||
|
}
|
4
tests/assets/nu_json/failStr2b_test.hjson
Normal file
4
tests/assets/nu_json/failStr2b_test.hjson
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
# invalid quoteless string
|
||||||
|
ql: }x
|
||||||
|
}
|
5
tests/assets/nu_json/failStr2c_test.hjson
Normal file
5
tests/assets/nu_json/failStr2c_test.hjson
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[
|
||||||
|
foo
|
||||||
|
# invalid quoteless string
|
||||||
|
}
|
||||||
|
]
|
5
tests/assets/nu_json/failStr2d_test.hjson
Normal file
5
tests/assets/nu_json/failStr2d_test.hjson
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[
|
||||||
|
foo
|
||||||
|
# invalid quoteless string
|
||||||
|
}x
|
||||||
|
]
|
4
tests/assets/nu_json/failStr3a_test.hjson
Normal file
4
tests/assets/nu_json/failStr3a_test.hjson
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
# invalid quoteless string
|
||||||
|
ql: {
|
||||||
|
}
|
4
tests/assets/nu_json/failStr3b_test.hjson
Normal file
4
tests/assets/nu_json/failStr3b_test.hjson
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
# invalid quoteless string
|
||||||
|
ql: {x
|
||||||
|
}
|
5
tests/assets/nu_json/failStr3c_test.hjson
Normal file
5
tests/assets/nu_json/failStr3c_test.hjson
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[
|
||||||
|
foo
|
||||||
|
# invalid quoteless string
|
||||||
|
{
|
||||||
|
]
|
5
tests/assets/nu_json/failStr3d_test.hjson
Normal file
5
tests/assets/nu_json/failStr3d_test.hjson
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[
|
||||||
|
foo
|
||||||
|
# invalid quoteless string
|
||||||
|
{x
|
||||||
|
]
|
4
tests/assets/nu_json/failStr4a_test.hjson
Normal file
4
tests/assets/nu_json/failStr4a_test.hjson
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
# invalid quoteless string
|
||||||
|
ql: [
|
||||||
|
}
|
4
tests/assets/nu_json/failStr4b_test.hjson
Normal file
4
tests/assets/nu_json/failStr4b_test.hjson
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
# invalid quoteless string
|
||||||
|
ql: [x
|
||||||
|
}
|
5
tests/assets/nu_json/failStr4c_test.hjson
Normal file
5
tests/assets/nu_json/failStr4c_test.hjson
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[
|
||||||
|
foo
|
||||||
|
# invalid quoteless string
|
||||||
|
[
|
||||||
|
]
|
5
tests/assets/nu_json/failStr4d_test.hjson
Normal file
5
tests/assets/nu_json/failStr4d_test.hjson
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[
|
||||||
|
foo
|
||||||
|
# invalid quoteless string
|
||||||
|
[x
|
||||||
|
]
|
4
tests/assets/nu_json/failStr5a_test.hjson
Normal file
4
tests/assets/nu_json/failStr5a_test.hjson
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
# invalid quoteless string
|
||||||
|
ql: :
|
||||||
|
}
|
4
tests/assets/nu_json/failStr5b_test.hjson
Normal file
4
tests/assets/nu_json/failStr5b_test.hjson
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
# invalid quoteless string
|
||||||
|
ql: :x
|
||||||
|
}
|
5
tests/assets/nu_json/failStr5c_test.hjson
Normal file
5
tests/assets/nu_json/failStr5c_test.hjson
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[
|
||||||
|
foo
|
||||||
|
# invalid quoteless string
|
||||||
|
:
|
||||||
|
]
|
5
tests/assets/nu_json/failStr5d_test.hjson
Normal file
5
tests/assets/nu_json/failStr5d_test.hjson
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[
|
||||||
|
foo
|
||||||
|
# invalid quoteless string
|
||||||
|
:x
|
||||||
|
]
|
4
tests/assets/nu_json/failStr6a_test.hjson
Normal file
4
tests/assets/nu_json/failStr6a_test.hjson
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
# invalid quoteless string
|
||||||
|
ql: ,
|
||||||
|
}
|
4
tests/assets/nu_json/failStr6b_test.hjson
Normal file
4
tests/assets/nu_json/failStr6b_test.hjson
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
# invalid quoteless string
|
||||||
|
ql: ,x
|
||||||
|
}
|
6
tests/assets/nu_json/failStr6c_test.hjson
Normal file
6
tests/assets/nu_json/failStr6c_test.hjson
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[
|
||||||
|
# invalid quoteless string
|
||||||
|
# note that if there were a preceding value the comma would
|
||||||
|
# be allowed/ignored as a separator/trailing comma
|
||||||
|
,
|
||||||
|
]
|
6
tests/assets/nu_json/failStr6d_test.hjson
Normal file
6
tests/assets/nu_json/failStr6d_test.hjson
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[
|
||||||
|
# invalid quoteless string
|
||||||
|
# note that if there were a preceding value the comma would
|
||||||
|
# be allowed/ignored as a separator/trailing comma
|
||||||
|
,x
|
||||||
|
]
|
48
tests/assets/nu_json/kan_result.hjson
Normal file
48
tests/assets/nu_json/kan_result.hjson
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
numbers:
|
||||||
|
[
|
||||||
|
0
|
||||||
|
0
|
||||||
|
0
|
||||||
|
42
|
||||||
|
42.1
|
||||||
|
-5
|
||||||
|
-5.1
|
||||||
|
1701
|
||||||
|
-1701
|
||||||
|
12.345
|
||||||
|
-12.345
|
||||||
|
]
|
||||||
|
native:
|
||||||
|
[
|
||||||
|
true
|
||||||
|
true
|
||||||
|
false
|
||||||
|
false
|
||||||
|
null
|
||||||
|
null
|
||||||
|
]
|
||||||
|
strings:
|
||||||
|
[
|
||||||
|
x 0
|
||||||
|
.0
|
||||||
|
00
|
||||||
|
01
|
||||||
|
0 0 0
|
||||||
|
42 x
|
||||||
|
42.1 asdf
|
||||||
|
1.2.3
|
||||||
|
-5 0 -
|
||||||
|
-5.1 --
|
||||||
|
17.01e2 +
|
||||||
|
-17.01e2 :
|
||||||
|
12345e-3 @
|
||||||
|
-12345e-3 $
|
||||||
|
true true
|
||||||
|
x true
|
||||||
|
false false
|
||||||
|
x false
|
||||||
|
null null
|
||||||
|
x null
|
||||||
|
]
|
||||||
|
}
|
45
tests/assets/nu_json/kan_result.json
Normal file
45
tests/assets/nu_json/kan_result.json
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"numbers": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
42,
|
||||||
|
42.1,
|
||||||
|
-5,
|
||||||
|
-5.1,
|
||||||
|
1701,
|
||||||
|
-1701,
|
||||||
|
12.345,
|
||||||
|
-12.345
|
||||||
|
],
|
||||||
|
"native": [
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
],
|
||||||
|
"strings": [
|
||||||
|
"x 0",
|
||||||
|
".0",
|
||||||
|
"00",
|
||||||
|
"01",
|
||||||
|
"0 0 0",
|
||||||
|
"42 x",
|
||||||
|
"42.1 asdf",
|
||||||
|
"1.2.3",
|
||||||
|
"-5 0 -",
|
||||||
|
"-5.1 --",
|
||||||
|
"17.01e2 +",
|
||||||
|
"-17.01e2 :",
|
||||||
|
"12345e-3 @",
|
||||||
|
"-12345e-3 $",
|
||||||
|
"true true",
|
||||||
|
"x true",
|
||||||
|
"false false",
|
||||||
|
"x false",
|
||||||
|
"null null",
|
||||||
|
"x null"
|
||||||
|
]
|
||||||
|
}
|
49
tests/assets/nu_json/kan_test.hjson
Normal file
49
tests/assets/nu_json/kan_test.hjson
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
# the comma forces a whitespace check
|
||||||
|
numbers:
|
||||||
|
[
|
||||||
|
0
|
||||||
|
0 ,
|
||||||
|
-0
|
||||||
|
42 ,
|
||||||
|
42.1 ,
|
||||||
|
-5
|
||||||
|
-5.1
|
||||||
|
17.01e2
|
||||||
|
-17.01e2
|
||||||
|
12345e-3 ,
|
||||||
|
-12345e-3 ,
|
||||||
|
]
|
||||||
|
native:
|
||||||
|
[
|
||||||
|
true ,
|
||||||
|
true
|
||||||
|
false ,
|
||||||
|
false
|
||||||
|
null ,
|
||||||
|
null
|
||||||
|
]
|
||||||
|
strings:
|
||||||
|
[
|
||||||
|
x 0
|
||||||
|
.0
|
||||||
|
00
|
||||||
|
01
|
||||||
|
0 0 0
|
||||||
|
42 x
|
||||||
|
42.1 asdf
|
||||||
|
1.2.3
|
||||||
|
-5 0 -
|
||||||
|
-5.1 --
|
||||||
|
17.01e2 +
|
||||||
|
-17.01e2 :
|
||||||
|
12345e-3 @
|
||||||
|
-12345e-3 $
|
||||||
|
true true
|
||||||
|
x true
|
||||||
|
false false
|
||||||
|
x false
|
||||||
|
null null
|
||||||
|
x null
|
||||||
|
]
|
||||||
|
}
|
34
tests/assets/nu_json/keys_result.hjson
Normal file
34
tests/assets/nu_json/keys_result.hjson
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
unquoted_key: test
|
||||||
|
_unquoted: test
|
||||||
|
test-key: test
|
||||||
|
-test: test
|
||||||
|
.key: test
|
||||||
|
trailing: test
|
||||||
|
trailing2: test
|
||||||
|
"#c1": test
|
||||||
|
"foo#bar": test
|
||||||
|
"//bar": test
|
||||||
|
"foo//bar": test
|
||||||
|
"/*foo*/": test
|
||||||
|
"foo/*foo*/bar": test
|
||||||
|
"/*": test
|
||||||
|
"foo/*bar": test
|
||||||
|
"\"": test
|
||||||
|
"foo\"bar": test
|
||||||
|
"'''": test
|
||||||
|
"foo'''bar": test
|
||||||
|
":": test
|
||||||
|
"foo:bar": test
|
||||||
|
"{": test
|
||||||
|
"foo{bar": test
|
||||||
|
"}": test
|
||||||
|
"foo}bar": test
|
||||||
|
"[": test
|
||||||
|
"foo[bar": test
|
||||||
|
"]": test
|
||||||
|
"foo]bar": test
|
||||||
|
nl1: test
|
||||||
|
nl2: test
|
||||||
|
nl3: test
|
||||||
|
}
|
34
tests/assets/nu_json/keys_result.json
Normal file
34
tests/assets/nu_json/keys_result.json
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"unquoted_key": "test",
|
||||||
|
"_unquoted": "test",
|
||||||
|
"test-key": "test",
|
||||||
|
"-test": "test",
|
||||||
|
".key": "test",
|
||||||
|
"trailing": "test",
|
||||||
|
"trailing2": "test",
|
||||||
|
"#c1": "test",
|
||||||
|
"foo#bar": "test",
|
||||||
|
"//bar": "test",
|
||||||
|
"foo//bar": "test",
|
||||||
|
"/*foo*/": "test",
|
||||||
|
"foo/*foo*/bar": "test",
|
||||||
|
"/*": "test",
|
||||||
|
"foo/*bar": "test",
|
||||||
|
"\"": "test",
|
||||||
|
"foo\"bar": "test",
|
||||||
|
"'''": "test",
|
||||||
|
"foo'''bar": "test",
|
||||||
|
":": "test",
|
||||||
|
"foo:bar": "test",
|
||||||
|
"{": "test",
|
||||||
|
"foo{bar": "test",
|
||||||
|
"}": "test",
|
||||||
|
"foo}bar": "test",
|
||||||
|
"[": "test",
|
||||||
|
"foo[bar": "test",
|
||||||
|
"]": "test",
|
||||||
|
"foo]bar": "test",
|
||||||
|
"nl1": "test",
|
||||||
|
"nl2": "test",
|
||||||
|
"nl3": "test"
|
||||||
|
}
|
48
tests/assets/nu_json/keys_test.hjson
Normal file
48
tests/assets/nu_json/keys_test.hjson
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
# unquoted keys
|
||||||
|
unquoted_key: test
|
||||||
|
_unquoted: test
|
||||||
|
test-key: test
|
||||||
|
-test: test
|
||||||
|
.key: test
|
||||||
|
# trailing spaces in key names are ignored
|
||||||
|
trailing : test
|
||||||
|
trailing2 : test
|
||||||
|
# comment char in key name
|
||||||
|
"#c1": test
|
||||||
|
"foo#bar": test
|
||||||
|
"//bar": test
|
||||||
|
"foo//bar": test
|
||||||
|
"/*foo*/": test
|
||||||
|
"foo/*foo*/bar": test
|
||||||
|
"/*": test
|
||||||
|
"foo/*bar": test
|
||||||
|
# quotes in key name
|
||||||
|
"\"": test
|
||||||
|
"foo\"bar": test
|
||||||
|
"'''": test
|
||||||
|
"foo'''bar": test
|
||||||
|
# control char in key name
|
||||||
|
":": test
|
||||||
|
"foo:bar": test
|
||||||
|
"{": test
|
||||||
|
"foo{bar": test
|
||||||
|
"}": test
|
||||||
|
"foo}bar": test
|
||||||
|
"[": test
|
||||||
|
"foo[bar": test
|
||||||
|
"]": test
|
||||||
|
"foo]bar": test
|
||||||
|
# newline
|
||||||
|
nl1:
|
||||||
|
test
|
||||||
|
nl2
|
||||||
|
:
|
||||||
|
test
|
||||||
|
|
||||||
|
nl3
|
||||||
|
|
||||||
|
:
|
||||||
|
|
||||||
|
test
|
||||||
|
}
|
13
tests/assets/nu_json/oa_result.hjson
Normal file
13
tests/assets/nu_json/oa_result.hjson
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[
|
||||||
|
a
|
||||||
|
{}
|
||||||
|
{}
|
||||||
|
[]
|
||||||
|
[]
|
||||||
|
{
|
||||||
|
b: 1
|
||||||
|
c: []
|
||||||
|
d: {}
|
||||||
|
}
|
||||||
|
[]
|
||||||
|
]
|
13
tests/assets/nu_json/oa_result.json
Normal file
13
tests/assets/nu_json/oa_result.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[
|
||||||
|
"a",
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
{
|
||||||
|
"b": 1,
|
||||||
|
"c": [],
|
||||||
|
"d": {}
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
]
|
13
tests/assets/nu_json/oa_test.hjson
Normal file
13
tests/assets/nu_json/oa_test.hjson
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[
|
||||||
|
a
|
||||||
|
{}
|
||||||
|
{}
|
||||||
|
[]
|
||||||
|
[]
|
||||||
|
{
|
||||||
|
b: 1
|
||||||
|
c: []
|
||||||
|
d: {}
|
||||||
|
}
|
||||||
|
[]
|
||||||
|
]
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user