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 } from '../src/core/abut/parse'; import { buildMembers } from '../src/core/abut/members'; import { ABUT_BEARING_RULE_DEFAULT, abutBearingChecks, abutElevationRows, abutSolplateRows, resolveBearingRule, } from '../src/core/abut/bearing-table'; import { applyBearingRule } from '../src/core/abut/edit'; import { checkStoredAbutments } from '../src/core/project'; const RAG = fileURLToPath(new URL('../../../RAG/운곡교P1입력.xlsx', import.meta.url)); const rec = parseAbutments(XLSX.read(readFileSync(RAG), { type: 'buffer' })).abutments[0]; const input = toAbutInput(rec); const model = buildAbut(input); const members = buildMembers(model, { bottomEl: input.foundationBottomEl, pileLengthMm: input.pileLengthMm }); const rule = resolveBearingRule(); describe('교대 받침 카드 표 (시안 ②, QA-15 가정)', () => { it('ELEVATION: block 125 = concrete 75 + pad 50, E = 75 + 50 + 181 + 30 = 336', () => { const rows = abutElevationRows(model, rule); expect(rows).toHaveLength(5); for (const r of rows) { expect(r.h1).toBe(75); expect(r.h2).toBe(50); expect(r.E).toBe(336); expect(r.solplateTopEl).toBeCloseTo(r.seatEl + 0.336, 6); } const first = rows.find((r) => r.no === 1)!; expect(first.seg).toBe('①'); expect(first.seatEl).toBeCloseTo(44.367, 3); expect(first.z).toBeCloseTo(44.492, 3); }); it('솔플레이트: L 800, W 740, S = −1.91 %, T1 38 / T2 22, check 16 ≈ 15.3', () => { const [r] = abutSolplateRows(model, rule, rec.slopeI); expect(r.L).toBe(800); expect(r.W).toBe(740); expect(r.S).toBeCloseTo(-1.91, 2); expect([r.T, r.T1, r.T2]).toEqual([30, 38, 22]); expect(r.check).toBe('16 ≈ 15.3'); }); it('the rule inputs change the table: h3 200 gives E 355, margin 150 gives L 850', () => { const r2 = resolveBearingRule({ h3Mm: 200, solplateMarginMm: 150 }); expect(abutElevationRows(model, r2)[0].E).toBe(355); expect(abutSolplateRows(model, r2, rec.slopeI)[0].L).toBe(850); expect(ABUT_BEARING_RULE_DEFAULT.kind).toBe('탄성받침'); }); it('checks: W02, W04 (흉벽 ≈ 145 · 전면 255), W03 and I01 all clear for A1', () => { const lines = abutBearingChecks(model, members, rule); expect(lines).toHaveLength(4); expect(lines[0]).toContain('W02 없음'); // 시안 145 is bearing ① (lateral 0.745); the smallest gap over the five bearings is 144 (lateral 0.744). expect(lines[1]).toMatch(/흉벽 14[45]/); expect(lines[1]).toContain('전면 255'); expect(lines[1]).toContain('W04 없음'); expect(lines[2]).toContain('W03 없음'); expect(lines[3]).toContain('I01 없음'); }); it('the rule edit keeps only changed values, refuses 0 and an empty 받침 종류, and the project file accepts it', () => { const edited = applyBearingRule(applyBearingRule(rec, 'h3Mm', 200), 'kind', '포트받침 3000 kN'); expect(edited.bearingRule).toEqual({ h3Mm: 200, kind: '포트받침 3000 kN' }); expect(() => applyBearingRule(rec, 'solplateTMm', 0)).toThrow('0보다 큰'); expect(() => applyBearingRule(rec, 'kind', ' ')).toThrow('받침 종류'); expect(() => checkStoredAbutments([edited])).not.toThrow(); expect(() => checkStoredAbutments([{ ...edited, bearingRule: { h3Mm: 'x' } }])).toThrow('받침 규칙'); }); });