|
| 1 | +/* |
| 2 | + * Copyright 2020 VMware, Inc. |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: BSD-2-Clause |
| 5 | + */ |
| 6 | + |
| 7 | +#[cfg(test)] |
| 8 | +mod tests { |
| 9 | + use serde::{Deserialize, Serialize}; |
| 10 | + use std::fs; |
| 11 | + use std::panic; |
| 12 | + use jsonpath_ri::jsonpath; |
| 13 | + |
| 14 | + #[derive(Debug, PartialEq, Serialize, Deserialize)] |
| 15 | + struct TestSuite { |
| 16 | + tests: Vec<Testcase>, |
| 17 | + } |
| 18 | + |
| 19 | + #[derive(Debug, PartialEq, Serialize, Deserialize)] |
| 20 | + struct Testcase { |
| 21 | + name: String, |
| 22 | + selector: String, |
| 23 | + document: serde_yaml::Value, // JSON deserialised as YAML |
| 24 | + result: serde_yaml::Value, // JSON deserialised as YAML |
| 25 | + } |
| 26 | + |
| 27 | + #[test] |
| 28 | + fn compliance_test_suite() { |
| 29 | + let y = fs::read_to_string("tests/cts.yaml").expect("failed to read cts.yaml"); |
| 30 | + |
| 31 | + let suite: TestSuite = serde_yaml::from_str(&y).expect("failed to deserialize cts.yaml"); |
| 32 | + |
| 33 | + let mut errors: Vec<String> = Vec::new(); |
| 34 | + for t in suite.tests { |
| 35 | + let result = panic::catch_unwind(|| { |
| 36 | + println!( |
| 37 | + "name = {}, selector = {}, document = {}, result = {}", |
| 38 | + t.name, |
| 39 | + t.selector, |
| 40 | + as_json(&t.document).expect("invalid document"), |
| 41 | + as_json(&t.result).expect("invalid result") |
| 42 | + ); |
| 43 | + let path = jsonpath::parse(&t.selector); |
| 44 | + assert!(path.is_ok(), "parse failed: {:?}", path.err().expect("should be an error")); |
| 45 | + |
| 46 | + if let Ok(p) = path { |
| 47 | + if let Ok(result) = p.find(as_json_value(&t.document).expect("invalid document")) { |
| 48 | + if result != as_json_value_array(&t.result).expect("invalid result") { |
| 49 | + assert!(false, "incorrect result") |
| 50 | + } |
| 51 | + } else { |
| 52 | + assert!(false, "find failed") // should not happen |
| 53 | + } |
| 54 | + } |
| 55 | + }); |
| 56 | + if let Err(err) = result { |
| 57 | + errors.push(format!("{:?}", err)); |
| 58 | + } |
| 59 | + } |
| 60 | + assert!(errors.is_empty()) |
| 61 | + } |
| 62 | + |
| 63 | + fn as_json(v: &serde_yaml::Value) -> Result<String, String> { |
| 64 | + match v { |
| 65 | + serde_yaml::Value::Null => Ok("null".to_string()), |
| 66 | + |
| 67 | + serde_yaml::Value::Bool(b) => Ok(b.to_string()), |
| 68 | + |
| 69 | + serde_yaml::Value::Number(num) => Ok(num.to_string()), |
| 70 | + |
| 71 | + serde_yaml::Value::String(s) => Ok(json::stringify(s.to_string())), |
| 72 | + |
| 73 | + serde_yaml::Value::Sequence(seq) => { |
| 74 | + let array_elements = seq |
| 75 | + .into_iter() |
| 76 | + .map(|v| as_json(v).expect("invalid sequence element")); |
| 77 | + Ok(format!("[{}]", itertools::join(array_elements, ","))) |
| 78 | + } |
| 79 | + |
| 80 | + serde_yaml::Value::Mapping(map) => { |
| 81 | + let object_members = map.iter().map(|(k, v)| { |
| 82 | + format!( |
| 83 | + "{}:{}", |
| 84 | + as_json(k).expect("invalid object key"), |
| 85 | + as_json(v).expect("invalid object value") |
| 86 | + ) |
| 87 | + }); |
| 88 | + Ok(format!("{{{}}}", itertools::join(object_members, ","))) |
| 89 | + } |
| 90 | + } |
| 91 | + } |
| 92 | + |
| 93 | + fn as_json_value(v: &serde_yaml::Value) -> Result<serde_json::Value, String> { |
| 94 | + match v { |
| 95 | + serde_yaml::Value::Null => Ok(serde_json::Value::Null), |
| 96 | + |
| 97 | + serde_yaml::Value::Bool(b) => Ok(serde_json::Value::Bool(*b)), |
| 98 | + |
| 99 | + serde_yaml::Value::Number(num) => Ok(serde_json::Value::Number(yaml_number_as_json(num.clone()))), |
| 100 | + |
| 101 | + serde_yaml::Value::String(s) => Ok(serde_json::Value::String(s.clone())), |
| 102 | + |
| 103 | + serde_yaml::Value::Sequence(seq) => { |
| 104 | + let array_elements = seq |
| 105 | + .into_iter() |
| 106 | + .map(|v| as_json_value(v).expect("invalid sequence element")); |
| 107 | + Ok(serde_json::Value::Array(array_elements.collect())) |
| 108 | + } |
| 109 | + |
| 110 | + serde_yaml::Value::Mapping(map) => { |
| 111 | + let object_members = map.iter().map(|(k, v)| { |
| 112 | + (serde_yaml::to_string(k).expect("non-string mapping key"), as_json_value(v).expect("invalid map value")) |
| 113 | + }); |
| 114 | + Ok(serde_json::Value::Object(object_members.collect())) |
| 115 | + } |
| 116 | + } |
| 117 | + } |
| 118 | + |
| 119 | + fn as_json_value_array(v: &serde_yaml::Value) -> Result<Vec<serde_json::Value>, String> { |
| 120 | + match v { |
| 121 | + serde_yaml::Value::Sequence(seq) => { |
| 122 | + let array_elements = seq |
| 123 | + .into_iter() |
| 124 | + .map(|v| as_json_value(v).expect("invalid sequence element")); |
| 125 | + Ok(array_elements.collect()) |
| 126 | + } |
| 127 | + _ => Err("not a sequence".to_string()) |
| 128 | + } |
| 129 | + } |
| 130 | + |
| 131 | + fn yaml_number_as_json(n: serde_yaml::Number) -> serde_json::Number { |
| 132 | + if n.is_i64() { |
| 133 | + serde_json::Number::from(n.as_i64().expect("invalid i64 in YAML")) |
| 134 | + } else if n.is_u64() { |
| 135 | + serde_json::Number::from(n.as_u64().expect("invalid u64 in YAML")) |
| 136 | + } else { |
| 137 | + serde_json::Number::from_f64(n.as_f64().expect("invalid f64 in YAML")).expect("invalid f64 for JSON") |
| 138 | + } |
| 139 | + } |
| 140 | +} |
0 commit comments