lantern

sprout-garden-phase-7-test

Test: Sprout Garden Phase 7

Following [[pattern-looking-glass-development]] - the tests ARE the documentation.

Subject

Phase 7 plot types: filter, counter, basket, recipe-pot (aggregation and synthesis)

config

path: null
plots_dir: /Users/graemefawcett/working/ben.fawcett.family/activities/sprout-garden/src/plots/types

Spec

Test: Filter Passes Matching Sprouts

describe('Filter', () => {
  it('passes sprouts matching criteria', () => {
    const filter = createFilter({ color: 'red' });
    const sprout = { shape: 'circle', color: 'red' };
    
    expect(filter.shouldPass(sprout)).toBe(true);
  });
  
  it('blocks sprouts not matching criteria', () => {
    const filter = createFilter({ color: 'red' });
    const sprout = { shape: 'circle', color: 'blue' };
    
    expect(filter.shouldPass(sprout)).toBe(false);
  });
  
  it('can filter by shape', () => {
    const filter = createFilter({ shape: 'star' });
    
    expect(filter.shouldPass({ shape: 'star', color: 'red' })).toBe(true);
    expect(filter.shouldPass({ shape: 'circle', color: 'red' })).toBe(false);
  });
  
  it('can filter by multiple properties', () => {
    const filter = createFilter({ shape: 'star', color: 'red' });
    
    expect(filter.shouldPass({ shape: 'star', color: 'red' })).toBe(true);
    expect(filter.shouldPass({ shape: 'star', color: 'blue' })).toBe(false);
    expect(filter.shouldPass({ shape: 'circle', color: 'red' })).toBe(false);
  });
  
  it('grow() returns null for blocked sprouts', () => {
    const filter = createFilter({ color: 'red' });
    const sprout = { shape: 'circle', color: 'blue' };
    
    expect(filter.grow(sprout)).toBeNull();
  });
});

Test: Counter Counts Sprouts

describe('Counter', () => {
  it('increments count on each sprout', () => {
    const counter = createCounter();
    
    counter.receive({ shape: 'circle', color: 'red' });
    expect(counter.count).toBe(1);
    
    counter.receive({ shape: 'square', color: 'blue' });
    expect(counter.count).toBe(2);
  });
  
  it('outputs count in continuous mode', () => {
    const counter = createCounter({ outputMode: 'continuous' });
    
    const result1 = counter.receive({ shape: 'circle', color: 'red' });
    expect(result1.count).toBe(1);
    
    const result2 = counter.receive({ shape: 'square', color: 'blue' });
    expect(result2.count).toBe(2);
  });
  
  it('can reset count', () => {
    const counter = createCounter();
    counter.receive({ shape: 'circle', color: 'red' });
    counter.receive({ shape: 'square', color: 'blue' });
    
    counter.reset();
    
    expect(counter.count).toBe(0);
  });
});

Test: Basket Collects Then Releases

describe('Basket', () => {
  it('holds sprouts until capacity reached', () => {
    const basket = createBasket({ capacity: 3 });
    
    basket.receive({ shape: 'circle', color: 'red' });
    expect(basket.shouldRelease()).toBe(false);
    
    basket.receive({ shape: 'square', color: 'blue' });
    expect(basket.shouldRelease()).toBe(false);
    
    basket.receive({ shape: 'triangle', color: 'green' });
    expect(basket.shouldRelease()).toBe(true);
  });
  
  it('releases all sprouts when full', () => {
    const basket = createBasket({ capacity: 3, releaseMode: 'all' });
    
    basket.receive({ shape: 'circle', color: 'red' });
    basket.receive({ shape: 'square', color: 'blue' });
    basket.receive({ shape: 'triangle', color: 'green' });
    
    const released = basket.release();
    
    expect(released.length).toBe(3);
  });
  
  it('empties after release', () => {
    const basket = createBasket({ capacity: 2 });
    
    basket.receive({ shape: 'circle', color: 'red' });
    basket.receive({ shape: 'square', color: 'blue' });
    basket.release();
    
    expect(basket.collected.length).toBe(0);
    expect(basket.shouldRelease()).toBe(false);
  });
});

Test: Recipe Pot Synthesizes

