import { readFileSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import * as XLSX from 'xlsx'; import { describe, expect, it } from 'vitest'; import { buildAbut } from '../src/core/abut/geometry'; import { parseAbutments, toAbutInput, type AbutRecord } from '../src/core/abut/parse'; import { buildMembers } from '../src/core/abut/members'; import { setAbutGround } from '../src/core/abut/edit'; import { abutGroundChanged, abutGroundIssues, supportTopEl } from '../src/core/abut/ground'; import { abutMemberRows } from '../src/core/abut/member-list'; import { checkStoredAbutments } from '../src/core/project'; import { abutGroundSectionSvg } from '../src/view/ground-svg'; const RAG = fileURLToPath(new URL('../../../RAG/운곡교P1입력.xlsx', import.meta.url)); const rec = parseAbutments(XLSX.read(readFileSync(RAG), { type: 'buffer' })).abutments[0]; const membersOf = (r: AbutRecord) => buildMembers(buildAbut(toAbutInput(r)), { bottomEl: r.foundationBottomEl, pileLengthMm: r.pileLengthMm }, r.shape); const codes = (r: AbutRecord) => abutGroundIssues(r, membersOf(r)).map((i) => i.code); // A1: 지반고 33.984, 기초 하단 40.895, 말뚝 선단 19.295 (spec_abut §12). const rows = [ { name: '퇴적토', bottomEl: 30 }, { name: '풍화암', bottomEl: 22 }, { name: '연암', bottomEl: 10 }, ]; describe('교대 지반·지층 (2026-11-04, 교각 카드와 같은 입력)', () => { it('defaults: 육상, no water, no rows; only AI01 (지반고 below the 저판 하면) is reported', () => { expect(codes(rec)).toEqual(['AI01']); expect(abutGroundIssues(rec, membersOf(rec))[0].message).toContain('6.911'); expect(abutGroundChanged(rec.ground)).toBe(false); }); it('the pier checks apply: G01 order, G02 water, G07 DHWL, G13 sea, G04 pile embedment into the 연암', () => { expect(codes(setAbutGround(rec, { strataRows: [{ name: '퇴적토', bottomEl: 35 }] }))).toContain('G01'); expect(codes(setAbutGround(rec, { groundWaterOn: true }))).toContain('G02'); expect(codes(setAbutGround(rec, { groundPosition: '하상' }))).toContain('G07'); expect(codes(setAbutGround(rec, { groundPosition: '해상' }))).toContain('G13'); // 연암 상면 22.000 − 1.0 × 0.6 = 21.4; the tip 19.295 is deep enough. expect(codes(setAbutGround(rec, { strataRows: rows }))).toEqual(['AI01']); const shallow = setAbutGround(rec, { strataRows: [{ name: '풍화암', bottomEl: 19.5 }, { name: '연암', bottomEl: 10 }] }); expect(codes(shallow)).toContain('G04'); expect(supportTopEl(rec.groundEl, rows)).toBe(22); expect(supportTopEl(rec.groundEl, [{ name: '퇴적토', bottomEl: 30 }])).toBeUndefined(); }); it('set: merges values, removes undefined, refuses non-numbers; the member row follows', () => { const a = setAbutGround(rec, { groundPosition: '하상', floodLevelEl: 36 }); expect(setAbutGround(a, { floodLevelEl: undefined }).ground).toEqual({ groundPosition: '하상' }); expect(() => setAbutGround(rec, { groundWaterEl: Number.NaN })).toThrow('숫자'); const row = abutMemberRows(setAbutGround(rec, { strataRows: rows }), '—').find((r) => r.id === 'ground')!; expect(row.summary).toBe('육상 · 지층 3 · 지반고 EL.33.984'); expect(row.changed).toBe(true); }); it('the project file keeps the 지반 values and refuses wrong ones', () => { expect(() => checkStoredAbutments([setAbutGround(rec, { groundPosition: '해상', highWaterEl: 35, strataRows: rows })])).not.toThrow(); expect(() => checkStoredAbutments([{ ...rec, ground: { groundPosition: '산지' } as never }])).toThrow('지반'); expect(() => checkStoredAbutments([{ ...rec, ground: { strataRows: [{ name: '연암', bottomEl: 'x' }] } as never }])).toThrow('지반'); }); it('삽도: layers, water and the abutment section with EL. labels', () => { const m = membersOf(rec); const s = m.shape; const svg = abutGroundSectionSvg({ ground: { groundEl: rec.groundEl, groundWaterOn: true, groundWaterEl: 31, strataRows: rows }, footingTopEl: m.footingTopEl, footingBottomEl: m.footingBottomEl!, seatEl: rec.seatEl, parapetTopEl: m.parapetTopStartEl, bracketHeightM: s.bracketHeightM, wallFrontM: s.wallFrontM, wallBackM: s.wallBackM, parapetBackM: s.parapetBackM, footingFrontM: s.footingFrontM, footingBackM: s.footingBackM, pileRowsT: m.piles.map((r) => r.t), pileBottomEl: m.pileBottomEl, }); for (const t of ['지반고 EL.33.984', '지하수위 EL.31.000', '연암층 상면 EL.22.000', '기초 하단 EL.40.895', '말뚝 선단 EL.19.295', '퇴적토', '풍화암']) expect(svg).toContain(t); }); });