Merge remote-tracking branch 'origin/master' into issue-94-响应式查询(Reactive_Query_System)/_Event-driven_Query

This commit is contained in:
YHH
2025-10-13 23:36:12 +08:00
5 changed files with 747 additions and 40 deletions

View File

@@ -0,0 +1,668 @@
import { Core } from '../src/Core';
import { Scene } from '../src/ECS/Scene';
import { DebugManager } from '../src/Utils/Debug/DebugManager';
import { DebugConfigService } from '../src/Utils/Debug/DebugConfigService';
import { IECSDebugConfig } from '../src/Types';
import { createLogger } from '../src/Utils/Logger';
const logger = createLogger('DebugManagerTest');
class TestScene extends Scene {
public initializeCalled = false;
public override initialize(): void {
this.initializeCalled = true;
}
public override begin(): void {
}
public override end(): void {
}
}
describe('DebugManager DI Architecture Tests', () => {
let originalConsoleWarn: typeof console.warn;
let originalConsoleError: typeof console.error;
beforeEach(() => {
(Core as any)._instance = null;
originalConsoleWarn = console.warn;
originalConsoleError = console.error;
console.warn = jest.fn();
console.error = jest.fn();
});
afterEach(() => {
console.warn = originalConsoleWarn;
console.error = originalConsoleError;
if (Core.Instance) {
Core.destroy();
}
});
describe('DebugConfigService - Configuration Service', () => {
test('should create with default configuration', () => {
const configService = new DebugConfigService();
const config = configService.getConfig();
expect(config).toBeDefined();
expect(config.enabled).toBe(false);
expect(config.websocketUrl).toBe('');
expect(config.debugFrameRate).toBe(30);
expect(config.autoReconnect).toBe(true);
expect(config.channels).toBeDefined();
});
test('should set and get configuration', () => {
const configService = new DebugConfigService();
const newConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 60,
autoReconnect: false,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
configService.setConfig(newConfig);
const retrievedConfig = configService.getConfig();
expect(retrievedConfig).toEqual(newConfig);
expect(retrievedConfig.enabled).toBe(true);
expect(retrievedConfig.websocketUrl).toBe('ws://localhost:9229');
expect(retrievedConfig.debugFrameRate).toBe(60);
});
test('should return correct enabled status', () => {
const configService = new DebugConfigService();
expect(configService.isEnabled()).toBe(false);
configService.setConfig({
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 30,
autoReconnect: true,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
});
expect(configService.isEnabled()).toBe(true);
});
test('should implement dispose method', () => {
const configService = new DebugConfigService();
expect(() => configService.dispose()).not.toThrow();
});
});
describe('DebugManager - DI Initialization', () => {
test('should initialize DebugManager through DI when debug config is enabled', () => {
const debugConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 30,
autoReconnect: true,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
const core = Core.create({
debug: true,
debugConfig: debugConfig
});
expect((core as any)._debugManager).toBeDefined();
expect((core as any)._debugManager).toBeInstanceOf(DebugManager);
});
test('should not create DebugManager when debug config is disabled', () => {
const core = Core.create({
debug: true,
debugConfig: {
enabled: false,
websocketUrl: '',
debugFrameRate: 30,
autoReconnect: true,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
}
});
expect((core as any)._debugManager).toBeUndefined();
});
test('should not create DebugManager when no debug config provided', () => {
const core = Core.create({ debug: true });
expect((core as any)._debugManager).toBeUndefined();
});
test('should register DebugConfigService in ServiceContainer', () => {
const debugConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 30,
autoReconnect: true,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
Core.create({
debug: true,
debugConfig: debugConfig
});
const configService = Core.services.resolve(DebugConfigService);
expect(configService).toBeDefined();
expect(configService).toBeInstanceOf(DebugConfigService);
});
test('should inject all dependencies correctly', () => {
const debugConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 30,
autoReconnect: true,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
const core = Core.create({
debug: true,
debugConfig: debugConfig
});
const debugManager = (core as any)._debugManager as DebugManager;
expect(debugManager).toBeDefined();
const sceneManager = (debugManager as any).sceneManager;
const performanceMonitor = (debugManager as any).performanceMonitor;
const config = (debugManager as any).config;
expect(sceneManager).toBeDefined();
expect(performanceMonitor).toBeDefined();
expect(config).toBeDefined();
expect(config.enabled).toBe(true);
expect(config.websocketUrl).toBe('ws://localhost:9229');
});
});
describe('Core.enableDebug - Runtime Activation', () => {
test('should enable debug at runtime', () => {
const core = Core.create({ debug: true });
expect(Core.isDebugEnabled).toBe(false);
const debugConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 30,
autoReconnect: true,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
Core.enableDebug(debugConfig);
expect(Core.isDebugEnabled).toBe(true);
expect((core as any)._debugManager).toBeDefined();
});
test('should create DebugConfigService when enabling debug at runtime', () => {
Core.create({ debug: true });
const debugConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 30,
autoReconnect: true,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
Core.enableDebug(debugConfig);
const configService = Core.services.resolve(DebugConfigService);
expect(configService).toBeDefined();
expect(configService.getConfig()).toEqual(debugConfig);
});
test('should update existing DebugManager config when already enabled', () => {
const initialConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 30,
autoReconnect: true,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
Core.create({ debug: true, debugConfig: initialConfig });
const updatedConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:8080',
debugFrameRate: 60,
autoReconnect: false,
channels: {
entities: false,
systems: true,
performance: true,
components: false,
scenes: true
}
};
Core.enableDebug(updatedConfig);
expect(Core.isDebugEnabled).toBe(true);
const debugManager = (Core.Instance as any)._debugManager;
expect(debugManager).toBeDefined();
});
test('should show warning when enabling debug without Core instance', () => {
const debugConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 30,
autoReconnect: true,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
Core.enableDebug(debugConfig);
expect(console.warn).toHaveBeenCalledWith(
expect.stringContaining('Core实例未创建请先调用Core.create()')
);
});
});
describe('Core.disableDebug', () => {
test('should disable debug functionality', () => {
const debugConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 30,
autoReconnect: true,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
Core.create({ debug: true, debugConfig: debugConfig });
expect(Core.isDebugEnabled).toBe(true);
Core.disableDebug();
expect(Core.isDebugEnabled).toBe(false);
expect((Core.Instance as any)._debugManager).toBeUndefined();
});
test('should handle disabling when Core instance does not exist', () => {
expect(() => Core.disableDebug()).not.toThrow();
});
test('should handle disabling when debug was never enabled', () => {
Core.create({ debug: true });
expect(() => Core.disableDebug()).not.toThrow();
});
});
describe('DebugManager - Auto Update Integration', () => {
test('should be registered as updatable service', () => {
const debugConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 30,
autoReconnect: true,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
Core.create({ debug: true, debugConfig: debugConfig });
const serviceContainer = (Core.Instance as any)._serviceContainer;
const updatableCount = serviceContainer.getUpdatableCount();
expect(updatableCount).toBeGreaterThan(0);
});
test('should be updated during Core.update cycle', () => {
const debugConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 30,
autoReconnect: true,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
const core = Core.create({ debug: true, debugConfig: debugConfig });
const debugManager = (core as any)._debugManager as DebugManager;
const updateSpy = jest.spyOn(debugManager, 'update');
Core.update(0.016);
expect(updateSpy).toHaveBeenCalledWith(0.016);
});
});
describe('DebugManager - Scene Integration', () => {
test('should respond to scene changes', () => {
const debugConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 30,
autoReconnect: true,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
const core = Core.create({ debug: true, debugConfig: debugConfig });
const debugManager = (core as any)._debugManager as DebugManager;
const sceneChangeSpy = jest.spyOn(debugManager, 'onSceneChanged');
const testScene = new TestScene();
Core.setScene(testScene);
expect(sceneChangeSpy).toHaveBeenCalled();
});
test('should collect debug data from current scene', () => {
const debugConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 30,
autoReconnect: true,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
Core.create({ debug: true, debugConfig: debugConfig });
const testScene = new TestScene();
Core.setScene(testScene);
const debugData = Core.getDebugData();
expect(debugData).toBeDefined();
expect(debugData).toHaveProperty('timestamp');
expect(debugData).toHaveProperty('frameworkVersion');
expect(debugData).toHaveProperty('currentScene');
});
});
describe('DebugManager - Configuration Management', () => {
test('should use correct debug frame rate', () => {
const debugConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 60,
autoReconnect: true,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
const core = Core.create({ debug: true, debugConfig: debugConfig });
const debugManager = (core as any)._debugManager as DebugManager;
const sendInterval = (debugManager as any).sendInterval;
expect(sendInterval).toBe(1000 / 60);
});
test('should handle channel configuration correctly', () => {
const debugConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 30,
autoReconnect: true,
channels: {
entities: true,
systems: false,
performance: false,
components: true,
scenes: false
}
};
Core.create({ debug: true, debugConfig: debugConfig });
const testScene = new TestScene();
Core.setScene(testScene);
const debugData = Core.getDebugData() as any;
expect(debugData.entities).toBeDefined();
expect(debugData.components).toBeDefined();
expect(debugData.systems).toBeUndefined();
expect(debugData.performance).toBeUndefined();
expect(debugData.scenes).toBeUndefined();
});
});
describe('DebugManager - Lifecycle', () => {
test('should start automatically on creation', () => {
const debugConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 30,
autoReconnect: true,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
const core = Core.create({ debug: true, debugConfig: debugConfig });
const debugManager = (core as any)._debugManager as DebugManager;
const isRunning = (debugManager as any).isRunning;
expect(isRunning).toBe(true);
});
test('should stop when disabling debug', () => {
const debugConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 30,
autoReconnect: true,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
Core.create({ debug: true, debugConfig: debugConfig });
const debugManager = (Core.Instance as any)._debugManager as DebugManager;
const stopSpy = jest.spyOn(debugManager, 'stop');
Core.disableDebug();
expect(stopSpy).toHaveBeenCalled();
});
test('should dispose properly on Core.destroy', () => {
const debugConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 30,
autoReconnect: true,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
Core.create({ debug: true, debugConfig: debugConfig });
const debugManager = (Core.Instance as any)._debugManager as DebugManager;
const stopSpy = jest.spyOn(debugManager, 'stop');
Core.destroy();
expect(stopSpy).toHaveBeenCalled();
});
});
describe('DebugManager - Pure DI Architecture Validation', () => {
test('should resolve all dependencies through ServiceContainer', () => {
const debugConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 30,
autoReconnect: true,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
Core.create({ debug: true, debugConfig: debugConfig });
const debugConfigService = Core.services.resolve(DebugConfigService);
expect(debugConfigService).toBeDefined();
const config = debugConfigService.getConfig();
expect(config).toEqual(debugConfig);
});
test('should not have mixed DI patterns', () => {
const debugConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 30,
autoReconnect: true,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
const core = Core.create({ debug: true, debugConfig: debugConfig });
const debugManager = (core as any)._debugManager as DebugManager;
const sceneManager = (debugManager as any).sceneManager;
const performanceMonitor = (debugManager as any).performanceMonitor;
const config = (debugManager as any).config;
expect(sceneManager).toBeDefined();
expect(performanceMonitor).toBeDefined();
expect(config).toBeDefined();
expect(config.enabled).toBe(true);
});
test('should use factory pattern for registration', () => {
const debugConfig: IECSDebugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:9229',
debugFrameRate: 30,
autoReconnect: true,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
Core.create({ debug: true, debugConfig: debugConfig });
const debugManager1 = (Core.Instance as any)._debugManager;
const debugManager2 = Core.services.resolve(DebugManager);
expect(debugManager1).toBe(debugManager2);
});
});
});