import type { PreferenceDefaultScopeType, PreferenceKeyType } from '@shared/data/preference/preferenceTypes' import { DefaultPreferences } from '@shared/data/preference/preferenceSchemas' import { vi } from 'vitest' /** * Mock PreferenceService for main process testing * Simulates the complete main process PreferenceService functionality */ // Mock preference state storage const mockPreferenceState = new Map() // Initialize with defaults Object.entries(DefaultPreferences.default).forEach(([key, value]) => { mockPreferenceState.set(key as PreferenceKeyType, value) }) // Mock subscription tracking const mockSubscriptions = new Map>() // windowId -> Set const mockMainSubscribers = new Map void>>() // Helper function to notify main process subscribers const notifyMainSubscribers = (key: string, newValue: any, oldValue?: any) => { const subscribers = mockMainSubscribers.get(key) if (subscribers) { subscribers.forEach(callback => { try { callback(newValue, oldValue) } catch (error) { console.warn('Mock PreferenceService: Main subscriber callback error:', error) } }) } } /** * Mock PreferenceService class */ export class MockMainPreferenceService { private static instance: MockMainPreferenceService private initialized = false private constructor() {} public static getInstance(): MockMainPreferenceService { if (!MockMainPreferenceService.instance) { MockMainPreferenceService.instance = new MockMainPreferenceService() } return MockMainPreferenceService.instance } // Mock initialization public initialize = vi.fn(async (): Promise => { this.initialized = true }) // Mock get method public get = vi.fn((key: K): PreferenceDefaultScopeType[K] => { return mockPreferenceState.get(key) ?? DefaultPreferences.default[key] }) // Mock set method public set = vi.fn(async ( key: K, value: PreferenceDefaultScopeType[K] ): Promise => { const oldValue = mockPreferenceState.get(key) mockPreferenceState.set(key, value) notifyMainSubscribers(key, value, oldValue) }) // Mock getMultiple method public getMultiple = vi.fn((keys: K[]) => { const result: any = {} keys.forEach(key => { result[key] = mockPreferenceState.get(key) ?? DefaultPreferences.default[key] }) return result }) // Mock setMultiple method public setMultiple = vi.fn(async (updates: Partial): Promise => { Object.entries(updates).forEach(([key, value]) => { if (value !== undefined) { const oldValue = mockPreferenceState.get(key as PreferenceKeyType) mockPreferenceState.set(key as PreferenceKeyType, value) notifyMainSubscribers(key, value, oldValue) } }) }) // Mock subscription methods public subscribeForWindow = vi.fn((windowId: number, keys: string[]): void => { if (!mockSubscriptions.has(windowId)) { mockSubscriptions.set(windowId, new Set()) } const windowKeys = mockSubscriptions.get(windowId)! keys.forEach(key => windowKeys.add(key)) }) public unsubscribeForWindow = vi.fn((windowId: number): void => { mockSubscriptions.delete(windowId) }) // Mock main process subscription methods public subscribeChange = vi.fn(( key: K, callback: (newValue: PreferenceDefaultScopeType[K], oldValue?: PreferenceDefaultScopeType[K]) => void ): (() => void) => { if (!mockMainSubscribers.has(key)) { mockMainSubscribers.set(key, new Set()) } mockMainSubscribers.get(key)!.add(callback) // Return unsubscribe function return () => { const subscribers = mockMainSubscribers.get(key) if (subscribers) { subscribers.delete(callback) if (subscribers.size === 0) { mockMainSubscribers.delete(key) } } } }) public subscribeMultipleChanges = vi.fn(( keys: PreferenceKeyType[], callback: (key: PreferenceKeyType, newValue: any, oldValue: any) => void ): (() => void) => { const unsubscribeFunctions = keys.map(key => this.subscribeChange(key, (newValue, oldValue) => callback(key, newValue, oldValue)) ) return () => { unsubscribeFunctions.forEach(unsubscribe => unsubscribe()) } }) // Mock utility methods public getAll = vi.fn((): PreferenceDefaultScopeType => { const result: any = {} Object.keys(DefaultPreferences.default).forEach(key => { result[key] = mockPreferenceState.get(key as PreferenceKeyType) ?? DefaultPreferences.default[key as PreferenceKeyType] }) return result }) public getSubscriptions = vi.fn(() => new Map(mockSubscriptions)) public removeAllChangeListeners = vi.fn((): void => { mockMainSubscribers.clear() }) public getChangeListenerCount = vi.fn((): number => { let total = 0 mockMainSubscribers.forEach(subscribers => { total += subscribers.size }) return total }) public getKeyListenerCount = vi.fn((key: PreferenceKeyType): number => { return mockMainSubscribers.get(key)?.size ?? 0 }) public getSubscribedKeys = vi.fn((): string[] => { return Array.from(mockMainSubscribers.keys()) }) public getSubscriptionStats = vi.fn((): Record => { const stats: Record = {} mockMainSubscribers.forEach((subscribers, key) => { stats[key] = subscribers.size }) return stats }) // Static methods public static registerIpcHandler = vi.fn((): void => { // Mock IPC handler registration }) } // Mock singleton instance const mockInstance = MockMainPreferenceService.getInstance() /** * Export mock service */ export const MockMainPreferenceServiceExport = { PreferenceService: MockMainPreferenceService, preferenceService: mockInstance } /** * Utility functions for testing */ export const MockMainPreferenceServiceUtils = { /** * Reset all mock call counts and state */ resetMocks: () => { // Reset all method mocks Object.values(mockInstance).forEach(method => { if (vi.isMockFunction(method)) { method.mockClear() } }) // Reset state to defaults mockPreferenceState.clear() Object.entries(DefaultPreferences.default).forEach(([key, value]) => { mockPreferenceState.set(key as PreferenceKeyType, value) }) // Clear subscriptions mockSubscriptions.clear() mockMainSubscribers.clear() }, /** * Set a preference value for testing */ setPreferenceValue: (key: K, value: PreferenceDefaultScopeType[K]) => { const oldValue = mockPreferenceState.get(key) mockPreferenceState.set(key, value) notifyMainSubscribers(key, value, oldValue) }, /** * Get current preference value */ getPreferenceValue: (key: K): PreferenceDefaultScopeType[K] => { return mockPreferenceState.get(key) ?? DefaultPreferences.default[key] }, /** * Set multiple preference values for testing */ setMultiplePreferenceValues: (values: Record) => { Object.entries(values).forEach(([key, value]) => { const oldValue = mockPreferenceState.get(key as PreferenceKeyType) mockPreferenceState.set(key as PreferenceKeyType, value) notifyMainSubscribers(key, value, oldValue) }) }, /** * Get all current preference values */ getAllPreferenceValues: (): Record => { const result: Record = {} mockPreferenceState.forEach((value, key) => { result[key] = value }) return result }, /** * Simulate window subscription */ simulateWindowSubscription: (windowId: number, keys: string[]) => { mockInstance.subscribeForWindow(windowId, keys) }, /** * Simulate external preference change */ simulateExternalPreferenceChange: (key: K, value: PreferenceDefaultScopeType[K]) => { const oldValue = mockPreferenceState.get(key) mockPreferenceState.set(key, value) notifyMainSubscribers(key, value, oldValue) }, /** * Get subscription counts for debugging */ getSubscriptionCounts: () => ({ windows: Array.from(mockSubscriptions.entries()).map(([windowId, keys]) => [windowId, keys.size]), mainSubscribers: Array.from(mockMainSubscribers.entries()).map(([key, subs]) => [key, subs.size]) }) }