Files
Pier_v1/tests/ground-model.test.ts
T
ypshimandClaude Haiku 5.5 c3606011b5 feat(ground): load ground_model.json and apply the pier-centre ground EL
- ground-model.ts: read and check schema 1 of the Python ground model.
- ② 지반·지층 card: import the json, show the DTM value beside the excel
  value, and apply it only when the user presses the button (tracked as an
  override, revertible).
- groundEl becomes an editable, tracked input; the project file keeps the
  imported model and checks it on open.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-23 16:48:27 +09:00

87 lines
3.6 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { groundElFor, parseGroundModel } from '../src/core/ground-model';
import { changedKeys, overrideKeys, revertDraft, type PierValues } from '../src/core/changes';
import { parseProject, serializeProject, SCHEMA_VERSION, type ProjectFile } from '../src/core/project';
import { loadP1 } from './helpers';
/** The shape written by RAG/pierzainer_ground (schema 1). */
const SAMPLE = JSON.stringify({
schema: 1,
generated: '2026-10-23',
coord: '측량 X(북) · Y(동), m. 치수 mm',
piers: [
{ id: 'P1', ground: { center: 29.355, excel: 28.931, used: 29.355, source: '계산' }, footing: { cover: 0.972 } },
{ id: 'P2', ground: { center: null, excel: null, used: null, source: '없음' } },
],
});
describe('지반 모델 읽기 (ground_model.json, schema 1)', () => {
it('reads the pier-centre ground EL and the excel value', () => {
const m = parseGroundModel(SAMPLE);
expect(m.piers[0]).toEqual({ id: 'P1', centerEl: 29.355, excelEl: 28.931 });
expect(groundElFor(m, 'P1')).toBe(29.355);
});
it('a pier outside the terrain has no value, and an unknown pier has none either', () => {
const m = parseGroundModel(SAMPLE);
expect(groundElFor(m, 'P2')).toBeUndefined();
expect(groundElFor(m, 'P9')).toBeUndefined();
});
it('refuses another schema number instead of guessing the layout', () => {
expect(() => parseGroundModel(SAMPLE.replace('"schema":1', '"schema":2'))).toThrow('형식 번호 2');
});
it('refuses a file without a pier list or without pier names', () => {
expect(() => parseGroundModel('{"schema": 1}')).toThrow('교각 목록');
expect(() => parseGroundModel('{"schema": 1, "piers": [{"ground": {}}]}')).toThrow('이름(id)');
});
it('refuses text that is not JSON', () => {
expect(() => parseGroundModel('not json')).toThrow('JSON으로 읽히지 않습니다');
});
});
describe('지반고 적용 (사용자가 누를 때만, 변경으로 기록)', () => {
const base = loadP1();
const pier: PierValues = { defaults: base, input: base, draft: { ...base, groundEl: 29.355 } };
it('an applied value counts as an override and can be reverted to the excel value', () => {
expect(overrideKeys(pier)).toContain('groundEl');
expect(revertDraft(pier, 'groundEl').groundEl).toBe(base.groundEl);
});
it('the draft and the generated input are compared, so the change waits for regeneration', () => {
expect(changedKeys(pier.input, pier.draft)).toEqual(['groundEl']);
});
});
describe('프로젝트 파일의 지반 모델', () => {
function project(extra: Partial<ProjectFile>): ProjectFile {
const p1 = loadP1();
return {
schemaVersion: SCHEMA_VERSION,
project: { name: 'x', bridge: '운곡교', client: '', author: '', crs: 'KATEC', memo: '' },
source: { fileName: 'x.xlsx', sheets: [] },
piers: [{ id: 'P1', input: p1 }],
history: [],
...extra,
};
}
it('keeps the imported ground model across save and open', () => {
const m = parseGroundModel(SAMPLE);
const reopened = parseProject(serializeProject(project({ groundModel: m })));
expect(reopened.groundModel).toEqual(m);
});
it('refuses a damaged ground model inside the project file', () => {
const text = serializeProject(project({})).replace('"history": []', '"history": [], "groundModel": {"schema": 1}');
expect(() => parseProject(text)).toThrow('교각 목록');
});
it('opens an older file that has no ground model', () => {
expect(parseProject(serializeProject(project({}))).groundModel).toBeUndefined();
});
});