Zum Inhalt

tests/presets/storage.test.ts

// tests/presets/storage.test.ts
import { beforeEach, describe, expect, it, vi } from 'vitest';
import type { Preset } from '~/engine/types';
import { deleteCustomPreset, loadCustomPresets, saveCustomPreset } from '~/presets/storage';

const species = {
  color: [0.5, 0.5, 0.5] as const,
  populationShare: 0.33,
  sensorAngle: 0.5,
  sensorDistance: 24,
  turnSpeed: 0.4,
  moveSpeed: 1,
  depositAmount: 20,
};

const samplePreset: Preset = {
  id: 'custom-1',
  name: 'My Custom',
  builtIn: false,
  tags: ['test'],
  tagSignal: 'pearl',
  params: {
    agentCount: 1000,
    spawnPattern: 'random',
    species: [species, species, species],
    interactionMatrix: [
      [1, -0.6, -0.6],
      [-0.6, 1, -0.6],
      [-0.6, -0.6, 1],
    ],
    decayRate: 0.97,
    diffusionFreq: 3,
    fadeStrength: 0.1,
    trailSaturation: 255,
    chaosInterval: 0,
    chaosStrength: 0,
    rhythmAmplitude: 0.05,
    simSpeed: 1,
    blendMode: 'additive',
    backgroundColor: [0, 0, 0],
    headIntensity: 0,
    kaleidoscope: 0,
    exposure: 2.5,
    feedbackAmount: 0.2,
    bloomThreshold: 0.25,
    bloomIntensity: 0.9,
    vignette: 0.3,
    saturation: 1.1,
    contrast: 1.05,
    audioReactive: { enabled: false, gain: 1, autoGain: false, routes: [] },
  },
};

beforeEach(() => {
  const store = new Map<string, string>();
  vi.stubGlobal('localStorage', {
    getItem: (k: string) => store.get(k) ?? null,
    setItem: (k: string, v: string) => store.set(k, v),
    removeItem: (k: string) => store.delete(k),
    clear: () => store.clear(),
    key: () => null,
    length: 0,
  });
});

describe('storage', () => {
  it('save then load roundtrips', () => {
    saveCustomPreset(samplePreset);
    const loaded = loadCustomPresets();
    expect(loaded).toHaveLength(1);
    expect(loaded[0]?.id).toBe('custom-1');
  });

  it('delete removes', () => {
    saveCustomPreset(samplePreset);
    deleteCustomPreset('custom-1');
    expect(loadCustomPresets()).toHaveLength(0);
  });

  it('loadCustomPresets returns [] when storage empty', () => {
    expect(loadCustomPresets()).toEqual([]);
  });

  it('loadCustomPresets ignores invalid entries', () => {
    localStorage.setItem('physarum:presets:custom', '[{"invalid":true}]');
    expect(loadCustomPresets()).toEqual([]);
  });

  it('migrates a legacy single-species preset on load', () => {
    const legacy = {
      id: 'custom-old',
      name: 'Old One',
      builtIn: false,
      tags: ['x'],
      tagSignal: 'pearl',
      params: {
        agentCount: 5000,
        sensorAngle: 0.5,
        sensorDistance: 10,
        turnSpeed: 0.4,
        moveSpeed: 1,
        evaporationRate: 0.05,
        diffusionRate: 0.5,
        depositAmount: 0.5,
        trailColor: [0.5, 0.5, 0.5],
        backgroundColor: [0, 0, 0],
        exposure: 2.5,
        audioReactive: { enabled: false, gain: 1, autoGain: false, routes: [] },
      },
    };
    localStorage.setItem('physarum:presets:custom', JSON.stringify([legacy]));
    const loaded = loadCustomPresets();
    expect(loaded).toHaveLength(1);
    const p = loaded[0];
    expect(p?.params.species[0]?.populationShare).toBe(1);
    expect(p?.params.species[1]?.populationShare).toBe(0);
    expect(p?.params.spawnPattern).toBe('random');
  });
});