mirror of
https://github.com/motajs/template.git
synced 2026-10-18 04:20:17 +08:00
test(06-06): cover map tile units and event view (stage 1)
- tile.test.ts: MapTileBase num/raw/set, default-event restore, per-tile event view, pointEvent linkage, setFaceDirection binder mapping - staticTile.test.ts: num/raw/set/raw-miss/shouldSave/toDynamic - dynamicTile.test.ts: create warn 143, num/raw/set, setPos, face direction, toStatic/toStaticIfSafe, step, delete - eventView.test.ts: extend per-priority dirty tracking and duplicate priority warn 136
This commit is contained in:
parent
6a6f717b04
commit
4cffe90794
231
packages-user/data-base/src/map/dynamicTile.test.ts
Normal file
231
packages-user/data-base/src/map/dynamicTile.test.ts
Normal file
@ -0,0 +1,231 @@
|
||||
// 测试 DynamicTile 的创建告警、数字与原始数据、位置、朝向、转换和删除
|
||||
import { afterAll, describe, expect, it, vi } from 'vitest';
|
||||
import {
|
||||
type IDataCommon,
|
||||
type IRoleFaceBinder,
|
||||
type ITileRawData,
|
||||
Dir8FaceHandler,
|
||||
FaceDirection,
|
||||
FaceGroup,
|
||||
FaceManager,
|
||||
RoleFaceBinder,
|
||||
TileStore,
|
||||
TileType
|
||||
} from '@user/data-common';
|
||||
import { DirectionMapper, logger } from '@motajs/common';
|
||||
import { type IResizableMapLayer } from './types';
|
||||
import { MapState } from './mapState';
|
||||
import { DynamicTile } from './dynamicTile';
|
||||
|
||||
vi.hoisted(() => {
|
||||
vi.stubGlobal('main', { replayChecking: true });
|
||||
vi.stubGlobal('location', { origin: 'http://localhost' });
|
||||
Map.prototype.getOrInsert ??= function <K, V>(
|
||||
this: Map<K, V>,
|
||||
key: K,
|
||||
value: V
|
||||
): V {
|
||||
const existing = this.get(key);
|
||||
if (existing !== undefined) return existing;
|
||||
this.set(key, value);
|
||||
return value;
|
||||
};
|
||||
Map.prototype.getOrInsertComputed ??= function <K, V>(
|
||||
this: Map<K, V>,
|
||||
key: K,
|
||||
callback: (key: K) => V
|
||||
): V {
|
||||
const existing = this.get(key);
|
||||
if (existing !== undefined) return existing;
|
||||
const value = callback(key);
|
||||
this.set(key, value);
|
||||
return value;
|
||||
};
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
/**
|
||||
* 构造一条最小图块原始数据
|
||||
* @param num 图块数字
|
||||
* @param id 图块字符串 id
|
||||
* @param events 默认事件映射
|
||||
*/
|
||||
function createTileData(
|
||||
num: number,
|
||||
id: string,
|
||||
events: Record<number, string> = {}
|
||||
): ITileRawData {
|
||||
return {
|
||||
num,
|
||||
id,
|
||||
events,
|
||||
type: TileType.Terrain,
|
||||
pass: { onlyEvents: false, outPass: 15, inPass: 15 },
|
||||
eventPass: true
|
||||
};
|
||||
}
|
||||
|
||||
interface DynamicFixture {
|
||||
layer: IResizableMapLayer;
|
||||
roleFace: IRoleFaceBinder;
|
||||
}
|
||||
|
||||
/** 构造一个含单图层的小地图,作为动态图块实例的宿主 */
|
||||
function createFixture(blocks: number[] = [0, 0, 0, 0]): DynamicFixture {
|
||||
const tileStore = new TileStore();
|
||||
tileStore.addTile(createTileData(1, 'base', { 10: 'base-event' }));
|
||||
tileStore.addTile(
|
||||
createTileData(2, 'alternate', { 20: 'alternate-event' })
|
||||
);
|
||||
const roleFace = new RoleFaceBinder();
|
||||
const faceManager = new FaceManager();
|
||||
faceManager.register(FaceGroup.Dir8, new Dir8FaceHandler());
|
||||
const state: IDataCommon = {
|
||||
tileStore,
|
||||
itemStore: {},
|
||||
mapStore: {},
|
||||
eventStore: {},
|
||||
roleFace,
|
||||
faceManager,
|
||||
directionMapper: new DirectionMapper(),
|
||||
saveSystem: {}
|
||||
} as never;
|
||||
const mapState = new MapState(tileStore, state);
|
||||
const map = mapState.fromRaw({
|
||||
floorId: 'F1',
|
||||
width: 2,
|
||||
map: { 0: blocks },
|
||||
layerAlias: { 0: 'event' },
|
||||
events: { 0: {} }
|
||||
})!;
|
||||
return {
|
||||
layer: map.getLayerByAlias('event')! as IResizableMapLayer,
|
||||
roleFace
|
||||
};
|
||||
}
|
||||
|
||||
describe('DynamicTile model', () => {
|
||||
// 验证构造时缺少图块原始数据会告警 143 且 raw 为空
|
||||
it('warns code 143 when the raw tile data is missing', () => {
|
||||
const { layer } = createFixture();
|
||||
|
||||
const result = logger.catch(() => new DynamicTile(99, 0, 0, layer));
|
||||
|
||||
expect(result.info.map(info => info.code)).toContain(143);
|
||||
expect(result.ret.num()).toBe(99);
|
||||
expect(result.ret.raw()).toBeNull();
|
||||
});
|
||||
|
||||
// 验证 num 与 raw 跟随图块存储,set 到未知数字时告警 143
|
||||
it('reflects num and raw and warns 143 on an unknown set', () => {
|
||||
const { layer } = createFixture();
|
||||
const tile = layer.createDynamic(1, 0, 0);
|
||||
|
||||
expect(tile.num()).toBe(1);
|
||||
expect(tile.raw()?.id).toBe('base');
|
||||
|
||||
const result = logger.catch(() => tile.set(99));
|
||||
expect(result.info.map(info => info.code)).toContain(143);
|
||||
expect(tile.num()).toBe(99);
|
||||
expect(tile.raw()).toBeNull();
|
||||
|
||||
tile.set(2);
|
||||
expect(tile.num()).toBe(2);
|
||||
expect(tile.raw()?.id).toBe('alternate');
|
||||
expect(tile.tileEvent().get()).toEqual(
|
||||
new Map([[20, 'alternate-event']])
|
||||
);
|
||||
expect(tile.tileEvent().dirty()).toBe(false);
|
||||
});
|
||||
|
||||
// 验证 setPos 更新坐标并同步图层索引
|
||||
it('updates the position and the layer index through setPos', () => {
|
||||
const { layer } = createFixture();
|
||||
const tile = layer.createDynamic(1, 0, 0);
|
||||
|
||||
tile.setPos(1, 1);
|
||||
|
||||
expect(tile.x).toBe(1);
|
||||
expect(tile.y).toBe(1);
|
||||
expect([...layer.getDynamicTilesAt(1, 1)]).toContain(tile);
|
||||
expect([...layer.getDynamicTilesAt(0, 0)]).toEqual([]);
|
||||
});
|
||||
|
||||
// 验证 getCurrentFaceDirection 依据朝向绑定返回 Unknown 或已绑定朝向
|
||||
it('reads the current face direction from the binder', () => {
|
||||
const { layer, roleFace } = createFixture();
|
||||
const tile = layer.createDynamic(1, 0, 0);
|
||||
|
||||
expect(tile.getCurrentFaceDirection()).toBe(FaceDirection.Unknown);
|
||||
|
||||
roleFace.malloc(1, FaceDirection.Down);
|
||||
expect(tile.getCurrentFaceDirection()).toBe(FaceDirection.Down);
|
||||
|
||||
roleFace.bind(2, 1, FaceDirection.Right);
|
||||
tile.setFaceDirection(FaceDirection.Right);
|
||||
expect(tile.getCurrentFaceDirection()).toBe(FaceDirection.Right);
|
||||
});
|
||||
|
||||
// 验证 toStatic 把动态图块写回静态图层并移出动态索引
|
||||
it('converts back to a static tile and removes it from the dynamic index', () => {
|
||||
const { layer } = createFixture();
|
||||
const tile = layer.createDynamic(1, 0, 0);
|
||||
|
||||
const restored = tile.toStatic();
|
||||
|
||||
expect(restored?.num()).toBe(1);
|
||||
expect(layer.getBlock(0, 0)).toBe(1);
|
||||
expect([...layer.getDynamicTilesAt(0, 0)]).toEqual([]);
|
||||
});
|
||||
|
||||
// 验证 toStatic 覆盖已有静态图块时告警 129
|
||||
it('warns code 129 when toStatic overwrites an existing static tile', () => {
|
||||
const { layer } = createFixture([2, 0, 0, 0]);
|
||||
const tile = layer.createDynamic(1, 0, 0);
|
||||
|
||||
const result = logger.catch(() => tile.toStatic());
|
||||
|
||||
expect(result.info.map(info => info.code)).toContain(129);
|
||||
expect(result.ret?.num()).toBe(1);
|
||||
});
|
||||
|
||||
// 验证 toStaticIfSafe 在目标点被占用时拒绝转换
|
||||
it('refuses toStaticIfSafe when the target cell is occupied', () => {
|
||||
const { layer } = createFixture([2, 0, 0, 0]);
|
||||
const tile = layer.createDynamic(1, 0, 0);
|
||||
|
||||
expect(tile.toStaticIfSafe()).toBeNull();
|
||||
expect(layer.getBlock(0, 0)).toBe(2);
|
||||
expect([...layer.getDynamicTilesAt(0, 0)]).toContain(tile);
|
||||
});
|
||||
|
||||
// 验证 step 返回控制器并在真实计时器下完成移动
|
||||
it('steps through the mover and resolves the controller', async () => {
|
||||
const { layer } = createFixture();
|
||||
const tile = layer.createDynamic(1, 0, 0);
|
||||
|
||||
const controller = tile.step(FaceDirection.Right);
|
||||
expect(controller).not.toBeNull();
|
||||
expect(tile.mover.moving).toBe(true);
|
||||
|
||||
await controller!.onEnd;
|
||||
|
||||
expect(tile.x).toBe(1);
|
||||
expect(tile.y).toBe(0);
|
||||
expect([...layer.getDynamicTilesAt(1, 0)]).toContain(tile);
|
||||
});
|
||||
|
||||
// 验证 delete 异步删除动态图块并清空动态索引
|
||||
it('deletes the dynamic tile and clears the index', async () => {
|
||||
const { layer } = createFixture();
|
||||
const tile = layer.createDynamic(1, 0, 0);
|
||||
|
||||
await tile.delete();
|
||||
|
||||
expect([...layer.getDynamicTilesAt(0, 0)]).toEqual([]);
|
||||
expect([...layer.iterateDynamicTiles()]).toEqual([]);
|
||||
});
|
||||
});
|
||||
@ -1,5 +1,6 @@
|
||||
// 测试 LayerEventView 的参考基准、dirty 状态和恢复行为
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { afterAll, describe, expect, it, vi } from 'vitest';
|
||||
import { logger } from '@motajs/common';
|
||||
import { LayerEventView } from './eventView';
|
||||
|
||||
vi.hoisted(() => {
|
||||
@ -7,6 +8,10 @@ vi.hoisted(() => {
|
||||
vi.stubGlobal('location', { origin: 'http://localhost' });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
describe('LayerEventView reference tracking', () => {
|
||||
// 验证新增、删除和清空事件时 dirty 状态能随参考基准正确变化
|
||||
it('keeps dirty state in sync with set, delete, and clear', () => {
|
||||
@ -49,3 +54,67 @@ describe('LayerEventView reference tracking', () => {
|
||||
expect(view.dirty()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('LayerEventView per-priority dirty tracking', () => {
|
||||
// 验证多个优先级的脏条目按优先级独立增减,互不影响
|
||||
it('tracks dirty entries of different priorities independently', () => {
|
||||
const view = new LayerEventView();
|
||||
view.set(10, 'alpha');
|
||||
view.set(20, 'beta');
|
||||
view.markPure();
|
||||
expect(view.dirty()).toBe(false);
|
||||
|
||||
view.set(10, 'changed');
|
||||
expect(view.dirty()).toBe(true);
|
||||
view.set(10, 'alpha');
|
||||
expect(view.dirty()).toBe(false);
|
||||
|
||||
view.set(30, 'gamma');
|
||||
view.set(40, 'delta');
|
||||
expect(view.dirty()).toBe(true);
|
||||
view.delete(30);
|
||||
expect(view.dirty()).toBe(true);
|
||||
view.delete(40);
|
||||
expect(view.dirty()).toBe(false);
|
||||
});
|
||||
|
||||
// 验证 clear 后逐条恢复参考基准才重新变回 clean
|
||||
it('clears every priority and only becomes clean after restoring all', () => {
|
||||
const view = new LayerEventView();
|
||||
view.set(10, 'alpha');
|
||||
view.set(20, 'beta');
|
||||
view.markPure();
|
||||
|
||||
view.clear();
|
||||
expect(view.get()).toEqual(new Map());
|
||||
expect(view.dirty()).toBe(true);
|
||||
|
||||
view.set(10, 'alpha');
|
||||
expect(view.dirty()).toBe(true);
|
||||
view.set(20, 'beta');
|
||||
expect(view.dirty()).toBe(false);
|
||||
});
|
||||
|
||||
// 验证删除不存在的优先级不会改变脏状态
|
||||
it('ignores deleting an unknown priority', () => {
|
||||
const view = new LayerEventView();
|
||||
view.set(10, 'alpha');
|
||||
view.markPure();
|
||||
|
||||
view.delete(99);
|
||||
|
||||
expect(view.get()).toEqual(new Map([[10, 'alpha']]));
|
||||
expect(view.dirty()).toBe(false);
|
||||
});
|
||||
|
||||
// 验证重复设置同一优先级会告警 136 并覆盖为最新值
|
||||
it('warns code 136 when the same priority is set twice', () => {
|
||||
const view = new LayerEventView();
|
||||
view.set(10, 'first');
|
||||
|
||||
const result = logger.catch(() => view.set(10, 'second'));
|
||||
|
||||
expect(result.info.map(info => info.code)).toContain(136);
|
||||
expect(view.get()).toEqual(new Map([[10, 'second']]));
|
||||
});
|
||||
});
|
||||
|
||||
169
packages-user/data-base/src/map/staticTile.test.ts
Normal file
169
packages-user/data-base/src/map/staticTile.test.ts
Normal file
@ -0,0 +1,169 @@
|
||||
// 测试 StaticTile 的图块数字、原始数据、设置、默认事件与转换为动态图块
|
||||
import { afterAll, describe, expect, it, vi } from 'vitest';
|
||||
import {
|
||||
type IDataCommon,
|
||||
type ITileRawData,
|
||||
Dir8FaceHandler,
|
||||
FaceGroup,
|
||||
FaceManager,
|
||||
RoleFaceBinder,
|
||||
TileStore,
|
||||
TileType
|
||||
} from '@user/data-common';
|
||||
import { DirectionMapper } from '@motajs/common';
|
||||
import { type IResizableMapLayer } from './types';
|
||||
import { MapState } from './mapState';
|
||||
import { StaticTile } from './staticTile';
|
||||
|
||||
vi.hoisted(() => {
|
||||
vi.stubGlobal('main', { replayChecking: true });
|
||||
vi.stubGlobal('location', { origin: 'http://localhost' });
|
||||
Map.prototype.getOrInsert ??= function <K, V>(
|
||||
this: Map<K, V>,
|
||||
key: K,
|
||||
value: V
|
||||
): V {
|
||||
const existing = this.get(key);
|
||||
if (existing !== undefined) return existing;
|
||||
this.set(key, value);
|
||||
return value;
|
||||
};
|
||||
Map.prototype.getOrInsertComputed ??= function <K, V>(
|
||||
this: Map<K, V>,
|
||||
key: K,
|
||||
callback: (key: K) => V
|
||||
): V {
|
||||
const existing = this.get(key);
|
||||
if (existing !== undefined) return existing;
|
||||
const value = callback(key);
|
||||
this.set(key, value);
|
||||
return value;
|
||||
};
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
/**
|
||||
* 构造一条最小图块原始数据
|
||||
* @param num 图块数字
|
||||
* @param id 图块字符串 id
|
||||
* @param events 默认事件映射
|
||||
*/
|
||||
function createTileData(
|
||||
num: number,
|
||||
id: string,
|
||||
events: Record<number, string> = {}
|
||||
): ITileRawData {
|
||||
return {
|
||||
num,
|
||||
id,
|
||||
events,
|
||||
type: TileType.Terrain,
|
||||
pass: { onlyEvents: false, outPass: 15, inPass: 15 },
|
||||
eventPass: true
|
||||
};
|
||||
}
|
||||
|
||||
/** 构造一个含单图层的小地图,作为静态图块实例的宿主 */
|
||||
function createFixture(blocks: number[] = [1, 2, 1, 2]): IResizableMapLayer {
|
||||
const tileStore = new TileStore();
|
||||
tileStore.addTile(createTileData(1, 'base', { 10: 'base-event' }));
|
||||
tileStore.addTile(
|
||||
createTileData(2, 'alternate', { 20: 'alternate-event' })
|
||||
);
|
||||
const faceManager = new FaceManager();
|
||||
faceManager.register(FaceGroup.Dir8, new Dir8FaceHandler());
|
||||
const state: IDataCommon = {
|
||||
tileStore,
|
||||
itemStore: {},
|
||||
mapStore: {},
|
||||
eventStore: {},
|
||||
roleFace: new RoleFaceBinder(),
|
||||
faceManager,
|
||||
directionMapper: new DirectionMapper(),
|
||||
saveSystem: {}
|
||||
} as never;
|
||||
const mapState = new MapState(tileStore, state);
|
||||
const map = mapState.fromRaw({
|
||||
floorId: 'F1',
|
||||
width: 2,
|
||||
map: { 0: blocks },
|
||||
layerAlias: { 0: 'event' },
|
||||
events: { 0: {} }
|
||||
})!;
|
||||
return map.getLayerByAlias('event')! as IResizableMapLayer;
|
||||
}
|
||||
|
||||
describe('StaticTile model', () => {
|
||||
// 验证 num 与 raw 跟随图层图块与图块存储,未知数字返回空原始数据
|
||||
it('reports num and raw from the layer and the tile store', () => {
|
||||
const layer = createFixture();
|
||||
const tile = layer.getTile(0, 0)!;
|
||||
|
||||
expect(tile.num()).toBe(1);
|
||||
expect(tile.raw()?.id).toBe('base');
|
||||
expect(tile.raw()?.num).toBe(1);
|
||||
|
||||
tile.set(2);
|
||||
expect(tile.num()).toBe(2);
|
||||
expect(tile.raw()?.id).toBe('alternate');
|
||||
|
||||
tile.set(99);
|
||||
expect(tile.num()).toBe(99);
|
||||
expect(tile.raw()).toBeNull();
|
||||
});
|
||||
|
||||
// 验证 set 写入图层并恢复新图块默认事件、标记为纯基准
|
||||
it('writes the layer and restores default events on set', () => {
|
||||
const layer = createFixture();
|
||||
const tile = layer.getTile(0, 0)!;
|
||||
|
||||
tile.set(2);
|
||||
|
||||
expect(layer.getBlock(0, 0)).toBe(2);
|
||||
expect(tile.tileEvent().get()).toEqual(
|
||||
new Map([[20, 'alternate-event']])
|
||||
);
|
||||
expect(tile.tileEvent().dirty()).toBe(false);
|
||||
});
|
||||
|
||||
// 验证 shouldSave 仅在事件视图偏离默认基准时为真
|
||||
it('only reports shouldSave when the tile events deviate', () => {
|
||||
const layer = createFixture();
|
||||
const tile = layer.getTile(0, 0)!;
|
||||
|
||||
expect(tile.shouldSave()).toBe(false);
|
||||
|
||||
tile.tileEvent().set(30, 'runtime-event');
|
||||
expect(tile.shouldSave()).toBe(true);
|
||||
|
||||
tile.tileEvent().delete(30);
|
||||
expect(tile.shouldSave()).toBe(false);
|
||||
});
|
||||
|
||||
// 验证 toDynamic 清空静态图块并生成继承默认事件的动态图块
|
||||
it('converts to a dynamic tile and clears the static block', () => {
|
||||
const layer = createFixture();
|
||||
const tile = layer.getTile(0, 0)!;
|
||||
|
||||
const dynamic = tile.toDynamic();
|
||||
|
||||
expect(tile.num()).toBe(0);
|
||||
expect(layer.getBlock(0, 0)).toBe(0);
|
||||
expect(dynamic.num()).toBe(1);
|
||||
expect(dynamic.tileEvent().get()).toEqual(
|
||||
new Map([[10, 'base-event']])
|
||||
);
|
||||
});
|
||||
|
||||
// 验证直接构造越图静态图块时 num 为 -1 且 raw 为空
|
||||
it('reports an out-of-map tile as num -1 with no raw data', () => {
|
||||
const layer = createFixture();
|
||||
const outside = new StaticTile(9, 9, layer);
|
||||
|
||||
expect(outside.num()).toBe(-1);
|
||||
expect(outside.raw()).toBeNull();
|
||||
});
|
||||
});
|
||||
197
packages-user/data-base/src/map/tile.test.ts
Normal file
197
packages-user/data-base/src/map/tile.test.ts
Normal file
@ -0,0 +1,197 @@
|
||||
// 测试 MapTileBase 经静态/动态图块呈现的图块数字、原始数据、默认事件和点位事件联动
|
||||
import { afterAll, describe, expect, it, vi } from 'vitest';
|
||||
import {
|
||||
type IDataCommon,
|
||||
type IRoleFaceBinder,
|
||||
type ITileRawData,
|
||||
Dir8FaceHandler,
|
||||
FaceDirection,
|
||||
FaceGroup,
|
||||
FaceManager,
|
||||
RoleFaceBinder,
|
||||
TileStore,
|
||||
TileType
|
||||
} from '@user/data-common';
|
||||
import { DirectionMapper } from '@motajs/common';
|
||||
import { type IResizableMapLayer } from './types';
|
||||
import { MapState } from './mapState';
|
||||
import { StaticTile } from './staticTile';
|
||||
|
||||
vi.hoisted(() => {
|
||||
vi.stubGlobal('main', { replayChecking: true });
|
||||
vi.stubGlobal('location', { origin: 'http://localhost' });
|
||||
Map.prototype.getOrInsert ??= function <K, V>(
|
||||
this: Map<K, V>,
|
||||
key: K,
|
||||
value: V
|
||||
): V {
|
||||
const existing = this.get(key);
|
||||
if (existing !== undefined) return existing;
|
||||
this.set(key, value);
|
||||
return value;
|
||||
};
|
||||
Map.prototype.getOrInsertComputed ??= function <K, V>(
|
||||
this: Map<K, V>,
|
||||
key: K,
|
||||
callback: (key: K) => V
|
||||
): V {
|
||||
const existing = this.get(key);
|
||||
if (existing !== undefined) return existing;
|
||||
const value = callback(key);
|
||||
this.set(key, value);
|
||||
return value;
|
||||
};
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
/**
|
||||
* 构造一条最小图块原始数据
|
||||
* @param num 图块数字
|
||||
* @param id 图块字符串 id
|
||||
* @param events 默认事件映射
|
||||
*/
|
||||
function createTileData(
|
||||
num: number,
|
||||
id: string,
|
||||
events: Record<number, string> = {}
|
||||
): ITileRawData {
|
||||
return {
|
||||
num,
|
||||
id,
|
||||
events,
|
||||
type: TileType.Terrain,
|
||||
pass: { onlyEvents: false, outPass: 15, inPass: 15 },
|
||||
eventPass: true
|
||||
};
|
||||
}
|
||||
|
||||
interface TileFixture {
|
||||
layer: IResizableMapLayer;
|
||||
roleFace: IRoleFaceBinder;
|
||||
}
|
||||
|
||||
/** 构造一个含单图层的小地图,作为图块实例的宿主 */
|
||||
function createFixture(blocks: number[] = [2, 1, 1, 2]): TileFixture {
|
||||
const tileStore = new TileStore();
|
||||
tileStore.addTile(createTileData(1, 'base', { 10: 'base-event' }));
|
||||
tileStore.addTile(
|
||||
createTileData(2, 'alternate', { 20: 'alternate-event' })
|
||||
);
|
||||
const roleFace = new RoleFaceBinder();
|
||||
const faceManager = new FaceManager();
|
||||
faceManager.register(FaceGroup.Dir8, new Dir8FaceHandler());
|
||||
const state: IDataCommon = {
|
||||
tileStore,
|
||||
itemStore: {},
|
||||
mapStore: {},
|
||||
eventStore: {},
|
||||
roleFace,
|
||||
faceManager,
|
||||
directionMapper: new DirectionMapper(),
|
||||
saveSystem: {}
|
||||
} as never;
|
||||
const mapState = new MapState(tileStore, state);
|
||||
const map = mapState.fromRaw({
|
||||
floorId: 'F1',
|
||||
width: 2,
|
||||
map: { 0: blocks },
|
||||
layerAlias: { 0: 'event' },
|
||||
events: { 0: {} }
|
||||
})!;
|
||||
return {
|
||||
layer: map.getLayerByAlias('event')! as IResizableMapLayer,
|
||||
roleFace
|
||||
};
|
||||
}
|
||||
|
||||
describe('MapTileBase tile identity', () => {
|
||||
// 验证 num/raw/set 始终与图块存储中的数据保持一致
|
||||
it('reflects the tile store through num, raw and set', () => {
|
||||
const { layer } = createFixture();
|
||||
const tile = layer.getTile(0, 0)!;
|
||||
|
||||
expect(tile.num()).toBe(2);
|
||||
expect(tile.raw()?.id).toBe('alternate');
|
||||
|
||||
tile.set(1);
|
||||
expect(tile.num()).toBe(1);
|
||||
expect(tile.raw()?.id).toBe('base');
|
||||
expect(tile.raw()?.num).toBe(1);
|
||||
});
|
||||
|
||||
// 验证 set 切换图块后恢复该图块默认事件并把事件视图标回纯基准
|
||||
it('restores the default events and marks the view pure after set', () => {
|
||||
const { layer } = createFixture();
|
||||
const tile = layer.getTile(0, 0)!;
|
||||
|
||||
expect(tile.tileEvent().get()).toEqual(
|
||||
new Map([[20, 'alternate-event']])
|
||||
);
|
||||
expect(tile.tileEvent().dirty()).toBe(false);
|
||||
|
||||
tile.set(1);
|
||||
expect(tile.tileEvent().get()).toEqual(new Map([[10, 'base-event']]));
|
||||
expect(tile.tileEvent().dirty()).toBe(false);
|
||||
});
|
||||
|
||||
// 验证每个图块实例持有独立的图块事件视图
|
||||
it('keeps a tile event view per tile instance', () => {
|
||||
const { layer } = createFixture();
|
||||
const first = layer.getTile(0, 0)!;
|
||||
const second = layer.getTile(1, 0)!;
|
||||
|
||||
first.tileEvent().set(30, 'first-only');
|
||||
|
||||
expect(second.tileEvent().get()).toEqual(new Map([[10, 'base-event']]));
|
||||
expect(second.tileEvent().dirty()).toBe(false);
|
||||
});
|
||||
|
||||
// 验证 pointEvent 返回该图块坐标的层点位视图,越图时返回 null
|
||||
it('delegates pointEvent to the layer view and returns null outside the map', () => {
|
||||
const { layer } = createFixture();
|
||||
const tile = layer.getTile(0, 0)!;
|
||||
|
||||
expect(tile.pointEvent()).toBe(layer.event(0, 0));
|
||||
layer.event(0, 0)!.set(5, 'point-event');
|
||||
expect(tile.pointEvent()!.get()).toEqual(new Map([[5, 'point-event']]));
|
||||
|
||||
const outside = new StaticTile(5, 5, layer);
|
||||
expect(outside.pointEvent()).toBeNull();
|
||||
});
|
||||
|
||||
// 验证 setFaceDirection 经朝向绑定器映射并返回映射后的图块数字
|
||||
it('maps the face direction through the binder and returns the new num', () => {
|
||||
const { layer, roleFace } = createFixture([1, 1, 1, 1]);
|
||||
roleFace.malloc(1, FaceDirection.Down);
|
||||
roleFace.bind(2, 1, FaceDirection.Right);
|
||||
const tile = layer.getTile(0, 0)!;
|
||||
|
||||
expect(tile.setFaceDirection(FaceDirection.Right)).toBe(2);
|
||||
expect(tile.num()).toBe(2);
|
||||
|
||||
expect(tile.setFaceDirection(FaceDirection.Up)).toBe(2);
|
||||
expect(tile.num()).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('MapTileBase on dynamic tiles', () => {
|
||||
// 验证动态图块的 num/raw/set 与设置后默认事件恢复和静态图块一致
|
||||
it('reflects num, raw and default events on a dynamic tile', () => {
|
||||
const { layer } = createFixture([0, 0, 0, 0]);
|
||||
const tile = layer.createDynamic(1, 0, 0);
|
||||
|
||||
expect(tile.num()).toBe(1);
|
||||
expect(tile.raw()?.id).toBe('base');
|
||||
|
||||
tile.set(2);
|
||||
expect(tile.num()).toBe(2);
|
||||
expect(tile.raw()?.id).toBe('alternate');
|
||||
expect(tile.tileEvent().get()).toEqual(
|
||||
new Map([[20, 'alternate-event']])
|
||||
);
|
||||
expect(tile.tileEvent().dirty()).toBe(false);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user