use boml::prelude::*; /// Test that boml can parse booleans and bare keys. #[test] fn bools_and_bare_keys() { let toml_source = concat!( "val1 = true\n", "val2 = false\n", "5678 = true\n", "dash-ed = true\n", "under_score = true\n" ); let toml = Toml::parse(toml_source).unwrap(); toml.assert_values( vec![ ("val1", true), ("val2", false), ("5678", true), ("dash-ed", true), ("under_score", true), ] .into_iter() .map(|(k, v)| (k, TomlValue::Boolean(v))) .collect(), ); } /// Test that boml can parse quoted keys. #[test] fn quoted_keys() { let toml_source = concat!( "'val0.1.1' = true\n", "'ʎǝʞ' = true\n", "\"quoted 'key'\" = true\n", "'quoted \"key\" 2' = true\n", ); let toml = Toml::parse(toml_source).unwrap(); toml.assert_values( vec![ ("val0.1.1", true), ("ʎǝʞ", true), ("quoted 'key'", true), ("quoted \"key\" 2", true), ] .into_iter() .map(|(k, v)| (k, TomlValue::Boolean(v))) .collect(), ); } /// Test that boml can handle dotted keys. #[test] fn dotted_keys() { let toml_source = concat!( "table.bool = true\n", "table.string = 'hi'\n", "table. spaced = 69\n", "table .infinity = -inf\n", ); let toml = Toml::parse(toml_source).unwrap(); let table = toml.get_table("table").unwrap(); assert!(table.get_boolean("bool").unwrap()); assert_eq!(table.get_string("string").unwrap(), "hi"); assert_eq!(table.get_integer("spaced").unwrap(), 69); assert_eq!(table.get_float("infinity").unwrap(), -f64::INFINITY); } /// Test that boml can parse literal strings and multiline literal strings. #[test] fn literal_strings() { let single = "Me when I have to write a demo sentence to test my incredible TOML parser but dunno what to say"; let multi = "Bruhhhh I gotta write\n*another*\ndemo sentence???\n:("; let toml_source = format!("single = '{single}'\n") + &format!("multi = '''{multi}'''"); let toml = Toml::parse(&toml_source).unwrap(); toml.assert_strings(vec![("single", single), ("multi", multi)]); } /// Test that boml can parse basic strings and multiline basic strings. #[test] fn basic_strings() { let toml_source = concat!( "normal = \"normality 100\"\n", r#"quotes = "Bro I got \"quotes\"" "#, "\n", r#"escapes = "\t\n\r\\" "#, "\n", "multi = \"\"\"me when\\n", "i do multiline\\r pretty neat", "\"\"\"\n", "whitespace = \"\"\"white\\ \n\n\n\r\n space\"\"\"" ); let toml = Toml::parse(toml_source).unwrap(); toml.assert_strings(vec![ ("normal", "normality 100"), ("quotes", "Bro I got \"quotes\""), ("escapes", "\t\n\r\\"), ("multi", "me when\ni do multiline\r pretty neat"), ("whitespace", "whitespace"), ]); } /// Test that boml can parse integers. #[test] fn integers() { let toml_source = concat!( "hex = 0x10\n", "decimal = 10\n", "octal = 0o10\n", "binary = 0b10\n", "neghex = -0x10\n", "posoctal = +0o10\n", "lmao = -0\n", "underscore = 10_00\n", "single = 2\n", ); let toml = Toml::parse(toml_source).unwrap(); toml.assert_values( vec![ ("hex", 16), ("decimal", 10), ("octal", 8), ("binary", 2), ("neghex", -16), ("posoctal", 8), ("lmao", 0), ("underscore", 1000), ("single", 2), ] .into_iter() .map(|(k, v)| (k, TomlValue::Integer(v))) .collect(), ); } /// Test that boml can parse floats. #[test] fn floats() { let toml_source = concat!( "fractional = 0.345\n", "exponential = 4e2\n", "exponential_neg = 4e-2\n", "exponential_pos = 4e+2\n", "pos_fractional = +0.567\n", "neg_fractional = -0.123\n", "capital_exponential = 2E2\n", "combined = 7.27e2\n", "nan = +nan\n", "infinity = -inf\n", "underscore = 10_00.0\n", ); let toml = Toml::parse(toml_source).unwrap(); toml.assert_values( vec![ ("fractional", 0.345), ("exponential", 4e2), ("exponential_neg", 4e-2), ("exponential_pos", 4e2), ("pos_fractional", 0.567), ("neg_fractional", -0.123), ("capital_exponential", 2e2), ("combined", 727.0), ("infinity", -f64::INFINITY), ("underscore", 1000.0), ] .into_iter() .map(|(key, val)| (key, TomlValue::Float(val))) .collect(), ); // NaN != NaN, so we have to check with the `is_nan()` method. let nan = toml.get_float("nan"); assert!(nan.is_ok()); assert!(nan.unwrap().is_nan()) } /// Test that boml can parse tables. #[test] fn tables() { let toml_source = concat!( "empty = {}\n", "inline = { name = 'inline', num = inf }\n", "\n", "[table1]\n", "name = 'table1'\n", "\n", "[table2]\n", "name = 'table2'\n", "num = 420\n", "\n", "[table3]\n", "array = ['hi', 'bye']\n", "array2 = [1]\n", ); let toml = Toml::parse(toml_source).unwrap(); let _empty = toml.get_table("empty").unwrap(); let inline = toml.get_table("inline").unwrap(); assert_eq!(inline.get_string("name"), Ok("inline")); assert_eq!(inline.get_float("num"), Ok(f64::INFINITY)); let table1 = toml.get_table("table1").unwrap(); assert_eq!(table1.get_string("name"), Ok("table1")); let table2 = toml.get_table("table2").unwrap(); assert_eq!(table2.get_string("name"), Ok("table2")); assert_eq!(table2.get_integer("num"), Ok(420)); let table3 = toml.get_table("table3").unwrap(); let array = table3.get_array("array").unwrap(); let array2 = table3.get_array("array2").unwrap(); assert_eq!(array.len(), 2); assert_eq!(array2.len(), 1); assert_eq!(array.first().unwrap().string().unwrap(), "hi"); assert_eq!(array.get(1).unwrap().string().unwrap(), "bye"); assert_eq!(array2.first().unwrap().integer().unwrap(), 1); } /// Test that boml can parse arrays. #[test] fn arrays() { let toml_source = concat!( "strings = ['hi', 'hello', 'how are you']\n", "nested = ['me', ['when i', 'nest'], 'arrays']\n", "tables = [{name = 'bruh'}, {name = 'bruh 2 electric boogaloo'}]\n", "single = [2]\n" ); // panic!("`{}`", &toml_source[160..=163]); let toml = Toml::parse(toml_source).unwrap(); let strings = toml.get_array("strings").unwrap(); let strings: Vec<&str> = strings.iter().map(|val| val.string().unwrap()).collect(); assert_eq!(strings, vec!["hi", "hello", "how are you"]); let mut nested = toml.get_array("nested").unwrap().iter(); assert_eq!(nested.next().unwrap().string().unwrap(), "me"); let mut subtable = nested.next().unwrap().array().unwrap().iter(); assert_eq!(subtable.next().unwrap().string().unwrap(), "when i"); assert_eq!(subtable.next().unwrap().string().unwrap(), "nest"); assert_eq!(nested.next().unwrap().string().unwrap(), "arrays"); let mut tables = toml.get_array("tables").unwrap().iter(); let table1 = tables.next().unwrap().table().unwrap(); assert_eq!(table1.get_string("name").unwrap(), "bruh"); let table2 = tables.next().unwrap().table().unwrap(); assert_eq!( table2.get_string("name").unwrap(), "bruh 2 electric boogaloo" ); let single = toml.get_array("single").unwrap(); assert_eq!(single.len(), 1); assert_eq!(single.first().unwrap().integer().unwrap(), 2); } /// Test that boml can parse array tables. #[test] fn array_tables() { let toml_source = concat!( "[[entry]]\n", "idx = 0\n", "value = 'HALLO'\n", "\n", "[[entry]]\n", "idx = 1\n", "value = 727\n", "\n", "[[entry]]\n", "idx = 2\n", "value = true\n", ); let toml = Toml::parse(toml_source).unwrap(); let entries = toml.get_array("entry").unwrap(); let first = entries[0].table().unwrap(); assert_eq!(first.get_integer("idx").unwrap(), 0); assert_eq!(first.get_string("value").unwrap(), "HALLO"); let second = entries[1].table().unwrap(); assert_eq!(second.get_integer("idx").unwrap(), 1); assert_eq!(second.get_integer("value").unwrap(), 727); let third = entries[2].table().unwrap(); assert_eq!(third.get_integer("idx").unwrap(), 2); assert!(third.get_boolean("value").unwrap()); } /// Test that boml works with weird formats - CRLF, weird spacings, etc. #[test] fn weird_formats() { let toml_source = concat!( " val1 = true\r\n", "val2= false", "\n\r\n\r\n\n", "val3 =true\n", "val4=false\n", "val5 = true \n", "[parent . \"child.dotted\"]\n", "yippee = true" ); let toml = Toml::new(toml_source).unwrap(); toml.assert_values( vec![ ("val1", true), ("val2", false), ("val3", true), ("val4", false), ("val5", true), ] .into_iter() .map(|(k, v)| (k, TomlValue::Boolean(v))) .collect(), ); let parent = toml.get_table("parent").unwrap(); let child = parent.get_table("child.dotted").unwrap(); assert!(child.get_boolean("yippee").unwrap()); } trait TomlTestUtils { fn assert_value(&self, key: &str, expected_value: TomlValue<'_>); fn assert_values(&self, expected_values: Vec<(&str, TomlValue<'_>)>); fn assert_strings(&self, strings: Vec<(&str, &str)>); } impl TomlTestUtils for Toml<'_> { #[inline] fn assert_value(&self, key: &str, expected_value: TomlValue<'_>) { assert_eq!(*self.get(key).unwrap(), expected_value); } #[inline] fn assert_values(&self, expected_values: Vec<(&str, TomlValue<'_>)>) { for (key, expected_value) in expected_values { self.assert_value(key, expected_value); } } fn assert_strings(&self, strings: Vec<(&str, &str)>) { for (key, expected_string) in strings { let value = self.get_string(key); assert!(value.is_ok()); assert_eq!(value.unwrap(), expected_string); } } }