df_ls_structure 0.3.0-rc.1

A language server for Dwarf Fortress RAW files
Documentation
use df_ls_core::{Choose, Clamp, Reference, ReferenceTo};
use df_ls_diagnostics::lsp_types::*;
use df_ls_lexical_analysis::test_utils::LexerTestBuilder;
use df_ls_structure::*;
use df_ls_syntax_analysis::test_utils::SyntaxTestBuilder;

#[test]
fn test_item_garments_and_shields() {
    SyntaxTestBuilder::from_lexer_test_builder(
        LexerTestBuilder::test_source(
            "item

            [OBJECT:ITEM]

            [ITEM_ARMOR:ITEM_ARMOR_LEATHER]
                [NAME:armor:armor]
                [PREPLURAL:suits of]
                [MATERIAL_PLACEHOLDER:leather]
                [ARMORLEVEL:1]
                [UBSTEP:1]
                [LBSTEP:1]
                [SHAPED]
                [LAYER:ARMOR]
                [COVERAGE:0]
                [LAYER_SIZE:20]
                [LAYER_PERMIT:50]
                [MATERIAL_SIZE:6]

            [ITEM_GLOVES:ITEM_GLOVES_GAUNTLETS]
                [NAME:gauntlet:gauntlets]
                [ARMORLEVEL:2]
                [UPSTEP:MAX]
                [SHAPED]
                [LAYER:ARMOR]
                [COVERAGE:100]
                [LAYER_SIZE:20]
                [LAYER_PERMIT:15]
                [MATERIAL_SIZE:2]

            [ITEM_SHIELD:ITEM_SHIELD_SHIELD]
                [NAME:shield:shields]
                [ARMORLEVEL:2]
                [BLOCKCHANCE:20]
                [UPSTEP:2]
                [MATERIAL_SIZE:4]
            ",
        )
        .add_test_lexer_diagnostics_codes(vec![])
        .add_test_lexer_diagnostics_ranges(vec![]),
    )
    .add_test_structure(DFRaw {
        header: "item".to_owned(),
        token_structure: vec![ObjectToken {
            item_tokens: vec![
                ItemToken::ArmorToken(ArmorToken {
                    reference: Some(ReferenceTo::new("ITEM_ARMOR_LEATHER".to_owned())),
                    ubstep: Some(Choose::Choice1(1)),
                    name: Some(("armor".to_owned(), "armor".to_owned())),
                    material_size: Some(6),
                    shaped: Some(()),
                    layer_size: Some(20),
                    layer_permit: Some(50),
                    layer: Some(LayerEnum::Armor),
                    coverage: Some(0),
                    armorlevel: Some(1),
                    preplural: Some("suits of".to_owned()),
                    material_placeholder: Some("leather".to_owned()),
                    lbstep: Some(Choose::Choice1(1)),
                    ..Default::default()
                }),
                ItemToken::GlovesToken(GlovesToken {
                    reference: Some(ReferenceTo::new("ITEM_GLOVES_GAUNTLETS".to_owned())),
                    upstep: Some(Choose::Choice2(MaxEnum::Max)),
                    name: Some(("gauntlet".to_owned(), "gauntlets".to_owned())),
                    material_size: Some(2),
                    shaped: Some(()),
                    layer_size: Some(20),
                    layer_permit: Some(15),
                    layer: Some(LayerEnum::Armor),
                    coverage: Some(100),
                    armorlevel: Some(2),
                    ..Default::default()
                }),
                ItemToken::ShieldToken(ShieldToken {
                    reference: Some(ReferenceTo::new("ITEM_SHIELD_SHIELD".to_owned())),
                    blockchance: Some(Clamp::new(20)),
                    upstep: Some(Choose::Choice1(2)),
                    armorlevel: Some(2),
                    name: Some(("shield".to_owned(), "shields".to_owned())),
                    material_size: Some(4),
                    ..Default::default()
                }),
            ],
            ..Default::default()
        }],
    })
    .add_test_syntax_diagnostics_codes(vec![])
    .add_test_syntax_diagnostics_ranges(vec![])
    .run_test();
}

