134 lines
4.7 KiB
JavaScript
134 lines
4.7 KiB
JavaScript
/**
|
|
* 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');
|
|
});
|
|
});
|
|
});
|