Skip to content

Commit

Permalink
Test merging happy path
Browse files Browse the repository at this point in the history
  • Loading branch information
theory committed Sep 6, 2024
1 parent a6559ac commit 38bcc7d
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 5 deletions.
16 changes: 11 additions & 5 deletions src/meta/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,20 +298,26 @@ impl TryFrom<Value> for Meta {
}
}

impl TryFrom<&[Value]> for Meta {
impl TryFrom<&[&Value]> for Meta {
type Error = Box<dyn Error>;
fn try_from(meta: &[Value]) -> Result<Self, Self::Error> {
// Merge multiple spec values into a single Meta object. The first value
// in `meta` should be the primary metadata, generally included in a
// distribution. Subsequent values will be merged into that first value
// via the [RFC 7396] merge pattern.
//
// [RFC 7396]: https://www.rfc-editor.org/rfc/rfc7396.html
fn try_from(meta: &[&Value]) -> Result<Self, Self::Error> {
if meta.is_empty() {
return Err(Box::from("meta contains no values"));
}

// Find the version of the first doc.
let version =
util::get_version(&meta[0]).ok_or("no spec version found in first meta value")?;
util::get_version(meta[0]).ok_or("no spec version found in first meta value")?;

// Convert the first doc to v2 if necessary.
let mut v2 = match version {
1 => v1::to_v2(&meta[0])?,
1 => v1::to_v2(meta[0])?,
2 => meta[0].clone(),
_ => return Err(Box::from(format!("Unknown meta version {version}"))),
};
Expand All @@ -324,7 +330,7 @@ impl TryFrom<&[Value]> for Meta {
// Validate the patched doc and return.
let mut validator = crate::valid::Validator::new();
validator.validate(&v2).map_err(|e| e.to_string())?;
Meta::from_version(version, v2)
Meta::from_version(2, v2)
}
}

Expand Down
109 changes: 109 additions & 0 deletions src/meta/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,112 @@ fn test_bad_corpus() -> Result<(), Box<dyn Error>> {

Ok(())
}

#[test]
fn test_try_merge_v1() -> Result<(), Box<dyn Error>> {
// Load a v1 META file.
let dir: PathBuf = [env!("CARGO_MANIFEST_DIR"), "corpus"].iter().collect();
let widget_file = dir.join("v1").join("widget.json");
let contents: Value = serde_json::from_reader(File::open(&widget_file)?)?;

// expect maps a JSON pointer to an expected value.
for (name, patch, expect) in [
(
"license",
json!({"license": "MIT"}),
json!({"/license": "MIT"}),
),
(
"tle",
json!({"contents": {"extensions": {"widget": {"tle": true}}}}),
json!({"/contents/extensions/widget": {
"control": "widget.control",
"sql": "sql/widget.sql.in",
"tle": true,
}}),
),
(
"categories",
json!({"classifications": {"categories": ["Analytics", "Connectors"]}}),
json!({"/classifications/categories": ["Analytics", "Connectors"]}),
),
(
"tags",
json!({"classifications": {"tags": ["hi", "go", "ick"]}}),
json!({"/classifications/tags": ["hi", "go", "ick"]}),
),
(
"resources",
json!({"resources": {
"issues": "https://example.com/issues",
"repository": "https://example.com/repo",
}}),
json!({"/resources": {
"homepage": "http://widget.example.org/",
"issues": "https://example.com/issues",
"repository": "https://example.com/repo",
}}),
),
] {
run_merge_case(name, &contents, &patch, &expect)?;
}

Ok(())
}

#[test]
fn test_try_merge_v2() -> Result<(), Box<dyn Error>> {
// Load a v2 META file.
let dir: PathBuf = [env!("CARGO_MANIFEST_DIR"), "corpus"].iter().collect();
let widget_file = dir.join("v2").join("minimal.json");
let contents: Value = serde_json::from_reader(File::open(&widget_file)?)?;

// expect maps a JSON pointer to an expected value.
for (name, patch, expect) in [
(
"license",
json!({"license": "MIT"}),
json!({"/license": "MIT"}),
),
(
"tle",
json!({"contents": {"extensions": {"pair": {"tle": true}}}}),
json!({"/contents/extensions/pair": {
"sql": "sql/pair.sql",
"control": "pair.control",
"tle": true,
}}),
),
] {
run_merge_case(name, &contents, &patch, &expect)?;
}

Ok(())
}

fn run_merge_case(
name: &str,
orig: &Value,
patch: &Value,
expect: &Value,
) -> Result<(), Box<dyn Error>> {
let meta = vec![orig, patch];
match Meta::try_from(meta.as_slice()) {
Err(e) => panic!("widget.json patching {name} failed: {e}"),
Ok(m) => {
// Convert the Meta object to JSON.
let output: Result<Value, Box<dyn Error>> = m.try_into();
match output {
Err(e) => panic!("widget.json {name} serialization failed: {e}"),
Ok(val) => {
// Compare expected values at pointers.
for (p, v) in expect.as_object().unwrap() {
assert_eq!(v, val.pointer(p).unwrap())
}
}
}
}
}

Ok(())
}

0 comments on commit 38bcc7d

Please sign in to comment.