Warning, /firebird/packages/firebird-ng/api/src/lib/geometry-pipeline.spec.ts is written in an unsupported language. File is not indexed.
0001 /**
0002 * The geometry pipeline seams as data: rule contributions merge by name
0003 * (a later name replaces an earlier one), each load selects one rule set and
0004 * one cut list, and post-processors run in registration order with their
0005 * `after` constraints.
0006 */
0007 import {
0008 GeometryPostProcessorRegistration,
0009 RootGeometryRules,
0010 orderGeometryPostProcessors,
0011 resolveRootGeometryRules,
0012 selectRootGeometryLoadRules,
0013 } from './geometry-pipeline';
0014
0015 const removeBeam: RootGeometryRules = { cutLists: { central: { label: 'Central', remove: ['Beam'] } } };
0016
0017 describe('pre-build TGeo rules', () => {
0018 it('merges contributions in order; a later name replaces an earlier one', async () => {
0019 const rules = await resolveRootGeometryRules([
0020 removeBeam,
0021 { editRules: { default: { detectors: [{ namePattern: '*/A*', editRules: [] }] } } },
0022 // A dynamic import, the way a pack keeps rule data out of the initial bundle
0023 () => Promise.resolve<RootGeometryRules>({ cutLists: { central: { remove: ['Beam', 'Far'] }, beamline: { remove: ['Q'] } } }),
0024 ]);
0025 expect(rules.cutLists).toEqual({ central: { remove: ['Beam', 'Far'] }, beamline: { remove: ['Q'] } });
0026 expect(Object.keys(rules.editRules ?? {})).toEqual(['default']);
0027 });
0028
0029 it('selects the named rule set and cut list; off and unknown names select nothing', async () => {
0030 const rules = await resolveRootGeometryRules([removeBeam]);
0031 expect(selectRootGeometryLoadRules(rules, 'off', 'central')).toEqual({ editRules: [], cutList: ['Beam'] });
0032 expect(selectRootGeometryLoadRules(rules, 'default', 'unknown')).toEqual({ editRules: [], cutList: [] });
0033 });
0034
0035 it('stays structured-cloneable, as the worker message requires', async () => {
0036 const rules = await resolveRootGeometryRules([removeBeam]);
0037 const selected = selectRootGeometryLoadRules(rules, 'off', 'central');
0038 expect(structuredClone(selected)).toEqual(selected);
0039 });
0040 });
0041
0042 describe('orderGeometryPostProcessors', () => {
0043 const processor = (id: string, after?: string[]): GeometryPostProcessorRegistration =>
0044 ({ id, after, load: () => Promise.reject(new Error('not loaded in this spec')) });
0045 const ids = (list: GeometryPostProcessorRegistration[]) => list.map(registration => registration.id);
0046
0047 it('keeps registration order without constraints', () => {
0048 expect(ids(orderGeometryPostProcessors([processor('a'), processor('b'), processor('c')]))).toEqual(['a', 'b', 'c']);
0049 });
0050
0051 it('runs a processor after the ids in its `after`, and ignores ids nobody registered', () => {
0052 const ordered = orderGeometryPostProcessors([processor('arranger', ['mirrors']), processor('other', ['missing']), processor('mirrors')]);
0053 expect(ids(ordered)).toEqual(['other', 'mirrors', 'arranger']);
0054 });
0055
0056 it('a later registration with the same id replaces the earlier one in place', () => {
0057 const replacement = processor('a', ['b']);
0058 const ordered = orderGeometryPostProcessors([processor('a'), processor('b'), replacement]);
0059 expect(ordered).toEqual([expect.objectContaining({ id: 'b' }), replacement]);
0060 });
0061
0062 it('names the processors of an `after` cycle', () => {
0063 expect(() => orderGeometryPostProcessors([processor('a', ['b']), processor('b', ['a'])]))
0064 .toThrow('Geometry post-processors wait for each other: a, b');
0065 });
0066 });