From 0e70cfb969b07071b0df8cef44f8f72f9147f37b Mon Sep 17 00:00:00 2001 From: ypshim Date: Fri, 23 Oct 2026 18:09:50 +0900 Subject: [PATCH] refactor(ground): remove the unversioned-file fallback - A file without a schema number is refused again; the example output in RAG/pierzainer_ground now has schema 2, so the temporary path is not needed. - The legacy fixture is removed; tests cover the missing and null schema numbers and a pier without a ground object. Co-Authored-By: Claude Haiku 5.5 --- src/core/ground-model.ts | 9 +- tests/fixtures/ground-model-legacy.json | 393 ------------------------ tests/ground-model.test.ts | 24 +- 3 files changed, 9 insertions(+), 417 deletions(-) delete mode 100644 tests/fixtures/ground-model-legacy.json diff --git a/src/core/ground-model.ts b/src/core/ground-model.ts index 2780f23..1a4c980 100644 --- a/src/core/ground-model.ts +++ b/src/core/ground-model.ts @@ -37,16 +37,11 @@ function numOrNull(v: unknown): number | null { return typeof v === 'number' && Number.isFinite(v) ? v : null; } -/** - * Checks the shape of a parsed ground_model.json. Throws with the first problem named in Korean. - * A file with no `schema` key is the layout written before the number was added: it is read as schema 1, and the - * `ground` object is required so that a renamed field is refused instead of loading as empty values. - * TODO: remove the no-schema branch once the 옛 파일 (examples/out) is regenerated with schema 1. - */ +/** Checks the shape of a parsed ground_model.json. Throws with the first problem named in Korean. */ export function checkGroundModel(raw: unknown): GroundModelFile { const obj = raw as Partial | null; if (!obj || typeof obj !== 'object') throw new Error('지반 모델 파일 형식이 아닙니다.'); - if (obj.schema !== undefined && !READABLE_SCHEMAS.includes(obj.schema)) { + if (!READABLE_SCHEMAS.includes(obj.schema as number)) { throw new Error(`지반 모델 형식 번호 ${String(obj.schema)}을(를) 읽을 수 없습니다 (지원: ${READABLE_SCHEMAS.join(', ')}).`); } if (!Array.isArray(obj.piers)) throw new Error('지반 모델 파일에 교각 목록(piers)이 없습니다.'); diff --git a/tests/fixtures/ground-model-legacy.json b/tests/fixtures/ground-model-legacy.json deleted file mode 100644 index d489ead..0000000 --- a/tests/fixtures/ground-model-legacy.json +++ /dev/null @@ -1,393 +0,0 @@ -{ - "generated": "2026-10-23", - "coord": "측량 X(북) · Y(동), m. 치수 mm", - "terrain": { - "file": "C0050202-001.dxf", - "spot_blocks": 433, - "spot_texts": 190, - "contours": 67, - "line3d_vertices": 0, - "points_used": 3429, - "by_source": { - "spot": 431, - "text": 5, - "contour": 2993, - "line3d": 0 - }, - "removed": 1, - "boreholes": 18, - "extent": [ - 259779.6342279386, - 179066.3432863709, - 260208.0132279157, - 179261.3784074617 - ] - }, - "removed_points": [ - { - "X": 260155.762358268, - "Y": 179189.228890184, - "Z": -18.115, - "source": "spot", - "reason": "EL 범위 밖 (0.0–200.0)" - } - ], - "boreholes_dxf": [ - { - "id": "BB-24", - "X": 260110.5200305235, - "Y": 179142.87077588285 - }, - { - "id": "BB-28", - "X": 259832.7395636612, - "Y": 179078.6772609205 - }, - { - "id": "NBB-21", - "X": 260169.7415555437, - "Y": 179217.2592038325 - }, - { - "id": "NBB-22", - "X": 260119.0843895569, - "Y": 179207.447663092 - }, - { - "id": "NBB-23", - "X": 260063.7209158014, - "Y": 179200.7170868495 - }, - { - "id": "NBB-24", - "X": 260013.7365954409, - "Y": 179193.2691158374 - }, - { - "id": "NBB-25", - "X": 259959.8230206913, - "Y": 179182.585023065 - }, - { - "id": "NBB-26", - "X": 259908.1691879086, - "Y": 179170.4141072329 - }, - { - "id": "NBB-27", - "X": 259862.0303893618, - "Y": 179162.6491102049 - }, - { - "id": "NBB-28", - "X": 259804.6978413376, - "Y": 179143.6022597326 - }, - { - "id": "NBB-29", - "X": 260162.3349768046, - "Y": 179177.2095564581 - }, - { - "id": "NBB-30", - "X": 260115.11201831407, - "Y": 179163.3224655297 - }, - { - "id": "NBB-31", - "X": 260052.92384203407, - "Y": 179154.4466218247 - }, - { - "id": "NBB-32", - "X": 260004.4464295526, - "Y": 179155.3905176037 - }, - { - "id": "NBB-33", - "X": 259953.9248062317, - "Y": 179147.6435384383 - }, - { - "id": "NBB-34", - "X": 259903.7958026133, - "Y": 179135.2767765673 - }, - { - "id": "NBB-35", - "X": 259855.9217242609, - "Y": 179124.5131579286 - }, - { - "id": "NBB-36", - "X": 259804.9274191266, - "Y": 179111.1866481418 - } - ], - "borehole_issues": [], - "piers": [ - { - "id": "P1", - "X": 259865.676, - "Y": 179138.094, - "axis_dir": [ - 0.16722, - -0.98592 - ], - "ground": { - "center": 29.355, - "corners": [ - 29.536, - 29.441, - 29.18, - 29.27 - ], - "min": 29.18, - "max": 29.536, - "used": 29.355, - "source": "계산", - "dtm_spacing": 19.0, - "excel": 28.931, - "diff_vs_excel": 0.424 - }, - "footing": { - "L_mm": 10400.0, - "W_mm": 8150.0, - "top_el": 28.208, - "bottom_el": 26.208, - "cover": 0.972 - }, - "pile": { - "tip_el": 2.208, - "d_mm": 609.6 - }, - "soil": null, - "alerts": [ - { - "code": "W09", - "level": "경고", - "pier": "P1", - "message": "엑셀 지반고 28.931와 지형 29.355의 차이 +0.424 m가 허용 0.3 m를 넘습니다." - }, - { - "code": "I05", - "level": "정보", - "pier": "P1", - "message": "시추 자료가 없어 지층을 판정하지 않았습니다." - } - ] - }, - { - "id": "P2", - "X": 259914.439, - "Y": 179149.112, - "axis_dir": [ - 0.167151, - -0.985931 - ], - "ground": { - "center": 28.167, - "corners": [], - "min": 28.167, - "max": 28.167, - "used": 28.167, - "source": "계산", - "dtm_spacing": 19.5, - "excel": null, - "diff_vs_excel": null - }, - "footing": { - "L_mm": null, - "W_mm": null, - "top_el": null, - "bottom_el": null, - "cover": null - }, - "pile": { - "tip_el": null, - "d_mm": null - }, - "soil": null, - "alerts": [ - { - "code": "I05", - "level": "정보", - "pier": "P2", - "message": "시추 자료가 없어 지층을 판정하지 않았습니다." - } - ] - }, - { - "id": "P3", - "X": 259963.44, - "Y": 179159.017, - "axis_dir": [ - 0.167117, - -0.985937 - ], - "ground": { - "center": 28.12, - "corners": [], - "min": 28.12, - "max": 28.12, - "used": 28.12, - "source": "계산", - "dtm_spacing": 48.6, - "excel": null, - "diff_vs_excel": null - }, - "footing": { - "L_mm": null, - "W_mm": null, - "top_el": null, - "bottom_el": null, - "cover": null - }, - "pile": { - "tip_el": null, - "d_mm": null - }, - "soil": null, - "alerts": [ - { - "code": "I07", - "level": "정보", - "pier": "P3", - "message": "지반고를 만든 지형 점이 최대 48.6 m 떨어져 있습니다 (기준 30 m). 현장 측량값을 확인하세요." - }, - { - "code": "I05", - "level": "정보", - "pier": "P3", - "message": "시추 자료가 없어 지층을 판정하지 않았습니다." - } - ] - }, - { - "id": "P4", - "X": 260012.654, - "Y": 179167.802, - "axis_dir": [ - 0.167117, - -0.985937 - ], - "ground": { - "center": 28.608, - "corners": [], - "min": 28.608, - "max": 28.608, - "used": 28.608, - "source": "계산", - "dtm_spacing": 44.3, - "excel": null, - "diff_vs_excel": null - }, - "footing": { - "L_mm": null, - "W_mm": null, - "top_el": null, - "bottom_el": null, - "cover": null - }, - "pile": { - "tip_el": null, - "d_mm": null - }, - "soil": null, - "alerts": [ - { - "code": "I07", - "level": "정보", - "pier": "P4", - "message": "지반고를 만든 지형 점이 최대 44.3 m 떨어져 있습니다 (기준 30 m). 현장 측량값을 확인하세요." - }, - { - "code": "I05", - "level": "정보", - "pier": "P4", - "message": "시추 자료가 없어 지층을 판정하지 않았습니다." - } - ] - }, - { - "id": "P5", - "X": 260062.055, - "Y": 179175.464, - "axis_dir": [ - 0.1671, - -0.98594 - ], - "ground": { - "center": 27.242, - "corners": [], - "min": 27.242, - "max": 27.242, - "used": 27.242, - "source": "계산", - "dtm_spacing": 2.7, - "excel": null, - "diff_vs_excel": null - }, - "footing": { - "L_mm": null, - "W_mm": null, - "top_el": null, - "bottom_el": null, - "cover": null - }, - "pile": { - "tip_el": null, - "d_mm": null - }, - "soil": null, - "alerts": [ - { - "code": "I05", - "level": "정보", - "pier": "P5", - "message": "시추 자료가 없어 지층을 판정하지 않았습니다." - } - ] - }, - { - "id": "P6", - "X": 260116.582, - "Y": 179182.59, - "axis_dir": [ - 0.167062, - -0.985946 - ], - "ground": { - "center": 28.766, - "corners": [], - "min": 28.766, - "max": 28.766, - "used": 28.766, - "source": "계산", - "dtm_spacing": 14.3, - "excel": null, - "diff_vs_excel": null - }, - "footing": { - "L_mm": null, - "W_mm": null, - "top_el": null, - "bottom_el": null, - "cover": null - }, - "pile": { - "tip_el": null, - "d_mm": null - }, - "soil": null, - "alerts": [ - { - "code": "I05", - "level": "정보", - "pier": "P6", - "message": "시추 자료가 없어 지층을 판정하지 않았습니다." - } - ] - } - ] -} \ No newline at end of file diff --git a/tests/ground-model.test.ts b/tests/ground-model.test.ts index a75b337..9bb73b0 100644 --- a/tests/ground-model.test.ts +++ b/tests/ground-model.test.ts @@ -1,4 +1,3 @@ -import { readFileSync } from 'node:fs'; import { describe, expect, it } from 'vitest'; import { groundElFor, parseGroundModel } from '../src/core/ground-model'; import { changedKeys, overrideKeys, revertDraft, type PierValues } from '../src/core/changes'; @@ -89,26 +88,17 @@ describe('지형 격자 (schema 2)', () => { }); }); -describe('번호 없는 옛 지반 모델 (B′: 임시 경로)', () => { - // examples/out/ground_model.json as written before the schema number existed (P1–P6, same values as the report). - const LEGACY = readFileSync(new URL('./fixtures/ground-model-legacy.json', import.meta.url), 'utf-8'); - - it('reads the unversioned file and reports it as schema 1', () => { - const m = parseGroundModel(LEGACY); - expect(m.schema).toBe(2); // normalised to the current schema - expect(m.piers.map((p) => p.id)).toEqual(['P1', 'P2', 'P3', 'P4', 'P5', 'P6']); - expect(groundElFor(m, 'P1')).toBe(29.355); - expect(m.piers[0].excelEl).toBe(28.931); +describe('형식 번호 검사', () => { + it('refuses a file with no schema number (the B′ fallback is removed)', () => { + expect(() => parseGroundModel(JSON.stringify({ piers: [{ id: 'P1', ground: { center: 29.355, excel: 28.931 } }] }))).toThrow('형식 번호 undefined'); }); - it('refuses a pier that has no ground object (a renamed field must not load as empty values)', () => { - const data = JSON.parse(LEGACY); - delete data.piers[1].ground; - expect(() => parseGroundModel(JSON.stringify(data))).toThrow('P2: 지반 값(ground)이 없습니다'); + it('refuses a null schema number', () => { + expect(() => parseGroundModel('{"schema": null, "piers": []}')).toThrow('형식 번호 null'); }); - it('refuses a null schema number instead of treating it as missing', () => { - expect(() => parseGroundModel(LEGACY.replace('{', '{"schema": null,'))).toThrow('형식 번호 null'); + it('refuses a pier that has no ground object', () => { + expect(() => parseGroundModel(JSON.stringify({ schema: 1, piers: [{ id: 'P2' }] }))).toThrow('P2: 지반 값(ground)이 없습니다'); }); });