blob: 83ac64e6db5b2fa0a845ef81759d86298eaa4655 [file] [log] [blame]
macro_rules! parse_key {
($s:expr) => {{
let key = $s.parse::<Key>();
assert!(key.is_ok());
&key.unwrap()
}};
}
macro_rules! as_table {
($e:ident) => {{
assert!($e.is_table());
$e.as_table_mut().unwrap()
}};
}
// rusfmt, U Can't Touch This
#[cfg(test)]
#[rustfmt::skip]
mod tests {
use toml_edit::{Document, Key, Value, Table, Item, value, table, array, decorated};
use std::iter::FromIterator;
use std::fmt;
use pretty_assertions::assert_eq;
// Copied from https://github.com/colin-kiegel/rust-pretty-assertions/issues/24
/// Wrapper around string slice that makes debug output `{:?}` to print string same way as `{}`.
/// Used in different `assert*!` macros in combination with `pretty_assertions` crate to make
/// test failures to show nice diffs.
#[derive(PartialEq, Eq)]
struct PrettyString<'a>(pub &'a str);
/// Make diff to display string as multi-line string
impl<'a> fmt::Debug for PrettyString<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.0)
}
}
struct Test {
doc: Document,
}
fn given(input: &str) -> Test {
let doc = input.parse::<Document>();
assert!(doc.is_ok());
Test {
doc: doc.unwrap(),
}
}
impl Test {
fn running<F>(&mut self, func: F) -> &mut Self
where F: Fn(&mut Table)
{
{
let root = self.doc.as_table_mut();
func(root);
}
self
}
fn produces_display(&self, expected: &str) -> &Self {
assert_eq!(
PrettyString(expected),
PrettyString(&self.doc.to_string()));
self
}
fn produces_in_original_order(&self, expected: &str) -> &Self {
assert_eq!(
PrettyString(expected),
PrettyString(&self.doc.to_string_in_original_order()));
self
}
fn produces(&self, expected: &str) -> &Self {
self.produces_display(expected).produces_in_original_order(expected);
self
}
}
// insertion
#[test]
fn test_insert_leaf_table() {
given(r#"
[servers]
[servers.alpha]
ip = "10.0.0.1"
dc = "eqdc10"
[other.table]"#
).running(|root| {
root["servers"]["beta"] = table();
root["servers"]["beta"]["ip"] = value("10.0.0.2");
root["servers"]["beta"]["dc"] = value("eqdc10");
}).produces(r#"
[servers]
[servers.alpha]
ip = "10.0.0.1"
dc = "eqdc10"
[servers.beta]
ip = "10.0.0.2"
dc = "eqdc10"
[other.table]
"#
);
}
#[test]
fn test_inserted_leaf_table_goes_after_last_sibling() {
given(r#"
[package]
[dependencies]
[[example]]
[dependencies.opencl]
[dev-dependencies]"#
).running(|root| {
root["dependencies"]["newthing"] = table();
}).produces_display(r#"
[package]
[dependencies]
[dependencies.opencl]
[dependencies.newthing]
[[example]]
[dev-dependencies]
"#).produces_in_original_order(r#"
[package]
[dependencies]
[[example]]
[dependencies.opencl]
[dependencies.newthing]
[dev-dependencies]
"#);
}
#[test]
fn test_inserting_tables_from_different_parsed_docs() {
given(
"[a]"
).running(|root| {
let other = "[b]".parse::<Document>().unwrap();
root["b"] = other["b"].clone();
}).produces(
"[a]\n[b]\n"
);
}
#[test]
fn test_insert_nonleaf_table() {
given(r#"
[other.table]"#
).running(|root| {
root["servers"] = table();
root["servers"]["alpha"] = table();
root["servers"]["alpha"]["ip"] = value("10.0.0.1");
root["servers"]["alpha"]["dc"] = value("eqdc10");
}).produces(r#"
[other.table]
[servers]
[servers.alpha]
ip = "10.0.0.1"
dc = "eqdc10"
"#
);
}
#[test]
fn test_insert_array() {
given(r#"
[package]
title = "withoutarray""#
).running(|root| {
root["bin"] = array();
assert!(root["bin"].is_array_of_tables());
let array = root["bin"].as_array_of_tables_mut().unwrap();
{
let first = array.append(Table::new());
first["hello"] = value("world");
}
array.append(Table::new());
}).produces(r#"
[package]
title = "withoutarray"
[[bin]]
hello = "world"
[[bin]]
"#
);
}
#[test]
fn test_insert_values() {
given(r#"
[tbl.son]"#
).running(|root| {
root["tbl"]["key1"] = value("value1");
root["tbl"]["\"key2\""] = value(42);
root["tbl"]["'key3'"] = value(8.1415926);
}).produces(r#"
[tbl]
key1 = "value1"
"key2" = 42
'key3' = 8.1415926
[tbl.son]
"#
);
}
// removal
#[test]
fn test_remove_leaf_table() {
given(r#"
[servers]
# Indentation (tabs and/or spaces) is allowed but not required
[servers.alpha]
ip = "10.0.0.1"
dc = "eqdc10"
[servers.beta]
ip = "10.0.0.2"
dc = "eqdc10""#
).running(|root| {
let servers = root.entry("servers");
let servers = as_table!(servers);
assert!(servers.remove("alpha").is_some());
}).produces(r#"
[servers]
[servers.beta]
ip = "10.0.0.2"
dc = "eqdc10"
"#
);
}
#[test]
fn test_remove_nonleaf_table() {
given(r#"
title = "not relevant"
# comment 1
[a.b.c] # comment 1.1
key1 = 1 # comment 1.2
# comment 2
[b] # comment 2.1
key2 = 2 # comment 2.2
# comment 3
[a] # comment 3.1
key3 = 3 # comment 3.2
[[a.'array']]
b = 1
[[a.b.c.trololololololo]] # ohohohohoho
c = 2
key3 = 42
# comment on some other table
[some.other.table]
# comment 4
[a.b] # comment 4.1
key4 = 4 # comment 4.2
key41 = 41 # comment 4.3
"#).running(|root| {
assert!(root.remove("a").is_some());
}).produces(r#"
title = "not relevant"
# comment 2
[b] # comment 2.1
key2 = 2 # comment 2.2
# comment on some other table
[some.other.table]
"#);
}
#[test]
fn test_remove_array_entry() {
given(r#"
[package]
name = "hello"
version = "1.0.0"
[[bin]]
name = "world"
path = "src/bin/world/main.rs"
[dependencies]
nom = "4.0" # future is here
[[bin]]
name = "delete me please"
path = "src/bin/dmp/main.rs""#
).running(|root| {
let dmp = root.entry("bin");
assert!(dmp.is_array_of_tables());
let dmp = dmp.as_array_of_tables_mut().unwrap();
assert_eq!(dmp.len(), 2);
dmp.remove(1);
assert_eq!(dmp.len(), 1);
}).produces(r#"
[package]
name = "hello"
version = "1.0.0"
[[bin]]
name = "world"
path = "src/bin/world/main.rs"
[dependencies]
nom = "4.0" # future is here
"#
);
}
#[test]
fn test_remove_array() {
given(r#"
[package]
name = "hello"
version = "1.0.0"
[[bin]]
name = "world"
path = "src/bin/world/main.rs"
[dependencies]
nom = "4.0" # future is here
[[bin]]
name = "delete me please"
path = "src/bin/dmp/main.rs""#
).running(|root| {
assert!(root.remove("bin").is_some());
}).produces(r#"
[package]
name = "hello"
version = "1.0.0"
[dependencies]
nom = "4.0" # future is here
"#
);
}
#[test]
fn test_remove_value() {
given(r#"
name = "hello"
# delete this
version = "1.0.0" # please
documentation = "https://docs.rs/hello""#
).running(|root| {
let value = root.remove("version");
assert!(value.is_some());
let value = value.unwrap();
assert!(value.is_value());
let value = value.as_value().unwrap();
assert!(value.is_str());
let value = value.as_str().unwrap();
assert_eq!(value, "1.0.0");
}).produces(r#"
name = "hello"
documentation = "https://docs.rs/hello"
"#
);
}
#[test]
fn test_remove_last_value_from_implicit() {
given(r#"
[a]
b = 1"#
).running(|root| {
let a = root.entry("a");
assert!(a.is_table());
let a = as_table!(a);
a.set_implicit(true);
let value = a.remove("b");
assert!(value.is_some());
let value = value.unwrap();
assert!(value.is_value());
let value = value.as_value().unwrap();
assert_eq!(value.as_integer(), Some(1));
}).produces(r#""#);
}
// values
#[test]
fn test_sort_values() {
given(r#"
[a.z]
[a]
# this comment is attached to b
b = 2 # as well as this
a = 1
c = 3
[a.y]"#
).running(|root| {
let a = root.entry("a");
let a = as_table!(a);
a.sort_values();
}).produces_display(r#"
[a]
a = 1
# this comment is attached to b
b = 2 # as well as this
c = 3
[a.z]
[a.y]
"#
).produces_in_original_order(r#"
[a.z]
[a]
a = 1
# this comment is attached to b
b = 2 # as well as this
c = 3
[a.y]
"#);
}
#[test]
fn test_set_position() {
given(r#"
[package]
[dependencies]
[dependencies.opencl]
[dev-dependencies]"#
).running(|root| {
for (header, table) in root.iter_mut() {
if header == "dependencies" {
let tab = as_table!(table);
tab.set_position(0);
let (_, segmented) = tab.iter_mut().next().unwrap();
as_table!(segmented).set_position(5)
}
}
}).produces_in_original_order(r#" [dependencies]
[package]
[dev-dependencies]
[dependencies.opencl]
"#);
}
#[test]
fn test_multiple_zero_positions() {
given(r#"
[package]
[dependencies]
[dependencies.opencl]
a=""
[dev-dependencies]"#
).running(|root| {
for (_, table) in root.iter_mut() {
as_table!(table).set_position(0)
}
}).produces_in_original_order(r#"
[package]
[dependencies]
[dev-dependencies]
[dependencies.opencl]
a=""
"#);
}
#[test]
fn test_multiple_max_usize_positions() {
given(r#"
[package]
[dependencies]
[dependencies.opencl]
a=""
[dev-dependencies]"#
).running(|root| {
for (_, table) in root.iter_mut() {
as_table!(table).set_position(usize::MAX)
}
}).produces_in_original_order(r#" [dependencies.opencl]
a=""
[package]
[dependencies]
[dev-dependencies]
"#);
}
macro_rules! as_array {
($entry:ident) => (
{
assert!($entry.is_value());
let a = $entry.as_value_mut().unwrap();
assert!(a.is_array());
a.as_array_mut().unwrap()
}
);
}
#[test]
fn test_insert_replace_into_array() {
given(r#"
a = [1,2,3]
b = []"#
).running(|root| {
{
let a = root.entry("a");
let a = as_array!(a);
assert_eq!(a.len(), 3);
assert!(a.get(2).is_some());
assert!(a.push(4).is_ok());
assert_eq!(a.len(), 4);
a.fmt();
}
let b = root.entry("b");
let b = as_array!(b);
assert!(b.is_empty());
assert!(b.push("hello").is_ok());
assert_eq!(b.len(), 1);
assert!(b.push_formatted(decorated("world".into(), "\n", "\n")).is_ok());
assert!(b.push_formatted(decorated("test".into(), "", "")).is_ok());
assert!(b.insert(1, "beep").is_ok());
assert!(b.insert_formatted(2, decorated("boop".into(), " ", " ")).is_ok());
// This should preserve formatting.
assert_eq!(b.replace(2, "zoink").unwrap().as_str(), Some("boop"));
// This should replace formatting.
assert_eq!(b.replace_formatted(4, decorated("yikes".into(), " ", "")).unwrap().as_str(), Some("test"));
// Check that pushing a different type into an array fails.
assert!(b.push(42).is_err());
}).produces(r#"
a = [1, 2, 3, 4]
b = ["hello", "beep", "zoink" ,
"world"
, "yikes"]
"#
);
}
#[test]
fn test_remove_from_array() {
given(r#"
a = [1, 2, 3, 4]
b = ["hello"]"#
).running(|root| {
{
let a = root.entry("a");
let a = as_array!(a);
assert_eq!(a.len(), 4);
assert!(a.remove(3).is_integer());
assert_eq!(a.len(), 3);
}
let b = root.entry("b");
let b = as_array!(b);
assert_eq!(b.len(), 1);
assert!(b.remove(0).is_str());
assert!(b.is_empty());
}).produces(r#"
a = [1, 2, 3]
b = []
"#
);
}
macro_rules! as_inline_table {
($entry:ident) => (
{
assert!($entry.is_value());
let a = $entry.as_value_mut().unwrap();
assert!(a.is_inline_table());
a.as_inline_table_mut().unwrap()
}
);
}
#[test]
fn test_insert_into_inline_table() {
given(r#"
a = {a=2, c = 3}
b = {}"#
).running(|root| {
{
let a = root.entry("a");
let a = as_inline_table!(a);
assert_eq!(a.len(), 2);
assert!(a.contains_key("a") && a.get("c").is_some() && a.get_mut("c").is_some());
a.get_or_insert("b", 42);
assert_eq!(a.len(), 3);
a.fmt();
}
let b = root.entry("b");
let b = as_inline_table!(b);
assert!(b.is_empty());
b.get_or_insert("'hello'", "world");
assert_eq!(b.len(), 1);
b.fmt()
}).produces(r#"
a = { a = 2, c = 3, b = 42 }
b = { 'hello' = "world" }
"#
);
}
#[test]
fn test_remove_from_inline_table() {
given(r#"
a = {a=2, c = 3, b = 42}
b = {'hello' = "world"}"#
).running(|root| {
{
let a = root.entry("a");
let a = as_inline_table!(a);
assert_eq!(a.len(), 3);
assert!(a.remove("c").is_some());
assert_eq!(a.len(), 2);
}
let b = root.entry("b");
let b = as_inline_table!(b);
assert_eq!(b.len(), 1);
assert!(b.remove("hello").is_some());
assert!(b.is_empty());
}).produces(r#"
a = {a=2, b = 42}
b = {}
"#
);
}
#[test]
fn test_as_table_like() {
given(r#"
a = {a=2, c = 3, b = 42}
x = {}
[[bin]]
[b]
x = "y"
[empty]"#
).running(|root| {
let a = root["a"].as_table_like();
assert!(a.is_some());
let a = a.unwrap();
assert_eq!(a.iter().count(), 3);
assert_eq!(a.len(), 3);
assert_eq!(a.get("a").and_then(Item::as_integer), Some(2));
let b = root["b"].as_table_like();
assert!(b.is_some());
let b = b.unwrap();
assert_eq!(b.iter().count(), 1);
assert_eq!(b.len(), 1);
assert_eq!(b.get("x").and_then(Item::as_str), Some("y"));
assert_eq!(root["x"].as_table_like().map(|t| t.iter().count()), Some(0));
assert_eq!(root["empty"].as_table_like().map(|t| t.is_empty()), Some(true));
assert!(root["bin"].as_table_like().is_none());
});
}
#[test]
fn test_inline_table_append() {
let mut a = Value::from_iter(vec![
(parse_key!("a"), 1),
(parse_key!("b"), 2),
(parse_key!("c"), 3),
]);
let a = a.as_inline_table_mut().unwrap();
let mut b = Value::from_iter(vec![
(parse_key!("c"), 4),
(parse_key!("d"), 5),
(parse_key!("e"), 6),
]);
let b = b.as_inline_table_mut().unwrap();
b.merge_into(a);
assert_eq!(a.len(), 5);
assert!(a.contains_key("e"));
assert!(b.is_empty());
}
} // mod tests