DFiP_Budget_planing/perf/analysis/svod2_search_oracle.test.mjs
Andrey Epifancev 5db0bd4cee fix(svod2): серверный поиск совпадает с экраном — пустое поле contract_detail не затирает contract_summary (R-30, решение пользователя 08.11)
В v3.svod2_lines counterparty/reference/deadline/comment берутся как COALESCE(detail, summary).
Оракулы (Python, JS, векторы) отбрасывают null при слиянии, legacy_full() снова читает
ответ без параметров. Тесты: пустое поле detail, отсутствие строки detail, перекрытие непустым detail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 11:45:37 +04:00

66 lines
3.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import assert from 'node:assert/strict';
import test from 'node:test';
import {
emitNumberVectors,
emitScreenVectors,
equals,
matchesSearch,
screenFacets,
screenFound,
screenRows,
} from './svod2_search_oracle.mjs';
const mk = (id, type, dir, org) => ({ data: { line_id: id, header: { smeta_type: type, smeta_direction: dir, org_name: org } } });
const rows2 = [mk(1, 'КВ', 'Развитие', 'А'), mk(2, 'АХР', 'Поддержка', 'Б')];
const rows3 = [mk(1, 'КВ', 'Р', 'Филиал Ёлки'), mk(2, 'КВ', 'Р', 'Филиал Ёлки'), mk(3, 'КВ', 'Р', null)];
test('пустое поле contract_detail не затирает contract_summary (R-30)', () => {
const row = { data: { header: { name: 'x' }, contract_summary: { counterparty: 'ООО Ромашка' }, contract_detail: { counterparty: null } } };
assert.equal(matchesSearch(row, 'ромаш'), true);
});
test('непустое поле contract_detail перекрывает contract_summary', () => {
const row = { data: { header: {}, contract_summary: { counterparty: 'ООО Ромашка' }, contract_detail: { counterparty: 'ИП Ёж' } } };
assert.equal(matchesSearch(row, 'ромаш'), false);
assert.equal(matchesSearch(row, 'ёж'), true);
});
test('число ищется в записи JS', () => {
const row = { data: { header: {}, contract_summary: {}, contract_detail: JSON.parse('{"ceiling_amount": 1234.50}') } };
assert.equal(matchesSearch(row, '1234.5'), true);
assert.equal(matchesSearch(row, '1234.50'), false);
});
test('screenRows: trim + lower, NBSP по краям', () => {
const rows = [{ data: { line_id: 1, header: { name: 'Аренда помещения' } } }];
assert.deepEqual(screenRows(rows, { search: ' АРЕНДА ' }).map((r) => r.data.line_id), [1]);
assert.deepEqual(screenRows(rows, { search: ' аренда ' }).map((r) => r.data.line_id), [1]);
});
test('equals: регистр и пробелы по краям, null не проходит', () => {
const r = (v) => ({ getValue: () => v });
assert.equal(equals(r('КВ'), 'smeta_type', 'кв '), true);
assert.equal(equals(r(null), 'smeta_type', 'кв'), false);
});
test('screenFacets: свой фильтр не применяется, чужие — да', () => {
const f = screenFacets(rows2, { filters: { smeta_type: 'КВ' } });
assert.deepEqual(f.smeta_type, [['АХР', 1], ['КВ', 1]]);
assert.deepEqual(f.smeta_direction, [['Развитие', 1]]);
});
test('screenFacets: одинаковые названия — один вариант, null не выдаётся', () => {
assert.deepEqual(screenFacets(rows3).org_name, [['Филиал Ёлки', 2]]);
});
test('screenFound считает только поиск', () => {
assert.deepEqual(screenFound(rows2, ''), { found: 2, total: 2 });
});
test('векторы чисел', () => {
const v = Object.fromEntries(emitNumberVectors().map(({ input, js }) => [input, js]));
assert.equal(v['1e21'], '1e+21');
assert.equal(v['-0'], '0');
assert.equal(v['1e-7'], '1e-7');
assert.equal(v['0.000001'], '0.000001');
assert.equal(v['100.00'], '100');
assert.equal(v['9007199254740993'], '9007199254740992');
});
test('векторы экрана: не меньше 12 случаев', () => {
const s = emitScreenVectors();
assert.ok(s.cases.length >= 12);
assert.ok(s.rows.length >= 10 && s.rows.length <= 15);
});