cadmpeg-ir 0.6.5

CAD data model, validation, diffing, and codec API for cadmpeg.
// SPDX-License-Identifier: Apache-2.0
use crate::annotations::{AnnotationBuilder, AnnotationIdentityCollision, StreamHandle};
use crate::provenance::Exactness;

#[test]
fn remapping_refuses_collisions_across_tables_without_mutation() {
    let mut builder = AnnotationBuilder::new();
    let stream = StreamHandle::new(crate::stream_name!("source"));
    builder.note("test:model:point#provenance", &stream, 7, Some("point"));
    builder.exactness("test:model:point#exactness", Exactness::Inferred);
    let mut annotations = builder.build();
    let before = annotations.clone();
    let error = annotations
        .map_ids(|_| Ok("test:model:point#merged".to_owned()))
        .unwrap()
        .unwrap_err();
    assert!(matches!(error, AnnotationIdentityCollision { id } if id == "test:model:point#merged"));
    assert_eq!(annotations, before);
}

#[test]
fn remapping_calls_once_per_identity_and_preserves_each_annotation() {
    let mut builder = AnnotationBuilder::new();
    let stream = StreamHandle::new(crate::stream_name!("source"));
    builder.note("test:model:point#a", &stream, 7, Some("point"));
    builder.exactness("test:model:point#a", Exactness::Inferred);
    builder.derived("test:model:point#b", "position").unwrap();
    let mut annotations = builder.build();
    let before = annotations.clone();
    let mut calls = Vec::new();
    annotations
        .map_ids(|id| {
            calls.push(id.to_owned());
            Ok(format!("{id}-mapped"))
        })
        .unwrap()
        .unwrap();
    assert_eq!(calls, ["test:model:point#a", "test:model:point#b"]);
    for (id, note) in &before.provenance {
        assert_eq!(
            annotations.provenance.get(&format!("{id}-mapped")),
            Some(note)
        );
    }
    for (id, note) in before.exactness() {
        assert_eq!(
            annotations.exactness().get(&format!("{id}-mapped")),
            Some(note)
        );
    }
    assert_eq!(annotations.provenance.len(), before.provenance.len());
    assert_eq!(annotations.exactness().len(), before.exactness().len());
}

#[test]
fn appending_refuses_shared_identities_in_either_table_without_mutation() {
    for reverse in [false, true] {
        let stream = StreamHandle::new(crate::stream_name!("source"));
        let mut left = AnnotationBuilder::new();
        left.note("test:model:point#shared", &stream, 1, None);
        let mut right = AnnotationBuilder::new();
        right.note("test:model:point#new", &stream, 2, None);
        right.exactness("test:model:point#shared", Exactness::Derived);
        let (mut target, incoming) = if reverse {
            (right.build(), left.build())
        } else {
            (left.build(), right.build())
        };
        let before = target.clone();
        let error = target.append(incoming).unwrap_err();
        assert!(
            matches!(error, AnnotationIdentityCollision { id } if id == "test:model:point#shared")
        );
        assert_eq!(target, before);
    }
}

#[test]
fn appending_disjoint_annotations_preserves_both_tables() {
    let stream = StreamHandle::new(crate::stream_name!("source"));
    let mut left = AnnotationBuilder::new();
    left.note("test:model:point#a", &stream, 1, None);
    let mut right = AnnotationBuilder::new();
    right.note("test:model:point#b", &stream, 2, Some("point"));
    right.exactness("test:model:point#b", Exactness::Derived);
    let mut target = left.build();
    let incoming = right.build();
    let original = target.clone();
    target.append(incoming.clone()).unwrap();
    assert_eq!(target.provenance.len(), 2);
    assert_eq!(target.exactness(), incoming.exactness());
    for (id, note) in original.provenance.iter().chain(&incoming.provenance) {
        assert_eq!(target.provenance.get(id), Some(note));
    }
}

#[test]
fn charged_remapping_preserves_collision_text_and_tables() {
    let mut builder = AnnotationBuilder::new();
    let stream = StreamHandle::new(crate::stream_name!("source"));
    builder.note("source-a", &stream, 7, Some("point"));
    builder.exactness("source-b", Exactness::Inferred);
    let mut annotations = builder.build();
    let before = annotations.clone();
    let error = cadmpeg_core::CodecError::from(
        annotations
            .map_ids(|_| Ok("merged".into()))
            .unwrap()
            .unwrap_err(),
    );
    assert!(
        matches!(error, cadmpeg_core::CodecError::Malformed(ref message)
        if message == "annotation identity collision at merged")
    );
    assert_eq!(annotations, before);
}