simple-update-in 0.1.0

Immutable nested update with structural sharing
Documentation
//! Core conformance cases for maps, arrays, removal, coercion, and upsert.
//!
//! Each test builds a literal input, runs one update, and asserts on the result
//! value. Pointer-sharing assertions live in `structural_sharing.rs`.

mod common;

use common::*;
use simple_update_in::Value;

#[test]
fn set_in_flat_map() {
    let from = obj(vec![("abc", n(123.0)), ("def", n(456.0))]);
    let actual = run(from.clone(), &[key("xyz")], constant(n(789.0)));
    assert!(!from.ptr_eq(&actual));
    assert_eq!(
        actual,
        obj(vec![
            ("abc", n(123.0)),
            ("def", n(456.0)),
            ("xyz", n(789.0))
        ]),
    );
}

#[test]
fn update_in_flat_map() {
    let from = obj(vec![("one", n(1.0)), ("two", n(2.0))]);
    let actual = run(from.clone(), &[key("one")], multiply(10.0));
    assert!(!from.ptr_eq(&actual));
    assert_eq!(actual, obj(vec![("one", n(10.0)), ("two", n(2.0))]));
}

#[test]
fn update_in_map() {
    let from = obj(vec![
        ("odd", obj(vec![("one", n(1.0)), ("three", n(3.0))])),
        ("even", obj(vec![("two", n(2.0))])),
    ]);
    let actual = run(from, &[key("odd"), key("one")], multiply(10.0));
    assert_eq!(
        actual,
        obj(vec![
            ("odd", obj(vec![("one", n(10.0)), ("three", n(3.0))])),
            ("even", obj(vec![("two", n(2.0))])),
        ]),
    );
}

#[test]
fn remove_in_map() {
    let from = obj(vec![("one", n(1.0)), ("two", n(2.0)), ("three", n(3.0))]);
    let actual = remove(from.clone(), &[key("three")]);
    assert!(!from.ptr_eq(&actual));
    assert_eq!(actual, obj(vec![("one", n(1.0)), ("two", n(2.0))]));
    assert!(actual.as_object().unwrap().get("three").is_none());
}

#[test]
fn remove_in_map_2() {
    let from = obj(vec![
        ("odd", obj(vec![("one", n(1.0)), ("three", n(3.0))])),
        ("even", obj(vec![("two", n(2.0))])),
    ]);
    let actual = remove(from, &[key("odd"), key("three")]);
    assert_eq!(
        actual,
        obj(vec![
            ("odd", obj(vec![("one", n(1.0))])),
            ("even", obj(vec![("two", n(2.0))])),
        ]),
    );
}

#[test]
fn set_in_flat_array() {
    let from = arr(vec![n(0.0), n(1.0), n(2.0)]);
    let actual = run(from.clone(), &[idx(1)], constant(n(3.0)));
    assert!(!from.ptr_eq(&actual));
    assert_eq!(actual, arr(vec![n(0.0), n(3.0), n(2.0)]));
}

#[test]
fn set_in_2d_array() {
    let from = arr(vec![
        n(0.0),
        arr(vec![n(1.1), n(1.2)]),
        arr(vec![n(2.1), n(2.2)]),
    ]);
    let actual = run(from, &[idx(1), idx(1)], constant(n(3.0)));
    assert_eq!(
        actual,
        arr(vec![
            n(0.0),
            arr(vec![n(1.1), n(3.0)]),
            arr(vec![n(2.1), n(2.2)]),
        ]),
    );
}

#[test]
fn insert_in_array() {
    let from = arr(vec![n(0.0), n(1.0), n(2.0)]);
    let actual = run(from.clone(), &[idx(3)], constant(n(3.0)));
    assert!(!from.ptr_eq(&actual));
    assert_eq!(actual, arr(vec![n(0.0), n(1.0), n(2.0), n(3.0)]));
}

#[test]
fn remove_in_array() {
    let from = arr(vec![n(0.0), n(1.0), n(2.0)]);
    let actual = remove(from.clone(), &[idx(1)]);
    assert!(!from.ptr_eq(&actual));
    assert_eq!(actual, arr(vec![n(0.0), n(2.0)]));
}

#[test]
fn remove_in_array_2() {
    let from = arr(vec![arr(vec![n(1.0), n(3.0)]), arr(vec![n(2.0), n(4.0)])]);
    let actual = remove(from, &[idx(0), idx(1)]);
    assert_eq!(
        actual,
        arr(vec![arr(vec![n(1.0)]), arr(vec![n(2.0), n(4.0)])]),
    );
}

