proofframe 0.7.2

Rust-native Arrow contracts, exact checks, fingerprints, and verifiable evidence
Documentation
mod support;

use std::sync::Arc;

use arrow::array::{
    ArrayRef, BooleanArray, Decimal128Array, Float64Array, Int64Array, StringArray,
    StringViewArray, UInt64Array,
};
use arrow::datatypes::{DataType, Field, Schema};
use arrow::record_batch::RecordBatch;
use proofframe::{CompiledContract, ContractDocument, ExecutionOptions, execute_reader};
use serde_json::{Value, json};

use support::reader_from_batches;

fn compile(source: &str, schema: &Schema) -> CompiledContract {
    let document = ContractDocument::from_json(source).unwrap();
    CompiledContract::compile_document(&document, schema).unwrap()
}

fn compile_json(source: Value, schema: &Schema) -> CompiledContract {
    compile(&source.to_string(), schema)
}

#[test]
fn row_count_and_null_ratio_are_dataset_level_violations() {
    let schema = Arc::new(Schema::new(vec![Field::new("email", DataType::Utf8, true)]));
    let batch = RecordBatch::try_new(
        schema.clone(),
        vec![Arc::new(StringArray::from(vec![Some("a@b.dev"), None, None])) as ArrayRef],
    )
    .unwrap();
    let plan = compile(
        r#"{
            "version":"proofframe.contract.v2",
            "columns":{},
            "dataset_rules":{
                "row_count":{"min":4},
                "null_ratio":{"email":{"max":0.5}}
            }
        }"#,
        schema.as_ref(),
    );

    let report = execute_reader(
        reader_from_batches(vec![batch]),
        &plan,
        &ExecutionOptions::default(),
    )
    .unwrap();

    assert_eq!(report.violation_count, 2);
    assert_eq!(
        report
            .findings
            .iter()
            .map(|finding| finding.rule)
            .collect::<Vec<_>>(),
        vec!["row_count", "null_ratio"]
    );
}

#[test]
fn composite_unique_is_exact_across_record_batch_boundaries() {
    let schema = Arc::new(Schema::new(vec![
        Field::new("order_id", DataType::Int64, false),
        Field::new("line_id", DataType::Int64, false),
    ]));
    let make_batch = |orders: &[i64], lines: &[i64]| {
        RecordBatch::try_new(
            schema.clone(),
            vec![
                Arc::new(Int64Array::from_iter_values(orders.iter().copied())) as ArrayRef,
                Arc::new(Int64Array::from_iter_values(lines.iter().copied())) as ArrayRef,
            ],
        )
        .unwrap()
    };
    let plan = compile_json(
        json!({
            "version": "proofframe.contract.v2",
            "columns": {},
            "dataset_rules": {
                "composite_unique": [{
                    "name": "line_key",
                    "columns": ["order_id", "line_id"]
                }]
            }
        }),
        schema.as_ref(),
    );

    let report = execute_reader(
        reader_from_batches(vec![make_batch(&[1, 1], &[1, 2]), make_batch(&[1], &[1])]),
        &plan,
        &ExecutionOptions::default(),
    )
    .unwrap();

    assert_eq!(report.violation_count, 1);
    assert!(report.findings.iter().any(|finding| {
        finding.rule == "composite_unique"
            && finding.row == Some(2)
            && finding.message.contains("line_key")
    }));
}

