209 строки
5.7 KiB
Rust
209 строки
5.7 KiB
Rust
#[macro_use]
|
|
extern crate serde;
|
|
extern crate serde_json;
|
|
|
|
use serde_json::Value;
|
|
use std::env;
|
|
use std::ffi::OsString;
|
|
use std::fs::{self, File};
|
|
use std::io::{BufReader, Write};
|
|
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
struct TestData {
|
|
avro: Value,
|
|
bigquery: Value,
|
|
json: Value,
|
|
#[serde(default, skip_serializing_if = "Value::is_null")]
|
|
context: Value,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
struct TestCase {
|
|
#[serde(default, skip_serializing_if = "Value::is_null")]
|
|
description: Value,
|
|
name: String,
|
|
// True if the schema does not involve ambiguous sections
|
|
#[serde(default)]
|
|
compatible: bool,
|
|
test: TestData,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
struct TestSuite {
|
|
#[serde(default, skip_serializing_if = "Value::is_null")]
|
|
description: Value,
|
|
name: String,
|
|
tests: Vec<TestCase>,
|
|
}
|
|
|
|
const TRUTHY_ENV_VALUES: [&str; 5] = ["y", "yes", "t", "true", "1"];
|
|
|
|
fn get_env_var_as_bool(var: &str, default: bool) -> bool {
|
|
match env::var(var) {
|
|
Ok(val) => TRUTHY_ENV_VALUES.contains(&val.to_lowercase().as_ref()),
|
|
_ => default,
|
|
}
|
|
}
|
|
|
|
fn format_json(obj: Value) -> String {
|
|
let pretty = serde_json::to_string_pretty(&obj).unwrap();
|
|
// 4 spaces
|
|
pretty.replace('\n', "\n ")
|
|
}
|
|
|
|
fn write_backup(path: &std::path::PathBuf) {
|
|
let mut backup = path.to_path_buf();
|
|
let mut extension = OsString::new();
|
|
if let Some(s) = backup.extension() {
|
|
extension.push(s);
|
|
extension.push(".");
|
|
};
|
|
extension.push("bak");
|
|
backup.set_extension(extension);
|
|
println!("Backing up: {:?} -> {:?}", path, backup);
|
|
fs::copy(path, backup).unwrap();
|
|
}
|
|
|
|
fn write_formatted_test(path: &std::path::PathBuf, suite: &TestSuite) {
|
|
println!("Formatting test: {:?}", path);
|
|
let formatted = serde_json::to_string_pretty(suite).unwrap();
|
|
let fp_write = File::create(path).unwrap();
|
|
writeln!(&fp_write, "{}", formatted).unwrap()
|
|
}
|
|
|
|
fn write_avro_tests(mut outfile: &File, suite: &TestSuite) {
|
|
for case in &suite.tests {
|
|
let formatted = format!(
|
|
r##"
|
|
#[test]{should_panic}
|
|
fn avro_{name}() {{
|
|
let input_data = r#"
|
|
{input_data}
|
|
"#;
|
|
let expected_data = r#"
|
|
{expected}
|
|
"#;
|
|
let mut context = Context {{
|
|
..Default::default()
|
|
}};
|
|
let input: Value = serde_json::from_str(input_data).unwrap();
|
|
let expected: Value = serde_json::from_str(expected_data).unwrap();
|
|
if expected.is_null() {{
|
|
// No expected data = no avro support
|
|
return;
|
|
}}
|
|
|
|
assert_eq!(expected, convert_avro(&input, context.clone()));
|
|
|
|
context.resolve_method = ResolveMethod::Panic;
|
|
convert_avro(&input, context);
|
|
}}
|
|
"##,
|
|
name = case.name,
|
|
should_panic = if case.compatible {
|
|
""
|
|
} else {
|
|
"\n#[should_panic]"
|
|
},
|
|
input_data = format_json(case.test.json.clone()),
|
|
expected = format_json(case.test.avro.clone()),
|
|
);
|
|
write!(outfile, "{}", formatted).unwrap()
|
|
}
|
|
}
|
|
|
|
fn write_bigquery_tests(mut outfile: &File, suite: &TestSuite) {
|
|
for case in &suite.tests {
|
|
let formatted = format!(
|
|
r##"
|
|
#[test]{should_panic}
|
|
fn bigquery_{name}() {{
|
|
let input_data = r#"
|
|
{input_data}
|
|
"#;
|
|
let expected_data = r#"
|
|
{expected}
|
|
"#;
|
|
let context_data = r#"
|
|
{context}
|
|
"#;
|
|
let context: Value = serde_json::from_str(context_data).unwrap();
|
|
let mut context: Context = if context.is_null() {{
|
|
Default::default()
|
|
}} else {{
|
|
serde_json::from_value(context).unwrap()
|
|
}};
|
|
let input: Value = serde_json::from_str(input_data).unwrap();
|
|
let expected: Value = serde_json::from_str(expected_data).unwrap();
|
|
assert_eq!(expected, convert_bigquery(&input, context.clone()));
|
|
|
|
context.resolve_method = ResolveMethod::Panic;
|
|
convert_bigquery(&input, context);
|
|
}}
|
|
"##,
|
|
name = case.name,
|
|
should_panic = if case.compatible {
|
|
""
|
|
} else {
|
|
"\n#[should_panic]"
|
|
},
|
|
input_data = format_json(case.test.json.clone()),
|
|
expected = format_json(case.test.bigquery.clone()),
|
|
context = format_json(case.test.context.clone()),
|
|
);
|
|
write!(outfile, "{}", formatted).unwrap()
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
let test_cases = "tests/resources/translate";
|
|
let mut avro_fp = File::create("tests/transpile_avro.rs").unwrap();
|
|
let mut bq_fp = File::create("tests/transpile_bigquery.rs").unwrap();
|
|
let format_tests = get_env_var_as_bool("FORMAT_TESTS", true);
|
|
let backup = get_env_var_as_bool("FORMAT_TESTS_BACKUP", false);
|
|
|
|
write!(
|
|
avro_fp,
|
|
r#"use jst::convert_avro;
|
|
use jst::{{Context, ResolveMethod}};
|
|
use pretty_assertions::assert_eq;
|
|
use serde_json::Value;
|
|
"#
|
|
)
|
|
.unwrap();
|
|
|
|
write!(
|
|
bq_fp,
|
|
r#"use jst::convert_bigquery;
|
|
use jst::{{Context, ResolveMethod}};
|
|
use pretty_assertions::assert_eq;
|
|
use serde_json::Value;
|
|
"#
|
|
)
|
|
.unwrap();
|
|
|
|
let mut paths: Vec<_> = fs::read_dir(test_cases)
|
|
.unwrap()
|
|
.map(|e| e.unwrap().path())
|
|
.filter(|e| match e.file_name() {
|
|
Some(os_str) => !os_str.to_str().unwrap().starts_with('.'),
|
|
None => false,
|
|
})
|
|
.collect();
|
|
paths.sort();
|
|
for path in paths {
|
|
println!("Test file: {:?}", path);
|
|
let file = File::open(&path).unwrap();
|
|
let reader = BufReader::new(file);
|
|
let suite: TestSuite = serde_json::from_reader(reader).unwrap();
|
|
write_avro_tests(&avro_fp, &suite);
|
|
write_bigquery_tests(&bq_fp, &suite);
|
|
if backup {
|
|
write_backup(&path);
|
|
}
|
|
if format_tests {
|
|
write_formatted_test(&path, &suite);
|
|
}
|
|
}
|
|
}
|