#[test]
fn mix_map_array() {
    let from = obj(vec![
        ("one", arr(vec![n(1.1), n(1.2), n(1.3)])),
        ("two", arr(vec![n(2.1), n(2.2), n(2.3)])),
    ]);
    let actual = run(from, &[key("one"), idx(1)], multiply(10.0));
    assert_eq!(
        actual,
        obj(vec![
            ("one", arr(vec![n(1.1), n(12.0), n(1.3)])),
            ("two", arr(vec![n(2.1), n(2.2), n(2.3)])),
        ]),
    );
}

#[test]
fn mix_array_map() {
    let from = arr(vec![
        obj(vec![("one", n(1.0)), ("three", n(3.0))]),
        obj(vec![("two", n(2.0))]),
    ]);
    let actual = run(from, &[idx(0), key("three")], multiply(10.0));
    assert_eq!(
        actual,
        arr(vec![
            obj(vec![("one", n(1.0)), ("three", n(30.0))]),
            obj(vec![("two", n(2.0))]),
        ]),
    );
}

#[test]
fn expand_undefined_as_map() {
    let actual = run(Value::Undefined, &[key("one")], constant(n(1.0)));
    assert_eq!(actual, obj(vec![("one", n(1.0))]));
}

#[test]
fn expand_map() {
    let from = obj(vec![("two", obj(vec![("three", n(2.3))]))]);
    let actual = run(from, &[key("one"), key("two")], constant(n(1.2)));
    assert_eq!(
        actual,
        obj(vec![
            ("one", obj(vec![("two", n(1.2))])),
            ("two", obj(vec![("three", n(2.3))])),
        ]),
    );
}

#[test]
fn incompatible_type_convert_array_to_map() {
    let from = arr(vec![n(0.0)]);
    let actual = run(from.clone(), &[key("one")], constant(n(1.0)));
    assert!(!from.ptr_eq(&actual));
    assert_eq!(actual, obj(vec![("one", n(1.0))]));
}

#[test]
fn incompatible_type_convert_string_to_map() {
    let from = s("123");
    let actual = run(from, &[key("one")], constant(n(1.0)));
    assert_eq!(actual, obj(vec![("one", n(1.0))]));
}

#[test]
fn modifying_undefined_in_map() {
    let from = obj(vec![("one", n(1.0))]);
    let actual = run(
        from.clone(),
        &[key("two"), key("three")],
        guarded_multiply(10.0),
    );
    assert!(from.ptr_eq(&actual));
}

#[test]
fn modifying_undefined_in_array() {
    let from = arr(vec![n(0.0), n(1.0), n(2.0), n(3.0)]);
    let actual = run(from.clone(), &[idx(4), idx(5)], guarded_multiply(10.0));
    assert!(from.ptr_eq(&actual));
}

#[test]
fn untouched_in_map() {
    let from = obj(vec![("one", n(1.0))]);
    let actual = run(from.clone(), &[key("one")], identity);
    assert!(from.ptr_eq(&actual));
}

#[test]
fn untouched_in_array() {
    let from = arr(vec![n(0.0), n(1.0), n(2.0)]);
    let actual = run(from.clone(), &[idx(1)], identity);
    assert!(from.ptr_eq(&actual));
}

#[test]
fn removing_non_existing_key_in_map() {
    let from = obj(vec![("one", n(1.0))]);
    let actual = remove(from.clone(), &[key("two")]);
    assert!(from.ptr_eq(&actual));
}

#[test]
fn removing_non_existing_key_in_array() {
    let from = arr(vec![n(0.0)]);
    let actual = remove(from.clone(), &[idx(1)]);
    assert!(from.ptr_eq(&actual));
}

#[test]
fn removing_using_undefined_in_map() {
    let from = obj(vec![("one", n(1.0))]);
    let actual = run(from, &[key("one")], constant(Value::Undefined));
    assert_eq!(actual, obj(vec![]));
}

#[test]
fn removing_using_undefined_in_array() {
    let from = arr(vec![n(0.0)]);
    let actual = run(from, &[idx(0)], constant(Value::Undefined));
    assert_eq!(actual, arr(vec![]));
}

#[test]
fn incompatible_type_and_untouched_map() {
    let from = obj(vec![("one", n(1.0))]);
    let actual = run(from, &[idx(0)], constant(Value::Undefined));
    assert_eq!(actual, arr(vec![]));
}

#[test]
fn incompatible_type_and_untouched_array() {
    let from = arr(vec![n(0.0)]);
    let actual = run(from, &[key("one")], constant(Value::Undefined));
    assert_eq!(actual, obj(vec![]));
}