#[test]
fn distinct_count_and_ratio_use_exact_dataset_state() {
    let schema = Arc::new(Schema::new(vec![Field::new(
        "customer_id",
        DataType::Int64,
        false,
    )]));
    let batch = RecordBatch::try_new(
        schema.clone(),
        vec![Arc::new(Int64Array::from_iter_values([1_i64, 1, 2, 3])) as ArrayRef],
    )
    .unwrap();
    let plan = compile(
        r#"{
            "version":"proofframe.contract.v2",
            "columns":{},
            "dataset_rules":{
                "distinct_count":{"customer_id":{"min":4}},
                "distinct_ratio":{"customer_id":{"min":1.0}}
            }
        }"#,
        schema.as_ref(),
    );

    let report = execute_reader(
        reader_from_batches(vec![batch]),
        &plan,
        &ExecutionOptions::default(),
    )
    .unwrap();

    assert_eq!(report.violation_count, 2);
    assert_eq!(
        report
            .findings
            .iter()
            .map(|finding| finding.rule)
            .collect::<Vec<_>>(),
        vec!["distinct_count", "distinct_ratio"]
    );
}

#[test]
fn distinct_count_supports_every_fixed_width_scalar_family_exactly() {
    let schema = Arc::new(Schema::new(vec![
        Field::new("enabled", DataType::Boolean, false),
        Field::new("unsigned_id", DataType::UInt64, false),
        Field::new("score", DataType::Float64, false),
        Field::new("amount", DataType::Decimal128(20, 2), false),
    ]));
    let amount = Decimal128Array::from_iter_values([10_001_i128, 10_001, 20_002])
        .with_precision_and_scale(20, 2)
        .unwrap();
    let batch = RecordBatch::try_new(
        schema.clone(),
        vec![
            Arc::new(BooleanArray::from(vec![true, true, false])) as ArrayRef,
            Arc::new(UInt64Array::from_iter_values([
                9_007_199_254_740_993_u64,
                9_007_199_254_740_993,
                9_007_199_254_740_995,
            ])) as ArrayRef,
            Arc::new(Float64Array::from_iter_values([1.5, 1.5, 2.5])) as ArrayRef,
            Arc::new(amount) as ArrayRef,
        ],
    )
    .unwrap();
    let plan = compile(
        r#"{
            "version":"proofframe.contract.v2",
            "columns":{},
            "dataset_rules":{"distinct_count":{
                "enabled":{"min":3},
                "unsigned_id":{"min":3},
                "score":{"min":3},
                "amount":{"min":3}
            }}
        }"#,
        schema.as_ref(),
    );

    let report = execute_reader(
        reader_from_batches(vec![batch]),
        &plan,
        &ExecutionOptions::default(),
    )
    .unwrap();

    assert_eq!(report.violation_count, 4);
    assert_eq!(
        report
            .findings
            .iter()
            .map(|finding| finding.column.as_str())
            .collect::<Vec<_>>(),
        vec!["enabled", "unsigned_id", "score", "amount"]
    );
}

#[test]
fn composite_unique_uses_type_tagged_canonical_scalar_keys() {
    let schema = Arc::new(Schema::new(vec![
        Field::new("enabled", DataType::Boolean, false),
        Field::new("amount", DataType::Decimal128(20, 2), false),
        Field::new("label", DataType::Utf8View, false),
    ]));
    let amount = Decimal128Array::from_iter_values([10_001_i128, 20_002, 10_001])
        .with_precision_and_scale(20, 2)
        .unwrap();
    let batch = RecordBatch::try_new(
        schema.clone(),
        vec![
            Arc::new(BooleanArray::from(vec![true, false, true])) as ArrayRef,
            Arc::new(amount) as ArrayRef,
            Arc::new(StringViewArray::from(vec!["alpha", "beta", "alpha"])) as ArrayRef,
        ],
    )
    .unwrap();
    let plan = compile(
        r#"{
            "version":"proofframe.contract.v2",
            "columns":{},
            "dataset_rules":{"composite_unique":[{
                "name":"typed_key","columns":["enabled","amount","label"]
            }]}
        }"#,
        schema.as_ref(),
    );

    let report = execute_reader(
        reader_from_batches(vec![batch]),
        &plan,
        &ExecutionOptions::default(),
    )
    .unwrap();

    assert_eq!(report.violation_count, 1);
    assert_eq!(report.findings[0].row, Some(2));
}