121 lines
5.1 KiB
TypeScript
121 lines
5.1 KiB
TypeScript
import * as XLSX from 'xlsx';
|
||
import { describe, expect, it } from 'vitest';
|
||
import { parseWorkbook } from '../src/core/parseWorkbook';
|
||
import { loadInputWorkbook, loadP1, loadWorkbook } from './helpers';
|
||
|
||
describe('parseWorkbook (P1 sheet intent.PR)', () => {
|
||
it('finds exactly one pier P1 with the input values of the sheet', () => {
|
||
const { piers, issues } = parseWorkbook(loadWorkbook());
|
||
expect(issues).toEqual([]);
|
||
expect(piers.map((p) => p.name)).toEqual(['P1']);
|
||
const p1 = loadP1();
|
||
expect(p1.type).toBe('T형');
|
||
expect(p1.foundationType).toBe('말뚝기초');
|
||
expect(p1.copingTopEl).toBeCloseTo(43.411, 6);
|
||
expect(p1.footingBottomEl).toBeCloseTo(26.208, 6);
|
||
expect(p1.groundEl).toBeCloseTo(28.931, 6);
|
||
expect(p1.pileLengthMm).toBe(24000);
|
||
expect(p1.copingWidthMm).toBe(3100);
|
||
expect(p1.copingLengthMm).toBe(12000);
|
||
expect(p1.columnCount).toBe(1);
|
||
});
|
||
|
||
it('reads 4 IP points and 10 bearings (5 front, 5 back)', () => {
|
||
const p1 = loadP1();
|
||
expect(p1.ips.map((p) => p.name)).toEqual(['IP1', 'IP2', 'IP3', 'IP4']);
|
||
expect(p1.bearings).toHaveLength(10);
|
||
expect(p1.bearings.filter((b) => b.row === '전열')).toHaveLength(5);
|
||
expect(p1.bearings.filter((b) => b.row === '후열')).toHaveLength(5);
|
||
});
|
||
|
||
it('converts the bearing azimuth strings to decimal degrees', () => {
|
||
const p1 = loadP1();
|
||
expect(p1.bearings[0].azimuthDeg).toBeCloseTo(14.0511, 4);
|
||
expect(p1.bearingAzimuthFrame).toBe('model-xy');
|
||
});
|
||
});
|
||
|
||
describe('sheet report (spec §2.3)', () => {
|
||
it('marks the P1 sheet as selectable and counts its tables', () => {
|
||
const { sheets } = parseWorkbook(loadWorkbook());
|
||
expect(sheets).toHaveLength(1);
|
||
expect(sheets[0]).toMatchObject({ name: 'intent.PR', ok: true, piers: 1, tables: { pier: 1, ip: 1, bearing: 1 } });
|
||
});
|
||
|
||
it('marks a sheet with a bad azimuth (E03) as not selectable and drops its pier', () => {
|
||
const wb = loadWorkbook();
|
||
wb.Sheets['intent.PR']['F32'].v = '75.9';
|
||
const { piers, sheets, issues } = parseWorkbook(wb);
|
||
expect(issues.map((i) => i.code)).toContain('E03');
|
||
expect(sheets[0].ok).toBe(false);
|
||
expect(piers).toHaveLength(0);
|
||
});
|
||
});
|
||
|
||
describe('tables split across sheets (spec §2.2: 시트 1장 = 교각 1기)', () => {
|
||
it('reports E05 and drops the pier when the IP table is not on the same sheet', () => {
|
||
const wb = loadWorkbook();
|
||
wb.Sheets['intent.PR']['B25'].v = '기타';
|
||
const { piers, sheets, issues } = parseWorkbook(wb);
|
||
expect(issues.map((i) => i.code)).toContain('E05');
|
||
expect(piers).toHaveLength(0);
|
||
expect(sheets[0].ok).toBe(false);
|
||
});
|
||
});
|
||
|
||
describe('three-sheet input (교각 · IP · 받침 on separate sheets, joined by 교각명)', () => {
|
||
/** Splits the P1 sheet into the three sheets the user prepares: rows 22–23, 25–29, 31–41 (1-based). */
|
||
function threeSheets(): XLSX.WorkBook {
|
||
const src = loadWorkbook();
|
||
const grid = XLSX.utils.sheet_to_json<(string | number | null)[]>(src.Sheets['intent.PR'], {
|
||
header: 1,
|
||
raw: true,
|
||
defval: null,
|
||
});
|
||
const wb = XLSX.utils.book_new();
|
||
XLSX.utils.book_append_sheet(wb, XLSX.utils.aoa_to_sheet(grid.slice(21, 23)), '교각');
|
||
XLSX.utils.book_append_sheet(wb, XLSX.utils.aoa_to_sheet(grid.slice(24, 29)), 'IP');
|
||
XLSX.utils.book_append_sheet(wb, XLSX.utils.aoa_to_sheet(grid.slice(30, 41)), '받침');
|
||
return wb;
|
||
}
|
||
|
||
it('joins the three sheets into one pier with 4 IP points and 10 bearings', () => {
|
||
const { piers, issues, sheets } = parseWorkbook(threeSheets());
|
||
expect(issues).toEqual([]);
|
||
expect(piers).toHaveLength(1);
|
||
expect(piers[0]).toMatchObject({ name: 'P1', sheet: '교각' });
|
||
expect(piers[0].ips).toHaveLength(4);
|
||
expect(piers[0].bearings).toHaveLength(10);
|
||
expect(sheets.map((s) => [s.name, s.ok, s.piers])).toEqual([
|
||
['교각', true, 1],
|
||
['IP', true, 0],
|
||
['받침', true, 0],
|
||
]);
|
||
});
|
||
});
|
||
|
||
describe('user input file (RAG/운곡교P1입력.xlsx)', () => {
|
||
it('accepts π형 as 2주형 without changing the source workbook value', () => {
|
||
const wb = loadInputWorkbook();
|
||
const grid = XLSX.utils.sheet_to_json<(string | number | null)[]>(wb.Sheets['교각'], { header: 1, defval: null });
|
||
const header = grid.findIndex((row) => row[0] === '교각명' && row[1] === '교각형식');
|
||
expect(header).toBeGreaterThanOrEqual(0);
|
||
grid[header + 1][1] = ' π형 ';
|
||
grid[header + 1][9] = 2;
|
||
wb.Sheets['교각'] = XLSX.utils.aoa_to_sheet(grid);
|
||
const { piers, issues } = parseWorkbook(wb);
|
||
expect(issues).toEqual([]);
|
||
expect(piers).toHaveLength(1);
|
||
expect(piers[0]).toMatchObject({ type: '2주형', columnCount: 2 });
|
||
expect(XLSX.utils.sheet_to_json<(string | number | null)[]>(wb.Sheets['교각'], { header: 1 })[header + 1][1]).toBe(' π형 ');
|
||
});
|
||
|
||
it('has the three sheets 교각 · IP · 받침 and parses to one pier, P1, with no issues', () => {
|
||
const wb = loadInputWorkbook();
|
||
expect(wb.SheetNames).toEqual(['교각', 'IP', '받침']);
|
||
const { piers, issues } = parseWorkbook(wb);
|
||
expect(issues).toEqual([]);
|
||
expect(piers.map((p) => [p.name, p.sheet])).toEqual([['P1', '교각']]);
|
||
});
|
||
});
|