Files
Pier_v1/tests/ground-inputs.test.ts
T
ypshimandClaude Haiku 5.5 16ab317094 feat(ground): 지반·지층 card inputs, layer rows, water level, section drawing
- types/ground.ts: 위치 (육상·하상·해상), 지하수위 고려 and EL, 지층 행
  (name and 하단 EL, from the top down). Checks G01 (layer order), G02 (water
  level range), G03 (layer name).
- The 지반고 still feeds the soil cover check; the layer rows and water level
  are inputs and do not change the 3D model.
- view/ground-svg.ts: the 삽도 drawn from the inputs and the generated
  footings and piles on one EL scale.
- 일괄 적용 copies 위치 and 지하수위 to the checked piers (속성 복사 item,
  off by default). Changes list shows arrays and booleans as text.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-26 10:11:42 +09:00

106 lines
4.7 KiB
TypeScript
Raw 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 { validateGround } from '../src/core/ground';
import { changedKeys } from '../src/core/changes';
import { COPY_ITEMS, applyCopy, planCopy } from '../src/core/copy';
import type { Issue, PierInput } from '../src/core/types';
import { groundSectionSvg } from '../src/view/ground-svg';
import { loadP1 } from './helpers';
const base = loadP1();
function withGround(extra: Partial<PierInput>): PierInput {
return { ...base, groundEl: 28.931, ...extra };
}
function ground(input: PierInput): string[] {
const issues: Issue[] = [];
validateGround(input, issues);
return issues.map((i) => i.code);
}
const GOOD_ROWS = [
{ name: '매립토', bottomEl: 27.5 },
{ name: '풍화토', bottomEl: 22 },
{ name: '연암', bottomEl: 10 },
];
describe('지반·지층 입력 검사 (G01–G03)', () => {
it('no issues for a well-ordered set of rows and a water level inside the range', () => {
expect(ground(withGround({ strataRows: GOOD_ROWS, groundWaterOn: true, groundWaterEl: 25 }))).toEqual([]);
});
it('G01: a layer whose bottom EL is not below the boundary above it', () => {
const rows = [{ name: '매립토', bottomEl: 27.5 }, { name: '풍화토', bottomEl: 28 }];
expect(ground(withGround({ strataRows: rows }))).toEqual(['G01']);
});
it('G01: the first layer must be below the ground EL', () => {
expect(ground(withGround({ strataRows: [{ name: '매립토', bottomEl: 29 }] }))).toEqual(['G01']);
});
it('G03: a layer name outside the strata list', () => {
expect(ground(withGround({ strataRows: [{ name: '점토', bottomEl: 27 }] }))).toEqual(['G03']);
});
it('G02: the water level above the ground, below the lowest layer, or missing while on', () => {
expect(ground(withGround({ strataRows: GOOD_ROWS, groundWaterOn: true, groundWaterEl: 29 }))).toEqual(['G02']);
expect(ground(withGround({ strataRows: GOOD_ROWS, groundWaterOn: true, groundWaterEl: 5 }))).toEqual(['G02']);
expect(ground(withGround({ groundWaterOn: true }))).toEqual(['G02']);
});
it('the water level is not checked when it is off', () => {
expect(ground(withGround({ strataRows: GOOD_ROWS, groundWaterOn: false, groundWaterEl: 99 }))).toEqual([]);
});
});
describe('일괄 적용 (속성 복사 · 위치·지하수위)', () => {
it('copies only the position and the water level, not the layer rows', () => {
const source = withGround({ groundPosition: '하상', groundWaterOn: true, groundWaterEl: 25, strataRows: GOOD_ROWS });
const target = withGround({ groundPosition: '육상', strataRows: [] });
const plan = planCopy(source, target, ['ground-position']);
expect(plan.changes.map((c) => c.key).sort()).toEqual(['groundPosition', 'groundWaterEl', 'groundWaterOn']);
const next = applyCopy(target, plan);
expect(next.groundPosition).toBe('하상');
expect(next.strataRows).toEqual([]);
});
it('the item is off by default, so the existing 속성 복사 defaults do not change', () => {
expect(COPY_ITEMS['ground-position'].defaultOn).toBe(false);
});
});
describe('변경 추적 (지반·지층 키)', () => {
it('a changed layer row or water level is reported as a change', () => {
const a = withGround({ strataRows: GOOD_ROWS });
const b = withGround({ strataRows: [...GOOD_ROWS, { name: '경암', bottomEl: 5 }] });
expect(changedKeys(a, b)).toEqual(['strataRows']);
expect(changedKeys(a, { ...a, groundWaterEl: 20 })).toEqual(['groundWaterEl']);
});
});
describe('단면 그림 (삽도)', () => {
const model = buildPier(base);
it('shows the ground EL and one band per layer row, with the 연암 top line', () => {
const svg = groundSectionSvg(withGround({ strataRows: GOOD_ROWS }), model);
expect(svg).toContain('지반고 28.931');
expect(svg).toContain('연암층 상면 EL 22.000');
expect((svg.match(/fill="#(EADFC8|DCCBA8|C9B38D)"/g) ?? []).length).toBeGreaterThanOrEqual(3);
});
it('draws the water level only when it is on and has a value', () => {
expect(groundSectionSvg(withGround({ strataRows: GOOD_ROWS, groundWaterOn: true, groundWaterEl: 25 }), model)).toContain('지하수위 25.000');
// The dashed water line and its label are absent (the aria-label always names 지하수위).
const off = groundSectionSvg(withGround({ strataRows: GOOD_ROWS, groundWaterOn: false, groundWaterEl: 25 }), model);
expect(off).not.toContain('stroke-dasharray="6 4"');
expect(off).not.toContain('지하수위 25');
});
it('with no layer rows, the ground band still fills the drawing down to its bottom', () => {
const svg = groundSectionSvg(withGround({}), model);
expect(svg).toContain('<svg');
expect(svg).toContain('지반고 28.931');
});
});