Sessions 5-7a: 955 tests, deployment ready
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* Ship Build — Scheme Classifier Enhancement Tests
|
||||
* Validates backward compatibility + new Synergy integration.
|
||||
*/
|
||||
|
||||
const {
|
||||
SCHEME_TYPES,
|
||||
MIN_POSSESSIONS,
|
||||
CACHE_TTL,
|
||||
getCacheKey,
|
||||
classifyFromDistribution,
|
||||
extractPnRPossessions,
|
||||
classifyScheme,
|
||||
} = require('../../src/services/schemeClassifier');
|
||||
|
||||
describe('Scheme Classifier — Ship Enhancement', () => {
|
||||
|
||||
// --- Backward Compatibility ---
|
||||
|
||||
describe('Backward Compatibility', () => {
|
||||
test('SCHEME_TYPES still contains all 5 classifications', () => {
|
||||
expect(SCHEME_TYPES).toEqual(['DROP', 'SWITCH', 'HEDGE', 'MIXED', 'UNKNOWN']);
|
||||
});
|
||||
|
||||
test('MIN_POSSESSIONS still 8', () => {
|
||||
expect(MIN_POSSESSIONS).toBe(8);
|
||||
});
|
||||
|
||||
test('CACHE_TTL still 6 hours', () => {
|
||||
expect(CACHE_TTL).toBe(21600);
|
||||
});
|
||||
|
||||
test('cache key format unchanged', () => {
|
||||
expect(getCacheKey('BOS', '2026-04-13')).toBe('scheme:BOS:2026-04-13');
|
||||
});
|
||||
|
||||
test('regex classification still works for DROP', () => {
|
||||
const possessions = Array.from({ length: 10 }, () => ({ description: 'drop coverage on ball screen' }));
|
||||
const result = classifyScheme(possessions);
|
||||
expect(result.scheme).toBe('DROP');
|
||||
});
|
||||
|
||||
test('regex classification still returns UNKNOWN below threshold', () => {
|
||||
const possessions = Array.from({ length: 5 }, () => ({ description: 'drop coverage' }));
|
||||
const result = classifyScheme(possessions);
|
||||
expect(result.scheme).toBe('UNKNOWN');
|
||||
});
|
||||
|
||||
test('extractPnRPossessions still finds PnR plays', () => {
|
||||
const plays = [
|
||||
{ description: 'pick and roll ball handler' },
|
||||
{ description: 'transition fastbreak' },
|
||||
];
|
||||
expect(extractPnRPossessions(plays)).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
// --- Synergy Distribution Classification ---
|
||||
|
||||
describe('Synergy Distribution Classification', () => {
|
||||
test('classifyFromDistribution returns UNKNOWN for empty distribution', () => {
|
||||
expect(classifyFromDistribution({})).toBe('UNKNOWN');
|
||||
expect(classifyFromDistribution(null)).toBe('UNKNOWN');
|
||||
});
|
||||
|
||||
test('classifyFromDistribution returns DROP for high PPP PnR', () => {
|
||||
const dist = {
|
||||
'PRBallHandler': { frequency_pct: 0.15, ppp: 1.0, to_pct: 0.05 },
|
||||
'PRRollman': { frequency_pct: 0.10, ppp: 0.90 },
|
||||
'Isolation': { frequency_pct: 0.08 },
|
||||
};
|
||||
expect(classifyFromDistribution(dist)).toBe('DROP');
|
||||
});
|
||||
|
||||
test('classifyFromDistribution returns HEDGE for low PPP high TO PnR', () => {
|
||||
const dist = {
|
||||
'PRBallHandler': { frequency_pct: 0.15, ppp: 0.75, to_pct: 0.18 },
|
||||
'PRRollman': { frequency_pct: 0.08, ppp: 0.70 },
|
||||
'Isolation': { frequency_pct: 0.05 },
|
||||
};
|
||||
expect(classifyFromDistribution(dist)).toBe('HEDGE');
|
||||
});
|
||||
|
||||
test('classifyFromDistribution returns SWITCH for high isolation frequency', () => {
|
||||
const dist = {
|
||||
'PRBallHandler': { frequency_pct: 0.10, ppp: 0.85, to_pct: 0.10 },
|
||||
'PRRollman': { frequency_pct: 0.05 },
|
||||
'Isolation': { frequency_pct: 0.18 },
|
||||
};
|
||||
expect(classifyFromDistribution(dist)).toBe('SWITCH');
|
||||
});
|
||||
|
||||
test('classifyFromDistribution returns UNKNOWN when too little PnR data', () => {
|
||||
const dist = {
|
||||
'PRBallHandler': { frequency_pct: 0.02, ppp: 0.90 },
|
||||
'PRRollman': { frequency_pct: 0.01 },
|
||||
'Isolation': { frequency_pct: 0.10 },
|
||||
};
|
||||
expect(classifyFromDistribution(dist)).toBe('UNKNOWN');
|
||||
});
|
||||
|
||||
test('classifyFromDistribution returns MIXED for mid-range values', () => {
|
||||
const dist = {
|
||||
'PRBallHandler': { frequency_pct: 0.12, ppp: 0.88, to_pct: 0.12 },
|
||||
'PRRollman': { frequency_pct: 0.08 },
|
||||
'Isolation': { frequency_pct: 0.10 },
|
||||
};
|
||||
expect(classifyFromDistribution(dist)).toBe('MIXED');
|
||||
});
|
||||
});
|
||||
|
||||
// --- Export validation ---
|
||||
|
||||
describe('Module Exports', () => {
|
||||
test('exports fetchSynergyScheme (new)', () => {
|
||||
expect(typeof require('../../src/services/schemeClassifier').fetchSynergyScheme).toBe('function');
|
||||
});
|
||||
|
||||
test('exports classifyFromDistribution (new)', () => {
|
||||
expect(typeof require('../../src/services/schemeClassifier').classifyFromDistribution).toBe('function');
|
||||
});
|
||||
|
||||
test('exports all original functions', () => {
|
||||
const mod = require('../../src/services/schemeClassifier');
|
||||
expect(typeof mod.getCacheKey).toBe('function');
|
||||
expect(typeof mod.fetchPlayByPlay).toBe('function');
|
||||
expect(typeof mod.extractPnRPossessions).toBe('function');
|
||||
expect(typeof mod.classifyScheme).toBe('function');
|
||||
expect(typeof mod.getSchemeClassification).toBe('function');
|
||||
expect(typeof mod.logSchemeToExtended).toBe('function');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user