pub mod json_tests {
use std::fs::File;
use std::io::{BufWriter, Write};
use std::path::PathBuf;
use serde::{Serialize, Deserialize};
use serde_json;
use slugify::slugify;
use indoc::indoc;
#[derive(Debug, Serialize, Deserialize)]
struct Symbol {
name: String,
value: String
}
#[derive(Debug, Serialize, Deserialize)]
struct StringColumn {
name: String,
value: String,
}
#[derive(Debug, Serialize, Deserialize)]
struct LongColumn {
name: String,
value: i64,
}
#[derive(Debug, Serialize, Deserialize)]
struct DoubleColumn {
name: String,
value: f64
}
#[derive(Debug, Serialize, Deserialize)]
struct BooleanColumn {
name: String,
value: bool
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "UPPERCASE")]
enum Column {
String(StringColumn),
Long(LongColumn),
Double(DoubleColumn),
Boolean(BooleanColumn)
}
#[derive(Debug, Serialize, Deserialize)]
struct Expected {
line: Option<String>,
#[serde(rename = "anyLines")]
any_lines: Option<Vec<String>>
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "status", rename_all = "UPPERCASE")]
enum Outcome {
Success(Expected),
Error
}
#[derive(Debug, Serialize, Deserialize)]
struct TestSpec {
#[serde(rename = "testName")]
test_name: String,
table: String,
symbols: Vec<Symbol>,
columns: Vec<Column>,
result: Outcome
}
fn parse() -> Vec<TestSpec> {
let mut json_path = PathBuf::from(
std::env::var("CARGO_MANIFEST_DIR").unwrap());
json_path.push("src");
json_path.push("tests");
json_path.push("interop");
json_path.push("ilp-client-interop-test.json");
let file = std::fs::File::open(json_path).unwrap();
serde_json::from_reader(file).unwrap()
}
pub fn build() -> Result<(), Box<dyn std::error::Error>> {
let specs = parse();
let mut file_path = PathBuf::from(std::env::var("OUT_DIR")?);
file_path.push("json_tests.rs");
let mut output = BufWriter::new(File::create(file_path)?);
writeln!(output, "{}", indoc!{r#"
// This file is auto-generated by build.rs.
use crate::{Result, ingress::{Buffer}};
use crate::tests::{TestResult};
fn matches_any_line(line: &str, expected: &[&str]) -> bool {
for &exp in expected {
if line == exp {
return true;
}
}
eprintln!(
"Could not match:\n {:?}\nTo any of: {:#?}",
line, expected);
false
}
"#})?;
for (index, spec) in specs.iter().enumerate() {
writeln!(output, "/// {}", spec.test_name)?;
writeln!(output, "#[test]")?;
writeln!(output, "fn test_{:03}_{}() -> TestResult {{",
index, slugify!(&spec.test_name, separator="_"))?;
writeln!(output, " let mut buffer = Buffer::new();")?;
let (expected, indent) = match &spec.result {
Outcome::Success(line) => (Some(line), ""),
Outcome::Error => (None, " ")
};
if expected.is_none() {
writeln!(output, " || -> Result<()> {{")?;
}
writeln!(output, "{} buffer", indent)?;
writeln!(output, "{} .table({:?})?", indent, spec.table)?;
for symbol in spec.symbols.iter() {
writeln!(output, "{} .symbol({:?}, {:?})?", indent, symbol.name, symbol.value)?;
}
for column in spec.columns.iter() {
match column {
Column::String(column) =>
writeln!(output, "{} .column_str({:?}, {:?})?", indent, column.name, column.value)?,
Column::Long(column) =>
writeln!(output, "{} .column_i64({:?}, {:?})?", indent, column.name, column.value)?,
Column::Double(column) =>
writeln!(output, "{} .column_f64({:?}, {:?})?", indent, column.name, column.value)?,
Column::Boolean(column) =>
writeln!(output, "{} .column_bool({:?}, {:?})?", indent, column.name, column.value)?,
}
}
writeln!(output, "{} .at_now()?;", indent)?;
if let Some(ref expected) = expected {
if let Some(ref line) = expected.line {
let exp_ln = format!("{}\n", line);
writeln!(output, " let exp = {:?};", exp_ln)?;
writeln!(output, " assert_eq!(buffer.as_str(), exp);")?;
}
else {
let any: Vec<String> = expected.any_lines.as_ref().unwrap()
.iter()
.map(|line| format!("{}\n", line))
.collect();
writeln!(output, " let any = [")?;
for line in any.iter() {
writeln!(output, " {:?},", line)?;
}
writeln!(output, " ];")?;
writeln!(output, " assert!(matches_any_line(buffer.as_str(), &any));")?;
}
}
else {
writeln!(output, " Ok(())")?;
writeln!(output, " }}().unwrap_err();")?;
}
writeln!(output, " Ok(())")?;
writeln!(output, "}}")?;
}
Ok(())
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=Cargo.lock");
println!("cargo:rerun-if-changed=src/test/interop/ilp-client-interop-test.json");
json_tests::build()?;
Ok(())
}