Files
Pier_v1/tests/piles.test.ts
ypshimandClaude Haiku 5.5 17b5b24682 feat(core,view): per-row pile counts 열별 본수 (plan C4)
- A 열 is one row across the footing width; each has its own count along the
  length. Default floor((L − 1400) / 2250) + 1 per 열, as in spec §4.6.
- Counts are validated: one per 열, whole numbers 2–30. Spacing below the
  2250 mm minimum is shown as a warning, not refused (the plan's 6본 → 5@1800
  example).
- PierInput gains an optional pileRows; absent means the defaults, so existing
  files and the P1 results are unchanged.
- Change tracking compares arrays by value; 열별 본수 can be reverted and
  copied (copy item off by default).
- The footing card has −/+ per 열 with spacing, total, and the display string.
- Tests: defaults 4열 × 5본 = 20 and the 1단계 text; 6본 → 5@1800; limits;
  model-level 21 piles.
- Not verified in a browser.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-22 10:34:39 +09:00

65 lines
2.9 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it } from 'vitest';
import { buildPier } from '../src/core/geometry';
import { loadP1 } from './helpers';
import { adjustRow, defaultRowCounts, layoutText, maxCount, resolveRowCounts, rowLayout, totalPiles, type PileGeometry } from '../src/core/piles';
// Footing 10400 × 8150, pile end 700, minimum centre spacing 2250 (spec §4.6, §3).
const G: PileGeometry = { footingLength: 10.4, footingWidth: 8.15, end: 0.7, minSpacing: 2.25 };
describe('말뚝 열별 본수 (spec §4.6, plan C4)', () => {
it('defaults give 4 열 × 5 본 = 20 for the P1 footing, and the 1단계 text is kept', () => {
expect(defaultRowCounts(G)).toEqual([5, 5, 5, 5]);
expect(totalPiles(defaultRowCounts(G))).toBe(20);
expect(layoutText(defaultRowCounts(G), G)).toBe('4@2250 × 3@2250 = 20본');
});
it('a 열 with 6 본 gives 5 gaps at 1800 mm, as in the plan (warning, not refused)', () => {
const counts = adjustRow(defaultRowCounts(G), 0, 1);
expect(counts[0]).toBe(6);
const layout = rowLayout(counts, G);
expect(Math.round(layout[0].spacing * 1000)).toBe(1800);
expect(layout[0].belowMinimum).toBe(true);
expect(layout[1].belowMinimum).toBe(false);
expect(layoutText(counts, G)).toBe('열1 5@1800 · 열2 4@2250 · 열3 4@2250 · 열4 4@2250 = 21본');
});
it('the total follows the counts: − and + change it by one per 열', () => {
expect(totalPiles(adjustRow(defaultRowCounts(G), 2, -1))).toBe(19);
expect(totalPiles(adjustRow(defaultRowCounts(G), 2, 1))).toBe(21);
});
it('counts are kept within the limits when adjusting', () => {
expect(adjustRow([2, 2, 2, 2], 0, -1)[0]).toBe(2);
expect(adjustRow([30, 2, 2, 2], 0, 1)[0]).toBe(30);
});
it('refuses a wrong number of 열 and a count that is not a whole number in range', () => {
expect(() => resolveRowCounts([5, 5, 5], G)).toThrow('4개여야');
expect(() => resolveRowCounts([5, 5, 1, 5], G)).toThrow('2–30');
expect(() => resolveRowCounts([5, 5, 5.5, 5], G)).toThrow('정수');
expect(resolveRowCounts([6, 5, 5, 5], G)).toEqual([6, 5, 5, 5]);
});
it('the default count matches the spec formula floor((L − 1400) / 2250) + 1', () => {
expect(maxCount(10.4, G)).toBe(5);
expect(maxCount(17.6, G)).toBe(8);
});
});
describe('열별 본수 in the model (spec §4.6)', () => {
it('buildPier uses the per-row counts: 6 + 5 + 5 + 5 = 21 piles, and the text follows', () => {
const p1 = loadP1();
const m = buildPier({ ...p1, pileRows: [6, 5, 5, 5] });
expect(m.piles).toHaveLength(21);
expect(m.derived.pileLayout).toBe('열1 5@1800 · 열2 4@2250 · 열3 4@2250 · 열4 4@2250 = 21본');
});
it('absent 열별 본수 gives the 1단계 result: 20 piles', () => {
expect(buildPier(loadP1()).piles).toHaveLength(20);
});
it('a wrong number of 열 is refused by buildPier', () => {
expect(() => buildPier({ ...loadP1(), pileRows: [5, 5, 5] })).toThrow('4개여야');
});
});