use crate::prog_gen::supported_testers::SupportedTester;
use crate::Result;
use indexmap::IndexMap;
use phf::phf_map;
use std::collections::{HashMap, HashSet};
use std::sync::RwLock;
include!(concat!(env!("OUT_DIR"), "/test_templates.rs"));
lazy_static! {
static ref LOADED_TESTS: RwLock<HashMap<String, TestTemplate>> = RwLock::new(HashMap::new());
}
#[derive(Debug, Deserialize, Clone, Serialize)]
pub struct TestTemplate {
pub parameter_list: Option<IndexMap<String, String>>,
pub aliases: Option<IndexMap<String, String>>,
pub values: Option<IndexMap<String, serde_json::Value>>,
pub parameters: Option<IndexMap<String, TestTemplateParameter>>,
pub collections: Option<IndexMap<String, TestTemplateCollection>>,
pub class_name: Option<String>,
pub accepted_values: Option<IndexMap<String, Vec<serde_json::Value>>>,
}
#[derive(Debug, Deserialize, Clone, Serialize)]
pub struct TestTemplateCollection {
pub parameters: Option<IndexMap<String, TestTemplateParameter>>,
pub collections: Option<IndexMap<String, TestTemplateCollection>>,
}
#[derive(Debug, Deserialize, Clone, Serialize)]
pub struct TestTemplateParameter {
#[serde(alias = "type")]
pub kind: Option<String>,
pub aliases: Option<Vec<String>>,
pub value: Option<serde_json::Value>,
pub accepted_values: Option<Vec<serde_json::Value>>,
}
pub fn load_test_from_lib(
tester: &SupportedTester,
lib_name: &str,
test_name: &str,
) -> Result<TestTemplate> {
log_trace!(
"Looking for test template definition '{}' in library '{}' (for {})",
test_name,
lib_name,
tester
);
let tester_name = tester.to_string().to_lowercase();
let key = format!("{}_{}_{}", &tester_name, lib_name, test_name);
if let Some(t) = LOADED_TESTS.read().unwrap().get(&key) {
return Ok(t.clone());
}
let mut available_tests: HashSet<String> = HashSet::new();
for path in crate::PROG_GEN_CONFIG.test_template_load_path() {
let path = path.join(format!("{}/{}/{}.json", tester_name, lib_name, test_name));
if path.exists() {
let contents = std::fs::read_to_string(&path)?;
let t: TestTemplate = serde_json::from_str(&contents)?;
LOADED_TESTS.write().unwrap().insert(key, t.clone());
return Ok(t);
}
if path.parent().unwrap().exists() {
for entry in std::fs::read_dir(path.parent().unwrap())? {
let entry = entry?;
if entry.path().is_file() {
let file_name = entry.file_name().to_string_lossy().to_string();
if file_name.ends_with(".json") {
available_tests.insert(file_name);
}
}
}
}
}
match import_test_template(&format!("{}/{}/{}.json", tester_name, lib_name, test_name)) {
Ok(t) => {
LOADED_TESTS.write().unwrap().insert(key, t.clone());
return Ok(t);
}
Err(e) => {
if e.to_string().contains("No test template found at path") {
log_debug!("{}", e);
let mut msg = format!(
"No test method named '{}' found in library '{}' (for {})",
test_name,
lib_name,
tester
);
if available_tests.len() > 0 {
let mut available_tests: Vec<String> = available_tests.into_iter().collect();
available_tests.sort();
msg.push_str("\n\nThe following test methods are available in this library:");
for t in available_tests {
msg.push_str(&format!("\n - {}", t));
}
}
bail!("{}", msg);
} else {
bail!("{}", e);
}
}
}
}
fn import_test_template(path: &str) -> Result<TestTemplate> {
match TEST_TEMPLATES.get(path) {
None => bail!("No test template found at path '{}'", path),
Some(s) => Ok(serde_json::from_str(s)?),
}
}
#[cfg(test)]
mod unit_tests {
use super::*;
#[test]
fn test_all_templates_import_cleanly() {
for (file, content) in TEST_TEMPLATES.entries() {
let _: TestTemplate =
serde_json::from_str(content).expect(&format!("Failed to import {}", file));
}
}
#[test]
fn test_kind_alias_and_recursive_collections_import() {
let template: TestTemplate = serde_json::from_str(
r#"{
"parameters": {
"enableSoftset": {
"kind": "boolean",
"value": "false"
}
},
"collections": {
"tsen": {
"parameters": {
"zDataDeltaLimit": {
"kind": "double",
"value": "0.0"
}
},
"collections": {
"registers": {
"parameters": {
"zLowLimit": {
"type": "double",
"value": "-Infinity"
}
}
}
}
}
}
}"#,
)
.unwrap();
assert_eq!(
template.parameters.as_ref().unwrap()["enableSoftset"]
.kind
.as_deref(),
Some("boolean")
);
assert!(template.collections.as_ref().unwrap().contains_key("tsen"));
assert!(
template.collections.as_ref().unwrap()["tsen"]
.collections
.as_ref()
.unwrap()
.contains_key("registers")
);
assert_eq!(
template.collections.as_ref().unwrap()["tsen"]
.collections
.as_ref()
.unwrap()["registers"]
.parameters
.as_ref()
.unwrap()["zLowLimit"]
.kind
.as_deref(),
Some("double")
);
}
}