Files
jordium-gantt-vue3/tests/unit/utils/conflictUtils.spec.ts
T

402 lines
11 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.
/**
* conflictUtils.spec.ts - 资源冲突检测工具单元测试
*/
import { describe, it, expect } from 'vitest'
import {
detectConflicts,
getTimeIntersection,
getConflictLevel,
type ConflictZone,
} from '../../../src/utils/conflictUtils'
import type { Task } from '../../../src/models/classes/Task'
describe('conflictUtils', () => {
describe('getConflictLevel', () => {
it('应该返回 light 等级(100%-120%', () => {
expect(getConflictLevel(100)).toBe('light')
expect(getConflictLevel(110)).toBe('light')
expect(getConflictLevel(120)).toBe('light')
})
it('应该返回 medium 等级(120%-150%', () => {
expect(getConflictLevel(121)).toBe('medium')
expect(getConflictLevel(130)).toBe('medium')
expect(getConflictLevel(150)).toBe('medium')
})
it('应该返回 severe 等级(>150%', () => {
expect(getConflictLevel(151)).toBe('severe')
expect(getConflictLevel(200)).toBe('severe')
expect(getConflictLevel(300)).toBe('severe')
})
})
describe('getTimeIntersection', () => {
it('应该正确计算两个任务的时间交集', () => {
const task1: Task = {
id: 1,
name: '任务1',
startDate: '2026-01-10',
endDate: '2026-01-15',
} as Task
const task2: Task = {
id: 2,
name: '任务2',
startDate: '2026-01-12',
endDate: '2026-01-20',
} as Task
const intersection = getTimeIntersection(task1, task2)
expect(intersection).not.toBeNull()
expect(intersection?.start).toEqual(new Date(2026, 0, 12))
expect(intersection?.end).toEqual(new Date(2026, 0, 15))
})
it('应该在无交集时返回null', () => {
const task1: Task = {
id: 1,
name: '任务1',
startDate: '2026-01-10',
endDate: '2026-01-15',
} as Task
const task2: Task = {
id: 2,
name: '任务2',
startDate: '2026-01-20',
endDate: '2026-01-25',
} as Task
const intersection = getTimeIntersection(task1, task2)
expect(intersection).toBeNull()
})
it('应该处理边界相接的情况(不算交集)', () => {
const task1: Task = {
id: 1,
name: '任务1',
startDate: '2026-01-10',
endDate: '2026-01-15',
} as Task
const task2: Task = {
id: 2,
name: '任务2',
startDate: '2026-01-15',
endDate: '2026-01-20',
} as Task
const intersection = getTimeIntersection(task1, task2)
// 边界相接不算交集
expect(intersection).toBeNull()
})
it('应该处理完全包含的情况', () => {
const task1: Task = {
id: 1,
name: '任务1',
startDate: '2026-01-10',
endDate: '2026-01-25',
} as Task
const task2: Task = {
id: 2,
name: '任务2',
startDate: '2026-01-15',
endDate: '2026-01-20',
} as Task
const intersection = getTimeIntersection(task1, task2)
expect(intersection).not.toBeNull()
expect(intersection?.start).toEqual(new Date(2026, 0, 15))
expect(intersection?.end).toEqual(new Date(2026, 0, 20))
})
it('应该处理缺少日期的情况', () => {
const task1: Task = {
id: 1,
name: '任务1',
startDate: '2026-01-10',
} as Task
const task2: Task = {
id: 2,
name: '任务2',
startDate: '2026-01-15',
endDate: '2026-01-20',
} as Task
const intersection = getTimeIntersection(task1, task2)
expect(intersection).toBeNull()
})
})
describe('detectConflicts', () => {
it('应该检测不出无冲突场景', () => {
const tasks: Task[] = [
{
id: 1,
name: '任务1',
startDate: '2026-01-10',
endDate: '2026-01-15',
resources: [{ id: 'r1', capacity: 50 }],
} as Task,
{
id: 2,
name: '任务2',
startDate: '2026-01-20',
endDate: '2026-01-25',
resources: [{ id: 'r1', capacity: 60 }],
} as Task,
]
const conflicts = detectConflicts(tasks, 'r1')
expect(conflicts).toHaveLength(0)
})
it('应该检测出轻度冲突(总占比100%-120%', () => {
const tasks: Task[] = [
{
id: 1,
name: '任务1',
startDate: '2026-01-10',
endDate: '2026-01-15',
resources: [{ id: 'r1', capacity: 60 }],
} as Task,
{
id: 2,
name: '任务2',
startDate: '2026-01-12',
endDate: '2026-01-20',
resources: [{ id: 'r1', capacity: 50 }],
} as Task,
]
const conflicts = detectConflicts(tasks, 'r1')
expect(conflicts).toHaveLength(1)
expect(conflicts[0].level).toBe('light')
expect(conflicts[0].totalPercent).toBe(110)
expect(conflicts[0].tasks).toHaveLength(2)
})
it('应该检测出中度冲突(总占比120%-150%', () => {
const tasks: Task[] = [
{
id: 1,
name: '任务1',
startDate: '2026-01-10',
endDate: '2026-01-15',
resources: [{ id: 'r1', capacity: 70 }],
} as Task,
{
id: 2,
name: '任务2',
startDate: '2026-01-12',
endDate: '2026-01-20',
resources: [{ id: 'r1', capacity: 65 }],
} as Task,
]
const conflicts = detectConflicts(tasks, 'r1')
expect(conflicts).toHaveLength(1)
expect(conflicts[0].level).toBe('medium')
expect(conflicts[0].totalPercent).toBe(135)
})
it('应该检测出严重冲突(总占比>150%)', () => {
const tasks: Task[] = [
{
id: 1,
name: '任务1',
startDate: '2026-01-10',
endDate: '2026-01-15',
resources: [{ id: 'r1', capacity: 80 }],
} as Task,
{
id: 2,
name: '任务2',
startDate: '2026-01-12',
endDate: '2026-01-20',
resources: [{ id: 'r1', capacity: 90 }],
} as Task,
]
const conflicts = detectConflicts(tasks, 'r1')
expect(conflicts).toHaveLength(1)
expect(conflicts[0].level).toBe('severe')
expect(conflicts[0].totalPercent).toBe(170)
})
it('应该检测出多任务冲突', () => {
const tasks: Task[] = [
{
id: 1,
name: '任务1',
startDate: '2026-01-10',
endDate: '2026-01-20',
resources: [{ id: 'r1', capacity: 40 }],
} as Task,
{
id: 2,
name: '任务2',
startDate: '2026-01-12',
endDate: '2026-01-18',
resources: [{ id: 'r1', capacity: 50 }],
} as Task,
{
id: 3,
name: '任务3',
startDate: '2026-01-15',
endDate: '2026-01-25',
resources: [{ id: 'r1', capacity: 30 }],
} as Task,
]
const conflicts = detectConflicts(tasks, 'r1')
expect(conflicts.length).toBeGreaterThan(0)
expect(conflicts[0].tasks.length).toBeGreaterThanOrEqual(2)
expect(conflicts[0].totalPercent).toBeGreaterThan(100)
})
it('应该正确过滤指定资源的任务', () => {
const tasks: Task[] = [
{
id: 1,
name: '任务1',
startDate: '2026-01-10',
endDate: '2026-01-15',
resources: [{ id: 'r1', capacity: 60 }],
} as Task,
{
id: 2,
name: '任务2',
startDate: '2026-01-12',
endDate: '2026-01-20',
resources: [{ id: 'r2', capacity: 80 }], // 不同资源
} as Task,
{
id: 3,
name: '任务3',
startDate: '2026-01-12',
endDate: '2026-01-20',
resources: [{ id: 'r1', capacity: 50 }],
} as Task,
]
const conflicts = detectConflicts(tasks, 'r1')
// 应该只检测r1的冲突,不包含r2的任务
expect(conflicts).toHaveLength(1)
expect(conflicts[0].tasks.every(t =>
tasks.find(task => task.id === t.id)?.resources?.some(r => r.id === 'r1')
)).toBe(true)
})
it('应该处理没有资源的任务', () => {
const tasks: Task[] = [
{
id: 1,
name: '任务1',
startDate: '2026-01-10',
endDate: '2026-01-15',
} as Task,
{
id: 2,
name: '任务2',
startDate: '2026-01-12',
endDate: '2026-01-20',
resources: [{ id: 'r1', capacity: 50 }],
} as Task,
]
const conflicts = detectConflicts(tasks, 'r1')
expect(conflicts).toHaveLength(0)
})
it('应该处理占比未超载的情况(<=100%', () => {
const tasks: Task[] = [
{
id: 1,
name: '任务1',
startDate: '2026-01-10',
endDate: '2026-01-15',
resources: [{ id: 'r1', capacity: 40 }],
} as Task,
{
id: 2,
name: '任务2',
startDate: '2026-01-12',
endDate: '2026-01-20',
resources: [{ id: 'r1', capacity: 50 }],
} as Task,
]
const conflicts = detectConflicts(tasks, 'r1')
// 总占比90%,未超载,不应检测出冲突
expect(conflicts).toHaveLength(0)
})
it('应该处理单个任务的情况', () => {
const tasks: Task[] = [
{
id: 1,
name: '任务1',
startDate: '2026-01-10',
endDate: '2026-01-15',
resources: [{ id: 'r1', capacity: 120 }], // 单个任务占比>100%也不算冲突
} as Task,
]
const conflicts = detectConflicts(tasks, 'r1')
expect(conflicts).toHaveLength(0)
})
it('应该合并重叠的冲突区域', () => {
const tasks: Task[] = [
{
id: 1,
name: '任务1',
startDate: '2026-01-10',
endDate: '2026-01-20',
resources: [{ id: 'r1', capacity: 60 }],
} as Task,
{
id: 2,
name: '任务2',
startDate: '2026-01-12',
endDate: '2026-01-18',
resources: [{ id: 'r1', capacity: 50 }],
} as Task,
{
id: 3,
name: '任务3',
startDate: '2026-01-15',
endDate: '2026-01-25',
resources: [{ id: 'r1', capacity: 55 }],
} as Task,
]
const conflicts = detectConflicts(tasks, 'r1')
// 应该将连续重叠的区域合并
expect(conflicts.length).toBeGreaterThan(0)
expect(conflicts.length).toBeLessThanOrEqual(2)
})
})
})