Add tests for the example KDL files (#1)

* Add From impls for KdlNodeValue

Most clients probably don't need to create these directly, but we may as
well make it easy for them.

* Add TryFrom impls to convert from KdlNodeValue to underlying types

This includes converting from borrowed values, which will produce `&str`
instead of `String`.

* Add test for parsing examples/ci.kdl

This tests that the file can parse, and that its contents match what we
expect. This test currently fails as the file cannot be parsed.

I may have gone a little overboard in the macro I wrote in order to
generate the expected nodes.

* Add test for parsing examples/cargo.kdl

* Add test for examples/nuget.kdl

Unlike the others, this one just validates that it parses, as the file
is sufficiently large that I don't want to copy its contents into the
test.
This commit is contained in:
Lily Ballard 2020-12-16 17:48:05 -08:00 committed by GitHub
parent 685a537658
commit 45ed92fdac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 136 additions and 0 deletions

136
tests/examples.rs Normal file
View File

@ -0,0 +1,136 @@
//! Tests the kdl files in the examples directory.
use kdl::*;
use std::collections::HashMap;
/// Helper for constructing nodes.
///
/// This takes input that's similar to KDL itself, but each node must be terminated with either
/// a semicolon or a braced block. Nodes whose name contains characters not valid in Rust
/// identifiers must be written as a string literal instead.
macro_rules! nodes {
([$v:ident]:name) => {};
([$v:ident]:name $name:ident $($tt:tt)*) => {
nodes!([$v]:values stringify!($name); {} {} $($tt)*)
};
([$v:ident]:name $name:literal $($tt:tt)*) => {
nodes!([$v]:values $name; {} {} $($tt)*)
};
([$v:ident]:values $name:expr; {$($value:literal,)*} $props:tt $new_value:literal $($tt:tt)*) => {
nodes!([$v]:values $name; {$($value,)* $new_value,} $props $($tt)*)
};
([$v:ident]:values $name:expr; $values:tt {$($key:ident=$prop:literal,)*} $new_key:ident=$new_prop:literal $($tt:tt)*) => {
nodes!([$v]:values $name; $values {$($key=$prop,)* $new_key=$new_prop,} $($tt)*)
};
([$v:ident]:values $name:expr; $values:tt $props:tt $(; $($tt:tt)*)?) => {
nodes!([$v]:values $name; $values $props {} $($($tt)*)?)
};
([$v:ident]:values $name:expr; {$($value:literal,)*} {$($key:ident=$prop:literal,)*} {$($child:tt)*} $($tail:tt)*) => {
$v.push(KdlNode {
name: $name.to_owned(),
values: vec![$( $value.to_owned().into() ),*],
properties: {
#[allow(unused_mut)]
let mut map = HashMap::new();
$(
map.insert(stringify!($key).to_owned(), $prop.to_owned().into());
)*
map
},
children: nodes!($($child)*),
});
nodes!([$v]:name $($tail)*);
};
// Explicitly match literal and ident at the start instead of $($tt:tt)*
// so we get better errors than "recursion limit exceeded" if we fail to match.
(:start $($tt:tt)+) => {{
let mut v = Vec::new();
nodes!([v]:name $($tt)+);
v
}};
($name:literal $($tt:tt)*) => {
nodes!(:start $name $($tt)*)
};
($name:ident $($tt:tt)*) => {
nodes!(:start $name $($tt)*)
};
() => { vec![] }
}
#[test]
fn test_ci() {
let doc = parse_document(include_str!("../examples/ci.kdl"));
let nodes = nodes! {
name "CI";
on "push" "pull_request";
env {
RUSTFLAGS "-Dwarnings"
}
jobs {
fmt_and_docs "Check fmt & build docs" {
"runs-on" "ubuntu-latest";
steps {
step uses="actions/checkout@v1";
step "Install Rust" uses="actions-rs/toolchain@v1" {
profile "minimal";
toolchain "stable";
components "rustfmt";
override true;
}
step "rustfmt" run="cargo fmt --all -- --check";
step "docs" run="cargo doc --no-deps";
}
}
build_and_test "Build & Test" {
"runs-on" "${{ matrix.os }}";
strategy {
matrix {
rust "1.46.0" "stable";
os "ubuntu-latest" "macOS-latest" "windows-latest";
}
}
steps {
step uses="actions/checkout@v1";
step "Install Rust" uses="actions-rs/toolchain@v1" {
profile "minimal";
toolchain "${{ matrix.rust }}";
components "clippy";
override true;
}
step "Clippy" run="cargo clippy --all -- -D warnings";
step "Run tests" run="cargo test --all --verbose";
}
}
}
};
assert_eq!(doc, Ok(nodes));
}
#[test]
fn test_cargo() {
let doc = parse_document(include_str!("../examples/cargo.kdl"));
let nodes = nodes! {
package {
name "kdl";
version "0.0.0";
description "kat's document language";
authors "Kat Marchán <kzm@zkat.tech>";
"license-file" "LICENSE.md";
edition "2018";
}
dependencies {
nom "6.0.1";
thiserror "1.0.22";
}
};
assert_eq!(doc, Ok(nodes));
}
#[test]
fn test_nuget() {
let doc = parse_document(include_str!("../examples/nuget.kdl"));
// This file is particularly large. It would be nice to validate it, but for now
// I'm just going to settle for making sure it parses.
doc.expect("Parsing failed");
}