summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib.rs7
-rw-r--r--src/tests/mod.rs56
-rw-r--r--src/tests/parsing.rs35
3 files changed, 97 insertions, 1 deletions
diff --git a/src/lib.rs b/src/lib.rs
index bd01f59..dc29621 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -14,6 +14,9 @@ use alloc::{format, vec};
use core::fmt;
use core::mem::take;
+#[cfg(test)]
+mod tests;
+
/// File and line information
#[derive(Clone, Debug)]
pub struct Location {
@@ -635,6 +638,8 @@ impl Configuration {
///
/// `reader` can be `&str`, `&[u8]`, or anything that implements [`std::io::BufRead`]
/// (if the `std` feature is enabled) such as `std::io::BufReader<std::fs::File>`.
+ ///
+ /// `filename` is used in error messages.
pub fn load<R: Read>(filename: &str, mut reader: R) -> Result<Self> {
// avoid big code size by using dyn reference.
// the impact on performance is not really important.
@@ -717,7 +722,7 @@ impl Configuration {
pub fn subkeys(&self, key: &str) -> impl '_ + Iterator<Item = &str> {
let key_dot = format!("{key}.");
let start_idx = self.first_subkey_index(key);
- (start_idx..).map_while(move |i| {
+ (start_idx..self.items.len()).map_while(move |i| {
let this_key = &self.items[i].0;
let suffix = this_key.strip_prefix(&key_dot)?;
Some(suffix.split_once('.').map_or(suffix, |(x, _)| x))
diff --git a/src/tests/mod.rs b/src/tests/mod.rs
new file mode 100644
index 0000000..58cd2b0
--- /dev/null
+++ b/src/tests/mod.rs
@@ -0,0 +1,56 @@
+use crate::Configuration;
+use std::collections::HashSet;
+
+mod parsing;
+
+fn check_configs_equal(
+ cfg1: &Configuration,
+ cfg2: &Configuration,
+) -> Result<(), Box<dyn std::error::Error>> {
+ fn check_configs_equal_at(
+ cfg1: &Configuration,
+ cfg2: &Configuration,
+ prefix: &str,
+ ) -> Result<(), Box<dyn std::error::Error>> {
+ let (keys1, keys2): (HashSet<&str>, HashSet<&str>) =
+ if let Some(k) = prefix.strip_suffix('.') {
+ (cfg1.subkeys(k).collect(), cfg2.subkeys(k).collect())
+ } else {
+ (cfg1.keys().collect(), cfg2.keys().collect())
+ };
+ for key in keys1.difference(&keys2) {
+ return Err(format!(
+ "Key {prefix}{key} appears at {}, but not in other configuration",
+ cfg1.location(&format!("{prefix}{key}")).unwrap()
+ )
+ .into());
+ }
+ for key in keys2.difference(&keys1) {
+ return Err(format!(
+ "Key {prefix}{key} appears at {}, but not in other configuration",
+ cfg2.location(&format!("{prefix}{key}")).unwrap()
+ )
+ .into());
+ }
+ for key in &keys1 {
+ let full_key = format!("{prefix}{key}");
+ let val1 = cfg1.get(&full_key);
+ let val2 = cfg2.get(&full_key);
+ if val1 != val2 {
+ return Err(format!(
+ "Mismatch between values for key {full_key}
+ defined as {val1:?} at {},
+but defined as {val2:?} at {}",
+ cfg1.location(&full_key)
+ .map_or("<nowhere>".into(), |x| format!("{x}")),
+ cfg2.location(&full_key)
+ .map_or("<nowhere>".into(), |x| format!("{x}")),
+ )
+ .into());
+ }
+ check_configs_equal_at(cfg1, cfg2, &format!("{full_key}."))?;
+ }
+ Ok(())
+ }
+ check_configs_equal_at(cfg1, cfg2, "")
+}
diff --git a/src/tests/parsing.rs b/src/tests/parsing.rs
new file mode 100644
index 0000000..2e701ed
--- /dev/null
+++ b/src/tests/parsing.rs
@@ -0,0 +1,35 @@
+use crate::Configuration;
+
+static TEST_DIR: &str = "../tests/parsing";
+
+fn single_test(flat_name: &str, complex_name: &str) -> Result<(), Box<dyn std::error::Error>> {
+ let config1 = Configuration::load_path(format!("{TEST_DIR}/{flat_name}"))?;
+ let config2 = Configuration::load_path(format!("{TEST_DIR}/{complex_name}"))?;
+ super::check_configs_equal(&config1, &config2)
+}
+
+fn try_parsing() -> Result<(), Box<dyn std::error::Error>> {
+ let tests = std::fs::read_dir(TEST_DIR).map_err(|e| {
+ format!(
+ "error reading {TEST_DIR}: {e} — try moving pom-rs to inside the main pom repository?"
+ )
+ })?;
+ for test_entry in tests {
+ let filename = test_entry
+ .map_err(|e| format!("error reading tests directory {TEST_DIR}: {e}"))?
+ .file_name()
+ .into_string()
+ .expect("bad UTF-8 in test name (file in {TEST_DIR})");
+ if filename.ends_with(".flat.pom") {
+ single_test(&filename, filename.replace(".flat.pom", ".pom").as_ref())?;
+ }
+ }
+ Ok(())
+}
+
+#[test]
+fn parsing() {
+ if let Err(e) = try_parsing() {
+ panic!("Error: {e}");
+ }
+}