mirror of
https://github.com/motajs/template.git
synced 2026-09-26 12:50:18 +08:00
test(06-08): cover common direction utils and MapLocIndexer (stage 1)
- add utils.test.ts covering getFaceMovement/degradeFace/nextFaceDirection/fromDirectionString for all directions - add indexer.test.ts covering MapLocIndexer coordinate/index round-trip and setWidth stride
This commit is contained in:
parent
2b6de6df5f
commit
7394a2591c
57
packages-user/data-common/src/common/indexer.test.ts
Normal file
57
packages-user/data-common/src/common/indexer.test.ts
Normal file
@ -0,0 +1,57 @@
|
||||
// 测试 L0 MapLocIndexer 的坐标与索引互转及地图宽度切换
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { MapLocIndexer } from './indexer';
|
||||
|
||||
/** 创建索引器并完成地图宽度设置 */
|
||||
function createIndexer(width: number): MapLocIndexer {
|
||||
const indexer = new MapLocIndexer();
|
||||
indexer.setWidth(width);
|
||||
return indexer;
|
||||
}
|
||||
|
||||
describe('MapLocIndexer', () => {
|
||||
// 验证坐标形式与定位符形式对同一位置返回一致的索引
|
||||
it('agrees between the coordinate and locator forms', () => {
|
||||
const indexer = createIndexer(5);
|
||||
|
||||
expect(indexer.locToIndex(0, 0)).toBe(0);
|
||||
expect(indexer.locToIndex(2, 3)).toBe(17);
|
||||
expect(indexer.locaterToIndex({ x: 2, y: 3 })).toBe(17);
|
||||
expect(indexer.locaterToIndex({ x: 2, y: 3 })).toBe(
|
||||
indexer.locToIndex(2, 3)
|
||||
);
|
||||
});
|
||||
|
||||
// 验证范围内索引可经 indexToLocator 与 locToIndex 无损往返
|
||||
it('round-trips every in-range index back to its locator', () => {
|
||||
const indexer = createIndexer(5);
|
||||
|
||||
for (let index = 0; index < 20; index++) {
|
||||
const locator = indexer.indexToLocator(index);
|
||||
expect(indexer.locToIndex(locator.x, locator.y)).toBe(index);
|
||||
expect(indexer.locaterToIndex(locator)).toBe(index);
|
||||
}
|
||||
});
|
||||
|
||||
// 验证扁平索引按宽度拆分为列与行(含行末与次行首)
|
||||
it('splits a flat index into its column and row', () => {
|
||||
const indexer = createIndexer(4);
|
||||
|
||||
expect(indexer.indexToLocator(0)).toEqual({ x: 0, y: 0 });
|
||||
expect(indexer.indexToLocator(3)).toEqual({ x: 3, y: 0 });
|
||||
expect(indexer.indexToLocator(4)).toEqual({ x: 0, y: 1 });
|
||||
expect(indexer.indexToLocator(9)).toEqual({ x: 1, y: 2 });
|
||||
});
|
||||
|
||||
// 验证 setWidth 改变行步长后,同一坐标映射到新索引
|
||||
it('changes the row stride after setWidth', () => {
|
||||
const indexer = createIndexer(4);
|
||||
|
||||
expect(indexer.locToIndex(1, 2)).toBe(9);
|
||||
|
||||
indexer.setWidth(10);
|
||||
|
||||
expect(indexer.locToIndex(1, 2)).toBe(21);
|
||||
expect(indexer.indexToLocator(21)).toEqual({ x: 1, y: 2 });
|
||||
});
|
||||
});
|
||||
203
packages-user/data-common/src/common/utils.test.ts
Normal file
203
packages-user/data-common/src/common/utils.test.ts
Normal file
@ -0,0 +1,203 @@
|
||||
// 测试 L0 common 朝向工具纯函数:坐标偏移、降级、旋转与字符串解析
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { FaceDirection } from './types';
|
||||
import {
|
||||
degradeFace,
|
||||
fromDirectionString,
|
||||
getFaceMovement,
|
||||
nextFaceDirection
|
||||
} from './utils';
|
||||
|
||||
/** 全部朝向枚举值,用于校验方向表的完整覆盖 */
|
||||
const ALL_DIRECTIONS: readonly FaceDirection[] = [
|
||||
FaceDirection.Unknown,
|
||||
FaceDirection.Left,
|
||||
FaceDirection.Up,
|
||||
FaceDirection.Right,
|
||||
FaceDirection.Down,
|
||||
FaceDirection.LeftUp,
|
||||
FaceDirection.RightUp,
|
||||
FaceDirection.LeftDown,
|
||||
FaceDirection.RightDown
|
||||
];
|
||||
|
||||
/** 每个朝向对应的单步坐标偏移量 */
|
||||
const FACE_MOVEMENTS: readonly [FaceDirection, Loc][] = [
|
||||
[FaceDirection.Unknown, { x: 0, y: 0 }],
|
||||
[FaceDirection.Left, { x: -1, y: 0 }],
|
||||
[FaceDirection.Up, { x: 0, y: -1 }],
|
||||
[FaceDirection.Right, { x: 1, y: 0 }],
|
||||
[FaceDirection.Down, { x: 0, y: 1 }],
|
||||
[FaceDirection.LeftUp, { x: -1, y: -1 }],
|
||||
[FaceDirection.RightUp, { x: 1, y: -1 }],
|
||||
[FaceDirection.LeftDown, { x: -1, y: 1 }],
|
||||
[FaceDirection.RightDown, { x: 1, y: 1 }]
|
||||
];
|
||||
|
||||
describe('getFaceMovement', () => {
|
||||
// 验证全部朝向(含未知)都返回唯一且正确的坐标偏移量
|
||||
it('returns the coordinate offset for every face direction', () => {
|
||||
for (const [dir, movement] of FACE_MOVEMENTS) {
|
||||
expect(getFaceMovement(dir)).toEqual(movement);
|
||||
}
|
||||
expect(FACE_MOVEMENTS.map(item => item[0]).sort()).toEqual(
|
||||
[...ALL_DIRECTIONS].sort()
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('degradeFace', () => {
|
||||
// 验证对角朝向降级为对应的左/右,正交朝向原样返回
|
||||
it('degrades diagonals into their orthogonal direction', () => {
|
||||
expect(degradeFace(FaceDirection.LeftUp)).toBe(FaceDirection.Left);
|
||||
expect(degradeFace(FaceDirection.LeftDown)).toBe(FaceDirection.Left);
|
||||
expect(degradeFace(FaceDirection.RightUp)).toBe(FaceDirection.Right);
|
||||
expect(degradeFace(FaceDirection.RightDown)).toBe(FaceDirection.Right);
|
||||
expect(degradeFace(FaceDirection.Left)).toBe(FaceDirection.Left);
|
||||
expect(degradeFace(FaceDirection.Right)).toBe(FaceDirection.Right);
|
||||
expect(degradeFace(FaceDirection.Up)).toBe(FaceDirection.Up);
|
||||
expect(degradeFace(FaceDirection.Down)).toBe(FaceDirection.Down);
|
||||
});
|
||||
|
||||
// 验证未知朝向默认返回未知,且可经 unknown 参数自定义返回值
|
||||
it('maps unknown to the configurable fallback', () => {
|
||||
expect(degradeFace(FaceDirection.Unknown)).toBe(FaceDirection.Unknown);
|
||||
expect(degradeFace(FaceDirection.Unknown, FaceDirection.Down)).toBe(
|
||||
FaceDirection.Down
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('nextFaceDirection', () => {
|
||||
// 验证四方向顺时针旋转顺序为上→右→下→左
|
||||
it('rotates four directions clockwise', () => {
|
||||
expect(nextFaceDirection(FaceDirection.Up)).toBe(FaceDirection.Right);
|
||||
expect(nextFaceDirection(FaceDirection.Right)).toBe(FaceDirection.Down);
|
||||
expect(nextFaceDirection(FaceDirection.Down)).toBe(FaceDirection.Left);
|
||||
expect(nextFaceDirection(FaceDirection.Left)).toBe(FaceDirection.Up);
|
||||
});
|
||||
|
||||
// 验证四方向逆时针旋转顺序为上→左→下→右
|
||||
it('rotates four directions anticlockwise', () => {
|
||||
expect(nextFaceDirection(FaceDirection.Up, true)).toBe(
|
||||
FaceDirection.Left
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.Left, true)).toBe(
|
||||
FaceDirection.Down
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.Down, true)).toBe(
|
||||
FaceDirection.Right
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.Right, true)).toBe(
|
||||
FaceDirection.Up
|
||||
);
|
||||
});
|
||||
|
||||
// 验证四方向模式下对角朝向同样按九十度旋转
|
||||
it('rotates diagonal directions in four-way mode', () => {
|
||||
expect(nextFaceDirection(FaceDirection.LeftUp)).toBe(
|
||||
FaceDirection.RightUp
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.RightUp)).toBe(
|
||||
FaceDirection.RightDown
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.RightDown)).toBe(
|
||||
FaceDirection.LeftDown
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.LeftDown)).toBe(
|
||||
FaceDirection.LeftUp
|
||||
);
|
||||
});
|
||||
|
||||
// 验证八方向顺时针按四十五度依次推进一整圈
|
||||
it('rotates eight directions clockwise', () => {
|
||||
expect(nextFaceDirection(FaceDirection.Up, false, true)).toBe(
|
||||
FaceDirection.RightUp
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.RightUp, false, true)).toBe(
|
||||
FaceDirection.Right
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.Right, false, true)).toBe(
|
||||
FaceDirection.RightDown
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.RightDown, false, true)).toBe(
|
||||
FaceDirection.Down
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.Down, false, true)).toBe(
|
||||
FaceDirection.LeftDown
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.LeftDown, false, true)).toBe(
|
||||
FaceDirection.Left
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.Left, false, true)).toBe(
|
||||
FaceDirection.LeftUp
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.LeftUp, false, true)).toBe(
|
||||
FaceDirection.Up
|
||||
);
|
||||
});
|
||||
|
||||
// 验证八方向逆时针按四十五度依次回退一整圈
|
||||
it('rotates eight directions anticlockwise', () => {
|
||||
expect(nextFaceDirection(FaceDirection.Up, true, true)).toBe(
|
||||
FaceDirection.LeftUp
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.LeftUp, true, true)).toBe(
|
||||
FaceDirection.Left
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.Left, true, true)).toBe(
|
||||
FaceDirection.LeftDown
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.LeftDown, true, true)).toBe(
|
||||
FaceDirection.Down
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.Down, true, true)).toBe(
|
||||
FaceDirection.RightDown
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.RightDown, true, true)).toBe(
|
||||
FaceDirection.Right
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.Right, true, true)).toBe(
|
||||
FaceDirection.RightUp
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.RightUp, true, true)).toBe(
|
||||
FaceDirection.Up
|
||||
);
|
||||
});
|
||||
|
||||
// 验证未知朝向在所有旋转模式下都原样透传
|
||||
it('passes unknown through every rotation mode', () => {
|
||||
expect(nextFaceDirection(FaceDirection.Unknown)).toBe(
|
||||
FaceDirection.Unknown
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.Unknown, true)).toBe(
|
||||
FaceDirection.Unknown
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.Unknown, false, true)).toBe(
|
||||
FaceDirection.Unknown
|
||||
);
|
||||
expect(nextFaceDirection(FaceDirection.Unknown, true, true)).toBe(
|
||||
FaceDirection.Unknown
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('fromDirectionString', () => {
|
||||
// 验证每个合法朝向字符串都解析为对应枚举值
|
||||
it('parses every direction string', () => {
|
||||
expect(fromDirectionString('left')).toBe(FaceDirection.Left);
|
||||
expect(fromDirectionString('right')).toBe(FaceDirection.Right);
|
||||
expect(fromDirectionString('up')).toBe(FaceDirection.Up);
|
||||
expect(fromDirectionString('down')).toBe(FaceDirection.Down);
|
||||
expect(fromDirectionString('leftup')).toBe(FaceDirection.LeftUp);
|
||||
expect(fromDirectionString('rightup')).toBe(FaceDirection.RightUp);
|
||||
expect(fromDirectionString('leftdown')).toBe(FaceDirection.LeftDown);
|
||||
expect(fromDirectionString('rightdown')).toBe(FaceDirection.RightDown);
|
||||
});
|
||||
|
||||
// 验证无法识别的字符串回退为未知朝向
|
||||
it('falls back to unknown for an unrecognized string', () => {
|
||||
const invalid = 'sideways' as Dir2;
|
||||
expect(fromDirectionString(invalid)).toBe(FaceDirection.Unknown);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user