2024-01-10 16:36:19 +01:00
|
|
|
import { mock } from "jest-mock-extended";
|
2024-02-06 17:35:22 +01:00
|
|
|
import { Observable, map } from "rxjs";
|
2024-01-04 20:47:49 +01:00
|
|
|
|
2023-11-29 15:59:50 +01:00
|
|
|
import {
|
|
|
|
GlobalState,
|
|
|
|
GlobalStateProvider,
|
|
|
|
KeyDefinition,
|
2023-12-05 16:20:16 +01:00
|
|
|
ActiveUserState,
|
|
|
|
SingleUserState,
|
2023-12-18 13:50:04 +01:00
|
|
|
SingleUserStateProvider,
|
|
|
|
StateProvider,
|
|
|
|
ActiveUserStateProvider,
|
2024-01-04 20:47:49 +01:00
|
|
|
DerivedState,
|
|
|
|
DeriveDefinition,
|
|
|
|
DerivedStateProvider,
|
2024-02-26 17:28:40 +01:00
|
|
|
UserKeyDefinition,
|
2023-11-29 15:59:50 +01:00
|
|
|
} from "../src/platform/state";
|
2023-12-05 16:20:16 +01:00
|
|
|
import { UserId } from "../src/types/guid";
|
2024-01-04 22:50:55 +01:00
|
|
|
import { DerivedStateDependencies } from "../src/types/state";
|
2023-11-29 15:59:50 +01:00
|
|
|
|
2024-01-10 16:36:19 +01:00
|
|
|
import { FakeAccountService } from "./fake-account-service";
|
2024-01-04 20:47:49 +01:00
|
|
|
import {
|
|
|
|
FakeActiveUserState,
|
|
|
|
FakeDerivedState,
|
|
|
|
FakeGlobalState,
|
|
|
|
FakeSingleUserState,
|
|
|
|
} from "./fake-state";
|
2023-11-29 15:59:50 +01:00
|
|
|
|
|
|
|
export class FakeGlobalStateProvider implements GlobalStateProvider {
|
2024-01-10 16:36:19 +01:00
|
|
|
mock = mock<GlobalStateProvider>();
|
|
|
|
establishedMocks: Map<string, FakeGlobalState<unknown>> = new Map();
|
2023-12-05 16:20:16 +01:00
|
|
|
states: Map<string, GlobalState<unknown>> = new Map();
|
2023-11-29 15:59:50 +01:00
|
|
|
get<T>(keyDefinition: KeyDefinition<T>): GlobalState<T> {
|
2024-01-10 16:36:19 +01:00
|
|
|
this.mock.get(keyDefinition);
|
2024-03-05 18:30:40 +01:00
|
|
|
const cacheKey = `${keyDefinition.fullName}_${keyDefinition.stateDefinition.defaultStorageLocation}`;
|
|
|
|
let result = this.states.get(cacheKey);
|
2023-11-29 15:59:50 +01:00
|
|
|
|
|
|
|
if (result == null) {
|
2024-01-10 16:36:19 +01:00
|
|
|
let fake: FakeGlobalState<T>;
|
|
|
|
// Look for established mock
|
|
|
|
if (this.establishedMocks.has(keyDefinition.key)) {
|
|
|
|
fake = this.establishedMocks.get(keyDefinition.key) as FakeGlobalState<T>;
|
|
|
|
} else {
|
|
|
|
fake = new FakeGlobalState<T>();
|
|
|
|
}
|
|
|
|
fake.keyDefinition = keyDefinition;
|
|
|
|
result = fake;
|
2024-03-05 18:30:40 +01:00
|
|
|
this.states.set(cacheKey, result);
|
2024-01-10 16:36:19 +01:00
|
|
|
|
2023-11-29 15:59:50 +01:00
|
|
|
result = new FakeGlobalState<T>();
|
2024-03-05 18:30:40 +01:00
|
|
|
this.states.set(cacheKey, result);
|
2023-11-29 15:59:50 +01:00
|
|
|
}
|
2024-01-10 16:36:19 +01:00
|
|
|
return result as GlobalState<T>;
|
2023-11-29 15:59:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
getFake<T>(keyDefinition: KeyDefinition<T>): FakeGlobalState<T> {
|
2023-12-05 16:20:16 +01:00
|
|
|
return this.get(keyDefinition) as FakeGlobalState<T>;
|
2023-11-29 15:59:50 +01:00
|
|
|
}
|
2024-01-10 16:36:19 +01:00
|
|
|
|
|
|
|
mockFor<T>(keyDefinitionKey: string, initialValue?: T): FakeGlobalState<T> {
|
|
|
|
if (!this.establishedMocks.has(keyDefinitionKey)) {
|
|
|
|
this.establishedMocks.set(keyDefinitionKey, new FakeGlobalState<T>(initialValue));
|
|
|
|
}
|
|
|
|
return this.establishedMocks.get(keyDefinitionKey) as FakeGlobalState<T>;
|
|
|
|
}
|
2023-11-29 15:59:50 +01:00
|
|
|
}
|
|
|
|
|
2023-12-18 13:50:04 +01:00
|
|
|
export class FakeSingleUserStateProvider implements SingleUserStateProvider {
|
2024-01-10 16:36:19 +01:00
|
|
|
mock = mock<SingleUserStateProvider>();
|
|
|
|
establishedMocks: Map<string, FakeSingleUserState<unknown>> = new Map();
|
2023-12-05 16:20:16 +01:00
|
|
|
states: Map<string, SingleUserState<unknown>> = new Map();
|
2024-02-26 17:28:40 +01:00
|
|
|
get<T>(
|
|
|
|
userId: UserId,
|
|
|
|
keyDefinition: KeyDefinition<T> | UserKeyDefinition<T>,
|
|
|
|
): SingleUserState<T> {
|
2024-01-10 16:36:19 +01:00
|
|
|
this.mock.get(userId, keyDefinition);
|
2024-02-26 17:28:40 +01:00
|
|
|
if (keyDefinition instanceof KeyDefinition) {
|
|
|
|
keyDefinition = UserKeyDefinition.fromBaseKeyDefinition(keyDefinition);
|
|
|
|
}
|
2024-03-05 18:30:40 +01:00
|
|
|
const cacheKey = `${keyDefinition.fullName}_${keyDefinition.stateDefinition.defaultStorageLocation}_${userId}`;
|
|
|
|
let result = this.states.get(cacheKey);
|
2023-11-29 15:59:50 +01:00
|
|
|
|
|
|
|
if (result == null) {
|
2024-01-10 16:36:19 +01:00
|
|
|
let fake: FakeSingleUserState<T>;
|
|
|
|
// Look for established mock
|
|
|
|
if (this.establishedMocks.has(keyDefinition.key)) {
|
|
|
|
fake = this.establishedMocks.get(keyDefinition.key) as FakeSingleUserState<T>;
|
|
|
|
} else {
|
|
|
|
fake = new FakeSingleUserState<T>(userId);
|
|
|
|
}
|
|
|
|
fake.keyDefinition = keyDefinition;
|
|
|
|
result = fake;
|
2024-03-05 18:30:40 +01:00
|
|
|
this.states.set(cacheKey, result);
|
2023-11-29 15:59:50 +01:00
|
|
|
}
|
2024-01-10 16:36:19 +01:00
|
|
|
return result as SingleUserState<T>;
|
2023-11-29 15:59:50 +01:00
|
|
|
}
|
|
|
|
|
2023-12-05 16:20:16 +01:00
|
|
|
getFake<T>(userId: UserId, keyDefinition: KeyDefinition<T>): FakeSingleUserState<T> {
|
|
|
|
return this.get(userId, keyDefinition) as FakeSingleUserState<T>;
|
|
|
|
}
|
2024-01-10 16:36:19 +01:00
|
|
|
|
|
|
|
mockFor<T>(userId: UserId, keyDefinitionKey: string, initialValue?: T): FakeSingleUserState<T> {
|
|
|
|
if (!this.establishedMocks.has(keyDefinitionKey)) {
|
|
|
|
this.establishedMocks.set(keyDefinitionKey, new FakeSingleUserState<T>(userId, initialValue));
|
|
|
|
}
|
|
|
|
return this.establishedMocks.get(keyDefinitionKey) as FakeSingleUserState<T>;
|
|
|
|
}
|
2023-12-05 16:20:16 +01:00
|
|
|
}
|
|
|
|
|
2023-12-18 13:50:04 +01:00
|
|
|
export class FakeActiveUserStateProvider implements ActiveUserStateProvider {
|
2024-02-06 17:35:22 +01:00
|
|
|
activeUserId$: Observable<UserId>;
|
2024-01-10 16:36:19 +01:00
|
|
|
establishedMocks: Map<string, FakeActiveUserState<unknown>> = new Map();
|
|
|
|
|
|
|
|
states: Map<string, FakeActiveUserState<unknown>> = new Map();
|
|
|
|
|
2024-02-06 17:35:22 +01:00
|
|
|
constructor(public accountService: FakeAccountService) {
|
|
|
|
this.activeUserId$ = accountService.activeAccountSubject.asObservable().pipe(map((a) => a.id));
|
|
|
|
}
|
2024-01-10 16:36:19 +01:00
|
|
|
|
2024-02-26 17:28:40 +01:00
|
|
|
get<T>(keyDefinition: KeyDefinition<T> | UserKeyDefinition<T>): ActiveUserState<T> {
|
|
|
|
if (keyDefinition instanceof KeyDefinition) {
|
|
|
|
keyDefinition = UserKeyDefinition.fromBaseKeyDefinition(keyDefinition);
|
|
|
|
}
|
2024-03-05 18:30:40 +01:00
|
|
|
const cacheKey = `${keyDefinition.fullName}_${keyDefinition.stateDefinition.defaultStorageLocation}`;
|
|
|
|
let result = this.states.get(cacheKey);
|
2023-12-05 16:20:16 +01:00
|
|
|
|
|
|
|
if (result == null) {
|
2024-01-10 16:36:19 +01:00
|
|
|
// Look for established mock
|
|
|
|
if (this.establishedMocks.has(keyDefinition.key)) {
|
|
|
|
result = this.establishedMocks.get(keyDefinition.key);
|
|
|
|
} else {
|
|
|
|
result = new FakeActiveUserState<T>(this.accountService);
|
|
|
|
}
|
|
|
|
result.keyDefinition = keyDefinition;
|
2024-03-05 18:30:40 +01:00
|
|
|
this.states.set(cacheKey, result);
|
2023-12-05 16:20:16 +01:00
|
|
|
}
|
2024-01-10 16:36:19 +01:00
|
|
|
return result as ActiveUserState<T>;
|
2023-12-05 16:20:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
getFake<T>(keyDefinition: KeyDefinition<T>): FakeActiveUserState<T> {
|
|
|
|
return this.get(keyDefinition) as FakeActiveUserState<T>;
|
2023-11-29 15:59:50 +01:00
|
|
|
}
|
2024-01-10 16:36:19 +01:00
|
|
|
|
|
|
|
mockFor<T>(keyDefinitionKey: string, initialValue?: T): FakeActiveUserState<T> {
|
|
|
|
if (!this.establishedMocks.has(keyDefinitionKey)) {
|
|
|
|
this.establishedMocks.set(
|
|
|
|
keyDefinitionKey,
|
|
|
|
new FakeActiveUserState<T>(this.accountService, initialValue),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return this.establishedMocks.get(keyDefinitionKey) as FakeActiveUserState<T>;
|
|
|
|
}
|
2023-11-29 15:59:50 +01:00
|
|
|
}
|
2023-12-18 13:50:04 +01:00
|
|
|
|
|
|
|
export class FakeStateProvider implements StateProvider {
|
2024-02-22 21:07:26 +01:00
|
|
|
mock = mock<StateProvider>();
|
2024-02-06 17:35:22 +01:00
|
|
|
getUserState$<T>(keyDefinition: KeyDefinition<T>, userId?: UserId): Observable<T> {
|
2024-02-22 21:07:26 +01:00
|
|
|
this.mock.getUserState$(keyDefinition, userId);
|
2024-02-06 17:35:22 +01:00
|
|
|
if (userId) {
|
|
|
|
return this.getUser<T>(userId, keyDefinition).state$;
|
|
|
|
}
|
|
|
|
return this.getActive<T>(keyDefinition).state$;
|
|
|
|
}
|
|
|
|
|
2024-02-08 20:54:15 +01:00
|
|
|
async setUserState<T>(
|
2024-02-26 17:28:40 +01:00
|
|
|
keyDefinition: KeyDefinition<T> | UserKeyDefinition<T>,
|
2024-02-08 20:54:15 +01:00
|
|
|
value: T,
|
|
|
|
userId?: UserId,
|
|
|
|
): Promise<[UserId, T]> {
|
2024-02-22 21:07:26 +01:00
|
|
|
await this.mock.setUserState(keyDefinition, value, userId);
|
2024-02-06 17:35:22 +01:00
|
|
|
if (userId) {
|
2024-02-08 20:54:15 +01:00
|
|
|
return [userId, await this.getUser(userId, keyDefinition).update(() => value)];
|
2024-02-06 17:35:22 +01:00
|
|
|
} else {
|
2024-02-08 20:54:15 +01:00
|
|
|
return await this.getActive(keyDefinition).update(() => value);
|
2024-02-06 17:35:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-26 17:28:40 +01:00
|
|
|
getActive<T>(keyDefinition: KeyDefinition<T> | UserKeyDefinition<T>): ActiveUserState<T> {
|
2023-12-18 13:50:04 +01:00
|
|
|
return this.activeUser.get(keyDefinition);
|
|
|
|
}
|
|
|
|
|
|
|
|
getGlobal<T>(keyDefinition: KeyDefinition<T>): GlobalState<T> {
|
|
|
|
return this.global.get(keyDefinition);
|
|
|
|
}
|
|
|
|
|
2024-02-26 17:28:40 +01:00
|
|
|
getUser<T>(
|
|
|
|
userId: UserId,
|
|
|
|
keyDefinition: KeyDefinition<T> | UserKeyDefinition<T>,
|
|
|
|
): SingleUserState<T> {
|
2023-12-18 13:50:04 +01:00
|
|
|
return this.singleUser.get(userId, keyDefinition);
|
|
|
|
}
|
|
|
|
|
2024-01-04 20:47:49 +01:00
|
|
|
getDerived<TFrom, TTo, TDeps extends DerivedStateDependencies>(
|
|
|
|
parentState$: Observable<TFrom>,
|
|
|
|
deriveDefinition: DeriveDefinition<unknown, TTo, TDeps>,
|
2024-01-04 22:50:55 +01:00
|
|
|
dependencies: TDeps,
|
2024-01-04 20:47:49 +01:00
|
|
|
): DerivedState<TTo> {
|
|
|
|
return this.derived.get(parentState$, deriveDefinition, dependencies);
|
|
|
|
}
|
|
|
|
|
2024-01-10 16:36:19 +01:00
|
|
|
constructor(public accountService: FakeAccountService) {}
|
|
|
|
|
2023-12-18 13:50:04 +01:00
|
|
|
global: FakeGlobalStateProvider = new FakeGlobalStateProvider();
|
|
|
|
singleUser: FakeSingleUserStateProvider = new FakeSingleUserStateProvider();
|
2024-01-10 16:36:19 +01:00
|
|
|
activeUser: FakeActiveUserStateProvider = new FakeActiveUserStateProvider(this.accountService);
|
2024-01-04 20:47:49 +01:00
|
|
|
derived: FakeDerivedStateProvider = new FakeDerivedStateProvider();
|
2024-02-06 17:35:22 +01:00
|
|
|
activeUserId$: Observable<UserId> = this.activeUser.activeUserId$;
|
2024-01-04 20:47:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
export class FakeDerivedStateProvider implements DerivedStateProvider {
|
|
|
|
states: Map<string, DerivedState<unknown>> = new Map();
|
|
|
|
get<TFrom, TTo, TDeps extends DerivedStateDependencies>(
|
|
|
|
parentState$: Observable<TFrom>,
|
|
|
|
deriveDefinition: DeriveDefinition<TFrom, TTo, TDeps>,
|
2024-01-04 22:50:55 +01:00
|
|
|
dependencies: TDeps,
|
2024-01-04 20:47:49 +01:00
|
|
|
): DerivedState<TTo> {
|
|
|
|
let result = this.states.get(deriveDefinition.buildCacheKey()) as DerivedState<TTo>;
|
|
|
|
|
|
|
|
if (result == null) {
|
2024-02-13 21:26:56 +01:00
|
|
|
result = new FakeDerivedState(parentState$, deriveDefinition, dependencies);
|
2024-01-04 20:47:49 +01:00
|
|
|
this.states.set(deriveDefinition.buildCacheKey(), result);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
2023-12-18 13:50:04 +01:00
|
|
|
}
|