describe('Recipe Pot', () => {
  const carRecipe = {
    requires: [
      { shape: 'star', color: 'red', count: 4 },
      { shape: 'square', color: 'blue', count: 1 }
    ],
    produces: { shape: 'car', color: 'red' }
  };
  
  it('collects ingredients', () => {
    const pot = createRecipePot(carRecipe);
    
    pot.receive({ shape: 'star', color: 'red' });
    
    expect(pot.collected.length).toBe(1);
  });
  
  it('detects when recipe is complete', () => {
    const pot = createRecipePot(carRecipe);
    
    // Add 4 red stars
    for (let i = 0; i < 4; i++) {
      pot.receive({ shape: 'star', color: 'red' });
    }
    expect(pot.isComplete()).toBe(false);
    
    // Add 1 blue square
    pot.receive({ shape: 'square', color: 'blue' });
    expect(pot.isComplete()).toBe(true);
  });
  
  it('produces output when complete', () => {
    const pot = createRecipePot(carRecipe);
    
    for (let i = 0; i < 4; i++) {
      pot.receive({ shape: 'star', color: 'red' });
    }
    pot.receive({ shape: 'square', color: 'blue' });
    
    const product = pot.synthesize();
    
    expect(product.shape).toBe('car');
    expect(product.color).toBe('red');
  });
  
  it('clears collected after synthesis', () => {
    const pot = createRecipePot(carRecipe);
    
    for (let i = 0; i < 4; i++) {
      pot.receive({ shape: 'star', color: 'red' });
    }
    pot.receive({ shape: 'square', color: 'blue' });
    pot.synthesize();
    
    expect(pot.collected.length).toBe(0);
  });
  
  it('rejects wrong ingredients', () => {
    const pot = createRecipePot(carRecipe);
    
    // Recipe needs red stars and blue square
    // Green circle is not needed
    const accepted = pot.receive({ shape: 'circle', color: 'green' });
    
    expect(accepted).toBe(false);
    expect(pot.collected.length).toBe(0);
  });
});

Test: Factory Pipeline

describe('Factory Pipeline', () => {
  it('filters then counts', () => {
    // spring (mixed) → filter (red only) → counter
    const sim = new Simulation(filterCountGarden);
    sim.run();
    
    const counter = sim.getPlotState('counter');
    expect(counter.count).toBe(3); // Only red sprouts counted
  });
  
  it('continuous production works', () => {
    // continuous spring → transformer → recipe pot → harvest
    const sim = new Simulation(factoryGarden);
    sim.run(100);
    
    const harvested = sim.sprouts.filter(s => s.status === 'arrived');
    expect(harvested.length).toBeGreaterThan(0);
    expect(harvested[0].shape).toBe('car');
  });
});

Results

{
  "summary": "0/5 tests passing",
  "phase": "Phase 7: Harvests & Recipes",
  "status": "not yet implemented",
  "tests": [
    {
      "test": "filter.js exists",
      "status": "fail",
      "details": "not yet implemented"
    },
    {
      "test": "counter.js exists",
      "status": "fail",
      "details": "not yet implemented"
    },
    {
      "test": "basket.js exists",
      "status": "fail",
      "details": "not yet implemented"
    },
    {
      "test": "recipe-pot.js exists",
      "status": "fail",
      "details": "not yet implemented"
    },
    {
      "test": "recipes.js exists",
      "status": "fail",
      "details": "not yet implemented"
    }
  ]
}

Provenance

Fences

test-filter

  • Status: Spec only (Phase 7 not implemented)
  • By: Claude (2025-11-29)
  • Note: Filter behavior specification

test-counter

  • Status: Spec only
  • By: Claude (2025-11-29)
  • Note: Counter behavior specification

test-basket

  • Status: Spec only
  • By: Claude (2025-11-29)
  • Note: Basket collection specification

test-recipe-pot

  • Status: Spec only
  • By: Claude (2025-11-29)
  • Note: Recipe synthesis specification

test-factory-pipeline

  • Status: Spec only
  • By: Claude (2025-11-29)
  • Note: Integration test for full pipeline

sprout-garden-phase-7-results

  • Status: Verified (checks for implementation)
  • By: Claude (2025-11-29)
  • Note: Reports Phase 7 implementation status

Slots

North

slots:
- sprout-garden-phase-7

South

slots: []

East

slots: []

West

slots:
- pattern-looking-glass-development