Files
Pier_v1/tests/validate-and-foundation.test.ts
T
ypshimandClaude Haiku 5.5 5466b3522e feat(core): haunch-and-Level-300 coping underside, steel pile 609.6, W03/W04 checks
- Multi-column coping (2·3주형): underside between columns drops 300 below
  Level with 300 × 300 haunches (spec §4.5, Q3 추천안).
- Steel pipe pile diameter 609.6 mm (spec §4.5, Q5 추천안).
- Direct foundation keeps the 100 mm blinding concrete (Q4 추천안, test added).
- W03: bearing centre closer than half a block width to a step boundary.
- W04: block footprint outside the coping plan.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-22 08:58:57 +09:00

109 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it } from 'vitest';
import { buildPier } from '../src/core/geometry';
import { validateInput, validatePier } from '../src/core/validate';
import type { Issue, PierInput } from '../src/core/types';
import { loadP1 } from './helpers';
function run(input: PierInput): Issue[] {
const issues: Issue[] = [];
if (validateInput(input, issues)) validatePier(input, buildPier(input), issues);
return issues;
}
describe('validation (spec §10)', () => {
it('P1 raises I01 (block 100 mm < cover + bar 119 mm) and no E/W', () => {
const issues = run(loadP1());
expect(issues.map((i) => i.code)).toContain('I01');
expect(issues.filter((i) => i.level !== 'I')).toEqual([]);
});
it('E01 when the pier type and column count disagree', () => {
const issues = run({ ...loadP1(), type: '2주형' });
expect(issues.map((i) => i.code)).toContain('E01');
});
it('E02 when front and back bearing counts differ', () => {
const p1 = loadP1();
const issues: Issue[] = [];
const bad = { ...p1, bearings: p1.bearings.filter((b) => !(b.row === '후열' && b.no === 10)) };
expect(validateInput(bad, issues)).toBe(false);
expect(issues.map((i) => i.code)).toContain('E02');
});
it('W01 when IP2 disagrees with the 1:9 recalculation by more than 1 mm', () => {
const p1 = loadP1();
const ips = p1.ips.map((p) => (p.name === 'IP2' ? { ...p, x: p.x + 0.002 } : p));
expect(run({ ...p1, ips }).map((i) => i.code)).toContain('W01');
});
});
describe('foundation types', () => {
it('직접기초: footing, no piles', () => {
const m = buildPier({ ...loadP1(), foundationType: '직접기초' });
expect(m.footings).toHaveLength(1);
expect(m.piles).toHaveLength(0);
});
it('직접기초: blinding concrete under the footing (Q4 추천안, 적용)', () => {
const m = buildPier({ ...loadP1(), foundationType: '직접기초' });
expect(m.blindings).toHaveLength(1);
expect(m.blindings[0].thickness).toBeCloseTo(0.1, 6);
});
it('말뚝기초: steel pipe pile 609.6 mm (Q5 추천안)', () => {
const m = buildPier(loadP1());
expect(m.piles.length).toBeGreaterThan(0);
expect(m.piles[0].diameter).toBeCloseTo(0.6096, 6);
});
it('2주형: underside between columns drops 300 below Level, T형 has no such point (Q3 추천안)', () => {
const t = buildPier(loadP1());
const dip = t.levelBottom - 0.3;
expect(t.profile.some(([, z]) => Math.abs(z - dip) < 1e-9)).toBe(false);
const two = buildPier({ ...loadP1(), type: '2주형', columnCount: 2 });
expect(two.profile.some(([, z]) => Math.abs(z - dip) < 1e-9)).toBe(true);
const outlineLow = Math.min(...two.profile.map(([, z]) => z));
expect(outlineLow).toBeCloseTo(dip, 9);
});
it('3주형 builds with two gaps of haunches', () => {
const m = buildPier({ ...loadP1(), type: '3주형', columnCount: 3 });
const dips = m.profile.filter(([, z]) => Math.abs(z - (m.levelBottom - 0.3)) < 1e-9);
expect(dips).toHaveLength(4);
});
it('현장타설말뚝: no footing, one pile of column diameter per column, tip = bottom EL − length', () => {
const m = buildPier({ ...loadP1(), foundationType: '현장타설말뚝' });
expect(m.footings).toHaveLength(0);
expect(m.piles).toHaveLength(1);
expect(m.piles[0].diameter).toBeCloseTo(2.0, 6);
expect(m.piles[0].bottom).toBeCloseTo(26.208 - 24, 6);
});
});
describe('bearing and block checks (spec §10 W03, W04)', () => {
it('P1 has no W03 or W04', () => {
const codes = run(loadP1()).map((i) => i.code);
expect(codes).not.toContain('W03');
expect(codes).not.toContain('W04');
});
it('W03 when a bearing centre is closer than half a block width to a step boundary', () => {
const m = buildPier(loadP1());
const boundary = m.segments[1].s0;
const bearings = m.bearings.map((b, k) => (k === 0 ? { ...b, s: boundary + 0.3 } : b));
const issues: Issue[] = [];
validatePier(loadP1(), { ...m, bearings }, issues);
expect(issues.map((i) => i.code)).toContain('W03');
});
it('W04 when a block footprint extends past the coping end', () => {
const m = buildPier(loadP1());
const blocks = m.blocks.map((b, k) => (k === 0 ? { ...b, s: 0.1 } : b));
const issues: Issue[] = [];
validatePier(loadP1(), { ...m, blocks }, issues);
expect(issues.map((i) => i.code)).toContain('W04');
});
});