262 lines
10 KiB
TypeScript
262 lines
10 KiB
TypeScript
/**
|
|
* InstallOrderRulesEngine 单元测试
|
|
*/
|
|
|
|
import {
|
|
InstallOrderRulesEngine,
|
|
InstallStepItem,
|
|
InstallOrderRule,
|
|
HardwareCategory,
|
|
PanelCategory,
|
|
} from '@/lib/3d/install-order-rules'
|
|
|
|
describe('InstallOrderRulesEngine', () => {
|
|
let engine: InstallOrderRulesEngine
|
|
|
|
beforeEach(() => {
|
|
engine = new InstallOrderRulesEngine()
|
|
})
|
|
|
|
describe('规则管理', () => {
|
|
it('应该加载内置规则', () => {
|
|
const rules = engine.getRules()
|
|
expect(rules.length).toBeGreaterThan(0)
|
|
})
|
|
|
|
it('应该能添加自定义规则', () => {
|
|
const customRule: InstallOrderRule = {
|
|
id: 'custom-rule',
|
|
name: '自定义规则',
|
|
description: '测试用',
|
|
priority: 100,
|
|
condition: () => false,
|
|
getOrder: (item) => item.originalOrder,
|
|
}
|
|
|
|
const initialCount = engine.getRules().length
|
|
engine.addRule(customRule)
|
|
expect(engine.getRules().length).toBe(initialCount + 1)
|
|
})
|
|
|
|
it('添加规则后应该按优先级排序', () => {
|
|
const highPriorityRule: InstallOrderRule = {
|
|
id: 'high-priority',
|
|
name: '高优先级',
|
|
description: '',
|
|
priority: 1,
|
|
condition: () => false,
|
|
getOrder: (item) => item.originalOrder,
|
|
}
|
|
|
|
engine.addRule(highPriorityRule)
|
|
const rules = engine.getRules()
|
|
expect(rules[0].id).toBe('high-priority')
|
|
})
|
|
|
|
it('应该能移除规则', () => {
|
|
const rules = engine.getRules()
|
|
const firstRuleId = rules[0].id
|
|
|
|
const result = engine.removeRule(firstRuleId)
|
|
expect(result).toBe(true)
|
|
expect(engine.getRules().find(r => r.id === firstRuleId)).toBeUndefined()
|
|
})
|
|
|
|
it('移除不存在的规则应该返回 false', () => {
|
|
const result = engine.removeRule('not-exist')
|
|
expect(result).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('合页-门板排序', () => {
|
|
it('合页应该在门板之前', () => {
|
|
const items: InstallStepItem[] = [
|
|
{ id: 'door-1', type: 'panel', category: 'door', name: '门板', originalOrder: 1 },
|
|
{ id: 'hinge-1', type: 'hardware', category: 'hinge', name: '合页', parentPanelId: 'door-1', originalOrder: 2 },
|
|
]
|
|
|
|
const sorted = engine.sortInstallSteps(items)
|
|
|
|
const hingeIndex = sorted.findIndex(i => i.id === 'hinge-1')
|
|
const doorIndex = sorted.findIndex(i => i.id === 'door-1')
|
|
|
|
expect(hingeIndex).toBeLessThan(doorIndex)
|
|
})
|
|
|
|
it('多个合页都应该在门板之前', () => {
|
|
const items: InstallStepItem[] = [
|
|
{ id: 'door-1', type: 'panel', category: 'door', name: '门板', originalOrder: 1 },
|
|
{ id: 'hinge-1', type: 'hardware', category: 'hinge', name: '合页1', parentPanelId: 'door-1', originalOrder: 3 },
|
|
{ id: 'hinge-2', type: 'hardware', category: 'hinge', name: '合页2', parentPanelId: 'door-1', originalOrder: 4 },
|
|
]
|
|
|
|
const sorted = engine.sortInstallSteps(items)
|
|
const doorIndex = sorted.findIndex(i => i.id === 'door-1')
|
|
|
|
sorted
|
|
.filter(i => i.category === 'hinge')
|
|
.forEach(hinge => {
|
|
const hingeIndex = sorted.findIndex(i => i.id === hinge.id)
|
|
expect(hingeIndex).toBeLessThan(doorIndex)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('滑轨-抽屉排序', () => {
|
|
it('滑轨应该在抽屉面板之前', () => {
|
|
const items: InstallStepItem[] = [
|
|
{ id: 'drawer-front', type: 'panel', category: 'drawer-front', name: '抽屉面板', originalOrder: 1 },
|
|
{ id: 'slide-1', type: 'hardware', category: 'slide', name: '滑轨', parentPanelId: 'drawer-front', originalOrder: 2 },
|
|
]
|
|
|
|
const sorted = engine.sortInstallSteps(items)
|
|
|
|
const slideIndex = sorted.findIndex(i => i.id === 'slide-1')
|
|
const drawerIndex = sorted.findIndex(i => i.id === 'drawer-front')
|
|
|
|
expect(slideIndex).toBeLessThan(drawerIndex)
|
|
})
|
|
})
|
|
|
|
describe('把手排序', () => {
|
|
it('门板上的把手应该在门板之后', () => {
|
|
const items: InstallStepItem[] = [
|
|
{ id: 'door-1', type: 'panel', category: 'door', name: '门板', originalOrder: 2 },
|
|
{ id: 'handle-1', type: 'hardware', category: 'handle', name: '把手', parentPanelId: 'door-1', originalOrder: 1 },
|
|
]
|
|
|
|
const sorted = engine.sortInstallSteps(items)
|
|
|
|
const handleIndex = sorted.findIndex(i => i.id === 'handle-1')
|
|
const doorIndex = sorted.findIndex(i => i.id === 'door-1')
|
|
|
|
expect(handleIndex).toBeGreaterThan(doorIndex)
|
|
})
|
|
})
|
|
|
|
describe('验证功能', () => {
|
|
it('正确的顺序应该通过验证', () => {
|
|
const items: InstallStepItem[] = [
|
|
{ id: 'hinge-1', type: 'hardware', category: 'hinge', name: '合页', parentPanelId: 'door-1', originalOrder: 1 },
|
|
{ id: 'door-1', type: 'panel', category: 'door', name: '门板', originalOrder: 2 },
|
|
]
|
|
|
|
const sorted = engine.sortInstallSteps(items)
|
|
const result = engine.validateOrder(sorted)
|
|
|
|
expect(result.valid).toBe(true)
|
|
expect(result.warnings.length).toBe(0)
|
|
})
|
|
|
|
it('错误的顺序应该产生警告', () => {
|
|
// 直接创建一个错误顺序的列表(跳过排序)
|
|
const items = [
|
|
{ id: 'door-1', type: 'panel' as const, category: 'door' as const, name: '门板', originalOrder: 1, finalOrder: 1 },
|
|
{ id: 'hinge-1', type: 'hardware' as const, category: 'hinge' as const, name: '合页', parentPanelId: 'door-1', originalOrder: 2, finalOrder: 2 },
|
|
]
|
|
|
|
const result = engine.validateOrder(items)
|
|
|
|
expect(result.valid).toBe(false)
|
|
expect(result.warnings.length).toBeGreaterThan(0)
|
|
})
|
|
})
|
|
|
|
describe('类型推断', () => {
|
|
describe('inferHardwareCategory', () => {
|
|
const testCases: Array<{ code: string; name: string; expected: HardwareCategory }> = [
|
|
{ code: 'HINGE-001', name: '铰链', expected: 'hinge' },
|
|
{ code: 'HG-001', name: '合页', expected: 'hinge' },
|
|
{ code: 'SLIDE-001', name: '滑轨', expected: 'slide' },
|
|
{ code: 'DR-001', name: '导轨', expected: 'slide' },
|
|
{ code: 'CON-001', name: '连接件', expected: 'connector' },
|
|
{ code: 'HANDLE-001', name: '把手', expected: 'handle' },
|
|
{ code: 'LS-001', name: '拉手', expected: 'handle' },
|
|
{ code: 'LOCK-001', name: '锁', expected: 'lock' },
|
|
{ code: 'DMP-001', name: '阻尼器', expected: 'damper' },
|
|
{ code: 'BF-001', name: '缓冲器', expected: 'damper' },
|
|
{ code: 'SUP-001', name: '支撑件', expected: 'support' },
|
|
{ code: 'SCR-001', name: '螺丝', expected: 'screw' },
|
|
{ code: 'M4X20', name: '螺钉', expected: 'screw' },
|
|
{ code: 'ABC-001', name: '未知类型', expected: 'other' },
|
|
]
|
|
|
|
testCases.forEach(({ code, name, expected }) => {
|
|
it(`应该将 "${code}" / "${name}" 识别为 "${expected}"`, () => {
|
|
const result = InstallOrderRulesEngine.inferHardwareCategory(code, name)
|
|
expect(result).toBe(expected)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('inferPanelCategory', () => {
|
|
const testCases: Array<{ name: string; expected: PanelCategory }> = [
|
|
{ name: '门板', expected: 'door' },
|
|
{ name: 'Door Panel', expected: 'door' },
|
|
{ name: '抽屉面板', expected: 'drawer-front' },
|
|
{ name: '抽屉侧板', expected: 'drawer-side' },
|
|
{ name: '抽屉背板', expected: 'drawer-back' },
|
|
{ name: '抽屉底板', expected: 'drawer-bottom' },
|
|
{ name: '层板', expected: 'shelf' },
|
|
{ name: 'Shelf', expected: 'shelf' },
|
|
{ name: '侧板', expected: 'side' },
|
|
{ name: '顶板', expected: 'top' },
|
|
{ name: '底板', expected: 'bottom' },
|
|
{ name: '背板', expected: 'back' },
|
|
{ name: '隔板', expected: 'partition' },
|
|
{ name: '未知板材', expected: 'other' },
|
|
]
|
|
|
|
testCases.forEach(({ name, expected }) => {
|
|
it(`应该将 "${name}" 识别为 "${expected}"`, () => {
|
|
const result = InstallOrderRulesEngine.inferPanelCategory(name)
|
|
expect(result).toBe(expected)
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('复杂场景', () => {
|
|
it('完整的门板安装顺序', () => {
|
|
const items: InstallStepItem[] = [
|
|
{ id: 'side-1', type: 'panel', category: 'side', name: '侧板', originalOrder: 1 },
|
|
{ id: 'door-1', type: 'panel', category: 'door', name: '门板', originalOrder: 2 },
|
|
{ id: 'hinge-1', type: 'hardware', category: 'hinge', name: '合页', parentPanelId: 'door-1', originalOrder: 3 },
|
|
{ id: 'handle-1', type: 'hardware', category: 'handle', name: '把手', parentPanelId: 'door-1', originalOrder: 4 },
|
|
{ id: 'damper-1', type: 'hardware', category: 'damper', name: '阻尼器', parentPanelId: 'door-1', originalOrder: 5 },
|
|
]
|
|
|
|
const sorted = engine.sortInstallSteps(items)
|
|
|
|
// 验证顺序:侧板 -> 合页 -> 门板 -> (阻尼器/把手)
|
|
const sideIndex = sorted.findIndex(i => i.id === 'side-1')
|
|
const hingeIndex = sorted.findIndex(i => i.id === 'hinge-1')
|
|
const doorIndex = sorted.findIndex(i => i.id === 'door-1')
|
|
const handleIndex = sorted.findIndex(i => i.id === 'handle-1')
|
|
|
|
expect(sideIndex).toBeLessThan(hingeIndex)
|
|
expect(hingeIndex).toBeLessThan(doorIndex)
|
|
expect(doorIndex).toBeLessThan(handleIndex)
|
|
})
|
|
|
|
it('完整的抽屉安装顺序', () => {
|
|
const items: InstallStepItem[] = [
|
|
{ id: 'side-1', type: 'panel', category: 'side', name: '侧板', originalOrder: 1 },
|
|
{ id: 'drawer-front', type: 'panel', category: 'drawer-front', name: '抽屉面板', originalOrder: 2 },
|
|
{ id: 'slide-1', type: 'hardware', category: 'slide', name: '滑轨', parentPanelId: 'drawer-front', originalOrder: 3 },
|
|
{ id: 'handle-1', type: 'hardware', category: 'handle', name: '把手', parentPanelId: 'drawer-front', originalOrder: 4 },
|
|
]
|
|
|
|
const sorted = engine.sortInstallSteps(items)
|
|
|
|
// 验证顺序:侧板 -> 滑轨 -> 抽屉面板 -> 把手
|
|
const sideIndex = sorted.findIndex(i => i.id === 'side-1')
|
|
const slideIndex = sorted.findIndex(i => i.id === 'slide-1')
|
|
const drawerIndex = sorted.findIndex(i => i.id === 'drawer-front')
|
|
|
|
expect(sideIndex).toBeLessThan(slideIndex)
|
|
expect(slideIndex).toBeLessThan(drawerIndex)
|
|
})
|
|
})
|
|
})
|