questdb-rs 4.0.5

QuestDB Client Library for Rust
Documentation
#[cfg(feature = "json_tests")]
pub mod json_tests {
    use indoc::indoc;
    use serde::{Deserialize, Serialize};
    use serde_json;
    use slugify::slugify;
    use std::fs::File;
    use std::io::{BufWriter, Write};
    use std::path::PathBuf;

    #[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();
        // eprintln!("Parsed JSON: {:#?}", specs);
        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)?);
        // let mut output = String::new();
        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)?;
            // for line in serde_json::to_string_pretty(&spec).unwrap().split("\n") {
            //     writeln!(output, "/// {}", line)?;
            // }
            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(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>> {
    #[cfg(feature = "json_tests")]
    {
        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(())
}