Tests, Tests, even more Tests and Holes

<
>
July 11, 2021

Just like every other good software developer I started adding tests 8 months into the project.
With a game such as Factor Y it’s sadly more difficult to write proper tests than with real world applications or algorithms.
Within a game’s setting what is truth keeps on changing and editing stats of e.g. a Belt might cause lots of tests to turn red.

I added some simple tests which test Structures individually such as:

let mut assembler = Assembler::new(&REC_WIRE);
let p = &PosRelative::default();
assert!(assembler.input.is_empty());
assert_eq!(assembler.out, 0);
assert_eq!(assembler.cooldown, 0);
assert_eq!(assembler.recipe, Some(&REC_WIRE));

assert!(assembler.accepts(p, &Item::Material(Material::Plate(Plate::Copper))));
assert!(!assembler.accepts(p, &Item::Material(Material::Plate(Plate::Iron))));

assembler.accept(p, Item::Material(Material::Plate(Plate::Copper)));
assert!(!assembler.input.is_empty());
assert!(!assembler.accepts(p, &Item::Material(Material::Plate(Plate::Copper))));
assert_eq!(assembler.out, 0);

But also more complex ones that construct Blueprints from a collection of BlueprintActions and then simulate them. To then check both the consumed Items at Sources as well as the Items put into Targets.
These tests are more work than the Structure specific ones but cover a lot more code (building the Blueprint, the simulation in general and all involved Structures as well as their interactions).

fn source_to_target_long() {
    // long arm from source to target
    let duration = 1000;
    type B = BlueprintAction;
    let actions = vec![
        B::IncreaseWidth(5),
        B::IncreaseHeight(1),
        B::Add(
            PosAnchor(Pos { row: 0, col: 0 }),
            Structure::Source(Source::new(Material::Coal)),
        ),
        B::Add(
            PosAnchor(Pos { row: 0, col: 2 }),
            Structure::LongArm(LongArm::e()),
        ),
        B::Add(
            PosAnchor(Pos { row: 0, col: 4 }),
            Structure::Target(Target::default()),
        ),
    ];
    // expected data after simulation
    ...
        size: [5, 1],
        input: vec![(15, Item::Material(Material::Coal))],
        output: Some((15, Box::new(Item::Material(Material::Coal)))),
        duration,
    ...
}

But since the behavior of Structures and the Recipes are far from stable at the current point in time, I’ll keep writing such tests to a minimum.

To make life easier when writing tests I also added a Hole Structure which destroys any Items pushed into it, without keeping track of them.
Especially when testing the Splitter this was very useful since then the Items of one of the Splitter‘s output Belts could be destroyed entirely, ensuring that only half of the Items make it to the Targets.