#[test]
fn test_item_siegeammo_and_toy_and_food_and_ammo() {
    SyntaxTestBuilder::from_lexer_test_builder(
        LexerTestBuilder::test_source(
            "item

            [OBJECT:ITEM]

            [ITEM_SIEGEAMMO:ITEM_SIEGEAMMO_BALLISTA]
                [NAME:ballista arrow:ballista arrows]
                [CLASS:BALLISTA]

            [ITEM_SIEGEAMMO:WRONG]
                [NAME:ballista arrow:ballista arrows]
                [CLASS:BA]

            [ITEM_TOY:ITEM_TOY_PUZZLEBOX]
                [NAME:puzzlebox:puzzleboxes]
                [HARD_MAT]

            [ITEM_FOOD:ITEM_FOOD_BISCUITS]
                [NAME:biscuits]
                [LEVEL:2]

            [ITEM_FOOD:ITEM_FOOD_STEW]
                [NAME:stew]
                [LEVEL:3]

            [ITEM_FOOD:ITEM_FOOD_ROAST]
                [NAME:roast]
                [LEVEL:4]

            [ITEM_FOOD:WRONG]
                [NAME:biscuits]
                [LEVEL:1]

            [ITEM_FOOD:WRONG]
                [NAME:biscuits]
                [LEVEL:5]

            [ITEM_AMMO:ITEM_AMMO_BOLTS]
                [NAME:bolt:bolts]
                [CLASS:BOLT]
                [SIZE:150]
                [ATTACK:EDGE:5:1000:stab:stabs:NO_SUB:1000]
                    [ATTACK_PREPARE_AND_RECOVER:3:3]
            ",
        )
        .add_test_lexer_diagnostics_codes(vec![])
        .add_test_lexer_diagnostics_ranges(vec![]),
    )
    .add_test_structure(DFRaw {
        header: "item".to_owned(),
        token_structure: vec![ObjectToken {
            item_tokens: vec![
                ItemToken::SiegeAmmoToken(SiegeAmmoToken {
                    reference: Some(ReferenceTo::new("ITEM_SIEGEAMMO_BALLISTA".to_owned())),
                    name: Some(("ballista arrow".to_owned(), "ballista arrows".to_owned())),
                    class: Some(SiegeAmmoClassEnum::Ballista),
                }),
                ItemToken::SiegeAmmoToken(SiegeAmmoToken {
                    reference: Some(ReferenceTo::new("WRONG".to_owned())),
                    name: Some(("ballista arrow".to_owned(), "ballista arrows".to_owned())),
                    class: None,
                }),
                ItemToken::ToyToken(ToyToken {
                    reference: Some(ReferenceTo::new("ITEM_TOY_PUZZLEBOX".to_owned())),
                    name: Some(("puzzlebox".to_owned(), "puzzleboxes".to_owned())),
                    hard_mat: Some(()),
                }),
                ItemToken::FoodToken(FoodToken {
                    reference: Some(ReferenceTo::new("ITEM_FOOD_BISCUITS".to_owned())),
                    name: Some("biscuits".to_owned()),
                    level: Some(Clamp::new(2)),
                }),
                ItemToken::FoodToken(FoodToken {
                    reference: Some(ReferenceTo::new("ITEM_FOOD_STEW".to_owned())),
                    name: Some("stew".to_owned()),
                    level: Some(Clamp::new(3)),
                }),
                ItemToken::FoodToken(FoodToken {
                    reference: Some(ReferenceTo::new("ITEM_FOOD_ROAST".to_owned())),
                    name: Some("roast".to_owned()),
                    level: Some(Clamp::new(4)),
                }),
                ItemToken::FoodToken(FoodToken {
                    reference: Some(ReferenceTo::new("WRONG".to_owned())),
                    name: Some("biscuits".to_owned()),
                    level: None,
                }),
                ItemToken::FoodToken(FoodToken {
                    reference: Some(ReferenceTo::new("WRONG".to_owned())),
                    name: Some("biscuits".to_owned()),
                    level: None,
                }),
                ItemToken::AmmoToken(AmmoToken {
                    reference: Some(ReferenceTo::new("ITEM_AMMO_BOLTS".to_owned())),
                    name: Some(("bolt".to_owned(), "bolts".to_owned())),
                    class: Some(Reference("BOLT".to_owned())),
                    size: Some(150),
                    attack: Some(ItemAttack {
                        attack: Some((
                            AttackTypeEnum::Edge,
                            5,
                            1000,
                            "stab".to_owned(),
                            "stabs".to_owned(),
                            Choose::Choice1(NoSubEnum::NoSub),
                            1000,
                        )),
                        attack_prepare_and_recover: Some((3, 3)),
                    }),
                }),
            ],
            ..Default::default()
        }],
    })
    .add_test_syntax_diagnostics_codes(vec!["wrong_enum_value", "too_small_int", "too_large_int"])
    .add_test_syntax_diagnostics_ranges(vec![
        Range {
            start: Position {
                line: 10,
                character: 23,
            },
            end: Position {
                line: 10,
                character: 25,
            },
        },
        Range {
            start: Position {
                line: 30,
                character: 23,
            },
            end: Position {
                line: 30,
                character: 24,
            },
        },
        Range {
            start: Position {
                line: 34,
                character: 23,
            },
            end: Position {
                line: 34,
                character: 24,
            },
        },
    ])
    .run_test();
}