implements typed identifiers

This commit is contained in:
Robin Chappatte
2024-06-12 18:13:15 +02:00
parent b654a3b26f
commit c60af59bec
4 changed files with 112 additions and 155 deletions

View File

@@ -3,89 +3,75 @@ import {
assertThrows,
} from 'https://deno.land/std@0.224.0/assert/mod.ts';
import { DependencyManager, Provider } from './dependency-manager.ts';
import { Identifier, Manager, Provider } from './dependency-manager.ts';
Deno.test('should register and resolve a simple dependency', () => {
const manager = new DependencyManager();
Deno.test('provide: should throw error when an identifier is reused', () => {
const value = 'test';
const identifier = Symbol() as Identifier<typeof value>;
const dependency = () => 'test';
manager.register(dependency);
const manager = new Manager();
manager.register(identifier, () => value);
const resolved = manager.resolve(dependency);
assertEquals(resolved, 'test');
assertThrows(
() => manager.register(identifier, () => value),
Error,
);
});
Deno.test('should register and resolve a module with multiple dependencies', () => {
const manager = new DependencyManager();
Deno.test('provide: should throw error when resolving a non-registered dependency', () => {
const identifier = Symbol();
const manager = new Manager();
const module = {
a: () => 'test1',
b: () => 42,
assertThrows(
() => manager.inject(identifier),
Error,
);
});
Deno.test('inject: should return the provided value (stand-alone injectable)', () => {
const value = 'foo';
const identifier = Symbol() as Identifier<typeof value>;
const manager = new Manager();
manager.register(identifier, () => value);
const resolved = manager.inject(identifier);
assertEquals(resolved, 'foo');
});
Deno.test('inject: should return the expected value (injectable with dependencies)', () => {
const providerA = () => 'a';
const identifierA = Symbol() as Identifier<ReturnType<typeof providerA>>;
const providerB = (m: Manager) => {
const a = manager.inject(identifierA);
return `-${a}-`;
};
const identifierB = Symbol() as Identifier<ReturnType<typeof providerB>>;
manager.register(module);
const manager = new Manager();
manager.register(identifierA, providerA);
manager.register(identifierB, providerB);
const a = manager.resolve(module.a);
const b = manager.resolve(module.b);
const b = manager.inject(identifierB);
assertEquals(a, 'test1');
assertEquals(b, 42);
assertEquals(b, '-a-');
});
Deno.test('should throw error when registering the same dependency twice', () => {
const manager = new DependencyManager();
Deno.test('inject: should throw error when detecting a circular dependency', () => {
const identifierA = Symbol();
const identifierB = Symbol();
const dependency = () => 'test';
manager.register(dependency);
const providerA = (manager: Manager) => manager.inject(identifierB);
const providerB = (manager: Manager) => manager.inject(identifierA);
const manager = new Manager();
manager.register(identifierA, providerA);
manager.register(identifierB, providerB);
assertThrows(
() => manager.register(dependency),
() => manager.inject(identifierA),
Error,
'This dependency or module has already been registered',
);
});
Deno.test('should throw error when resolving a non-registered dependency', () => {
const manager = new DependencyManager();
const dependency = () => 'test';
assertThrows(
() => manager.resolve(dependency),
Error,
'This key has not (yet ?) been used to register something',
);
});
Deno.test('should resolve dependency recursively (when not circular)', () => {
const manager = new DependencyManager();
const dependencyA = () => 'A';
const dependencyB = (manager: DependencyManager) =>
manager.resolve(dependencyA);
manager.register(dependencyA);
manager.register(dependencyB);
const b = manager.resolve(dependencyB);
assertEquals(b, 'A');
});
Deno.test('should throw error when detecting a circular dependency', () => {
const manager = new DependencyManager();
const dependencyA: Provider<string> = (manager) =>
manager.resolve(dependencyB);
const dependencyB: Provider<string> = (manager) =>
manager.resolve(dependencyA);
manager.register(dependencyA);
manager.register(dependencyB);
assertThrows(
() => manager.resolve(dependencyA),
Error,
'Circular dependency detected',
);
});