molgfx-core 0.1.2

The semantic scene graph: columnar tables, GPU record layouts, the borrowed coordinate seam.
Documentation
use super::*;

#[test]
fn strings_and_builders_lower_to_the_same_selection_ir() {
    let parsed = match "polymer and not water".parse::<Select>() {
        Ok(parsed) => parsed,
        Err(error) => panic!("selection parses: {error}"),
    };
    assert_eq!(parsed, Select::polymer().and(Select::water().negate()));
}

#[test]
fn boolean_precedence_and_parentheses_are_deterministic() {
    let implicit = match "protein or nucleic and not water".parse::<Select>() {
        Ok(parsed) => parsed,
        Err(error) => panic!("selection parses: {error}"),
    };
    assert_eq!(
        implicit,
        Select::protein().or(Select::nucleic().and(Select::water().negate()))
    );
    let grouped = match "(protein or nucleic) and not water".parse::<Select>() {
        Ok(parsed) => parsed,
        Err(error) => panic!("selection parses: {error}"),
    };
    assert_ne!(implicit, grouped);
}

#[test]
fn spatial_strings_use_the_validated_builder() {
    let parsed = match "within 5.5 of (ligand or water)".parse::<Select>() {
        Ok(parsed) => parsed,
        Err(error) => panic!("selection parses: {error}"),
    };
    let expected = match Select::within(5.5, Select::ligands().or(Select::water())) {
        Ok(expected) => expected,
        Err(error) => panic!("typed selection builds: {error}"),
    };
    assert_eq!(parsed, expected);
}

#[test]
fn hierarchy_and_property_strings_use_the_same_typed_builders() {
    let parsed = match "chain A and resname GLY and element C and b_factor >= 10".parse::<Select>()
    {
        Ok(parsed) => parsed,
        Err(error) => panic!("rich selection parses: {error}"),
    };
    let b_factor = match Select::b_factor(PropertyComparison::GreaterOrEqual, 10.0) {
        Ok(value) => value,
        Err(error) => panic!("B-factor predicate builds: {error}"),
    };
    let expected = match Select::chain("A") {
        Ok(value) => value,
        Err(error) => panic!("chain predicate builds: {error}"),
    }
    .and(match Select::residue_name("GLY") {
        Ok(value) => value,
        Err(error) => panic!("residue predicate builds: {error}"),
    })
    .and(match Select::element("C") {
        Ok(value) => value,
        Err(error) => panic!("element predicate builds: {error}"),
    })
    .and(b_factor);
    assert_eq!(parsed, expected);
}

#[test]
fn geometric_and_secondary_selection_builders_validate_input() {
    assert!(Select::in_sphere(molgfx_math::Vec3::ZERO, 2.0).is_ok());
    assert!(Select::in_box(-molgfx_math::Vec3::ONE, molgfx_math::Vec3::ONE).is_ok());
    assert!(Select::in_sphere(molgfx_math::Vec3::ZERO, f32::NAN).is_err());
    assert!(Select::in_box(molgfx_math::Vec3::ONE, -molgfx_math::Vec3::ONE).is_err());
    assert_eq!(
        Select::helix(),
        Select::secondary(SecondaryStructure::Helix)
    );
    assert_eq!(
        Select::hydrogen(),
        Select::from_str("hydrogen").ok().unwrap()
    );
}

#[test]
fn malformed_strings_return_the_stable_selection_error() {
    for source in [
        "",
        "within nope of ligand",
        "protein and",
        "(water",
        "magic",
    ] {
        let Err(error) = source.parse::<Select>() else {
            panic!("malformed selection must fail: {source}")
        };
        assert_eq!(error.code(), "MOLGFX-E0034");
    }
    assert!(Select::within(f32::NAN, Select::all()).is_err());
    assert!(Select::within(-1.0, Select::all()).is_err());
}