Files
Pier_v1/tests/ground-inputs.test.ts
T
ypshimandClaude Haiku 5.5 325c841733 feat(ground): pile-tip embedment check and soil layers from the ground model
- ground.ts: G04 when a pile tip is above the 연암 상면 minus 1.0 × D; G05
  (info) when layers are entered but there is no 연암 row. No message while
  no layers are entered at all.
- ground-model.ts: reads the Python soil.layers as strata rows; the project
  file keeps and checks them.
- ② card: a button fills the layer rows from the ground model for the pier.

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

138 lines
6.1 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, validatePileEmbedment } 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');
});
});
describe('말뚝 선단 근입 (G04·G05)', () => {
// P1 model: pile tips at about EL 2.2 m, D 0.6096 m, so the limit is the 연암 top minus 0.6096.
const model = buildPier(base);
const deepest = Math.max(...model.piles.map((p) => p.bottom));
function embed(input: PierInput): string[] {
const issues: Issue[] = [];
validatePileEmbedment(input, model, issues);
return issues.map((i) => i.code);
}
it('no check and no message when no layers are entered yet', () => {
expect(embed(withGround({}))).toEqual([]);
});
it('G04: a pile tip above the 연암 top minus the embedment', () => {
// 연암 top = the 매립토 bottom 2.5 m, so the limit is 2.5 − 0.6096 = 1.89 m, above the tips at 2.2 m.
expect(deepest).toBeGreaterThan(2.5 - 0.6096);
const rows = [{ name: '매립토', bottomEl: 2.5 }, { name: '연암', bottomEl: 1 }];
expect(embed(withGround({ strataRows: rows }))).toEqual(['G04']);
});
it('no G04 when the 연암 top is high enough above the tips', () => {
const rows = [{ name: '매립토', bottomEl: 20 }, { name: '연암', bottomEl: 10 }];
expect(embed(withGround({ strataRows: rows }))).toEqual([]);
});
it('G05 (info): layers entered but no 연암 row, so the embedment is not checked', () => {
expect(embed(withGround({ strataRows: [{ name: '풍화토', bottomEl: 20 }] }))).toEqual(['G05']);
});
});