feat: implement RoleHandler with abstract methods for destroy and run

This commit is contained in:
2026-04-24 00:44:07 -03:00
parent 4b6149da21
commit 754c6a1313
7 changed files with 194 additions and 18 deletions

View File

@@ -125,6 +125,32 @@ describe('UpgraderHandler', () => {
expect(memory.previousDestination).toBeUndefined();
});
it('releases both destination and previousDestination source spots when both are set', () => {
const { state, memory } = createFixture({
memory: {
destination: { type: 'source', id: 'src1', sourceSpot: 0 },
previousDestination: {
type: 'source',
id: 'src1',
sourceSpot: 3,
},
},
});
state.sourcesStates['src1'].spots[0] = PositionSpotStatus.OCCUPIED;
state.sourcesStates['src1'].spots[3] = PositionSpotStatus.OCCUPIED;
UpgraderHandler.destroy(memory, state);
expect(state.sourcesStates['src1'].spots[0]).toBe(
PositionSpotStatus.EMPTY
);
expect(state.sourcesStates['src1'].spots[3]).toBe(
PositionSpotStatus.EMPTY
);
expect(memory.destination).toBeUndefined();
expect(memory.previousDestination).toBeUndefined();
});
it('does nothing when destination is not a source', () => {
const { state, memory } = createFixture({
memory: {
@@ -148,6 +174,21 @@ describe('UpgraderHandler', () => {
expect(() => UpgraderHandler.destroy(memory, state)).not.toThrow();
});
it('does not throw when destination source ID is missing from state', () => {
const { state, memory } = createFixture({
memory: {
destination: {
type: 'source',
id: 'nonexistent',
sourceSpot: 0,
},
},
});
expect(() => UpgraderHandler.destroy(memory, state)).not.toThrow();
expect(memory.destination).toBeUndefined();
});
});
describe('validateCreepMemory (via run)', () => {
@@ -173,7 +214,7 @@ describe('UpgraderHandler', () => {
});
it('transitions from source to controller destination when energy is full', () => {
const { state, controller, creep, mockSource, mockController } =
const { state, controller, creep, mockController } =
createFixture({
memory: {
destination: {
@@ -186,7 +227,7 @@ describe('UpgraderHandler', () => {
storeCapacity: 50,
controllerInRoom: { id: 'ctrl1' } as StructureController,
});
mockSource();
// getSourceById is not called in this path — only getControllerById is needed
mockController(controller);
UpgraderHandler.run(creep, state);
@@ -230,6 +271,13 @@ describe('UpgraderHandler', () => {
UpgraderHandler.run(creep, state);
expect(creep.memory.destination).toBeUndefined();
// previousDestination is set to the old source before checking room.controller,
// so the source spot can be released on the next tick
expect(creep.memory.previousDestination).toEqual({
type: 'source',
id: 'src1',
sourceSpot: 0,
});
});
});
@@ -257,6 +305,19 @@ describe('UpgraderHandler', () => {
expect(creep.memory.destination).toBeUndefined();
});
it('marks the assigned source spot as OCCUPIED in state', () => {
const { state, creep, mockSource } = createFixture();
mockSource();
UpgraderHandler.run(creep, state);
const spotIndex = (creep.memory.destination as any)?.sourceSpot;
expect(spotIndex).toBeDefined();
expect(state.sourcesStates['src1'].spots[spotIndex]).toBe(
PositionSpotStatus.OCCUPIED
);
});
});
describe('onSourceDestination', () => {
@@ -291,6 +352,26 @@ describe('UpgraderHandler', () => {
expect(creep.moveTo).toHaveBeenCalled();
});
it('moves to the computed spot position (not source pos) when not in range', () => {
const { state, creep, mockSource } = createFixture({
memory: {
destination: { type: 'source', id: 'src1', sourceSpot: 0 },
},
});
mockSource();
(creep.harvest as jest.Mock).mockReturnValue(
(global as any).ERR_NOT_IN_RANGE
);
UpgraderHandler.run(creep, state);
expect(creep.moveTo).toHaveBeenCalledWith(
// spot 0 → delta (-1,-1) from source pos (5,5) → (4,4)
expect.objectContaining({ x: 4, y: 4, roomName: 'W1N1' }),
expect.objectContaining({ reusePath: 10 })
);
});
it('logs and returns when source is not found', () => {
const { state, creep, mockSource } = createFixture({
memory: {
@@ -365,4 +446,15 @@ describe('UpgraderHandler', () => {
expect(creep.upgradeController).not.toHaveBeenCalled();
});
});
describe('run', () => {
it('returns the state object', () => {
const { state, creep, mockSource } = createFixture();
mockSource(null);
const result = UpgraderHandler.run(creep, state);
expect(result).toBe(state);
});
});
});