Files
otaman/frontend/tests/response_map.test.js
T
catarrh 072e8fe08b C-APDU encoder features + GET STATUS E3 coverage; v1.9.2
SIM/USIM encoder (registry §2.3):
- New PIN commands: DISABLE '26' / ENABLE '28' (single FF-padded PIN,
  Lc=08) and UNBLOCK '2C' (unblock+new, Lc=10); dynamic field labels
- ACTIVATE/DEACTIVATE FILE target selection: Current EF (case 1),
  by FID (P1=00), path from MF (P1=08), path from current DF (P1=09)
  with Lc+FID/path data form
- LANG_RU entries for new labels

Tests:
- sim.test.js: new stub-DOM genSimUsim harness; exact-hex for all PIN
  ops, ACTIVATE/DEACTIVATE forms, SELECT Le rules, RECORD P1=00 rule
- response_map.test.js: lookupSw wildcards (91XX / 63CX), LIFECYCLE_MAP
  per GPC v2.3, PRIVILEGE_NAMES vs Tables 11-7/11-8/11-9

GET STATUS E3 template decoding verified already present
(TLV_TAG_NAMES + decodeTlvValue cover 4F/9F70/C5/CF/C4/CC/CE/84).

Version 1.9.1 -> 1.9.2, SW cache otaman-v12 -> otaman-v13
2026-08-22 23:54:49 +03:00

57 lines
2.3 KiB
JavaScript

const { test } = require('node:test');
const assert = require('node:assert');
const fs = require('node:fs');
const path = require('node:path');
const html = fs.readFileSync(path.join(__dirname, '..', 'index.html'), 'utf8');
function extractBlock(startMarker, endMarker) {
const start = html.indexOf(startMarker);
const end = html.indexOf(endMarker, start);
if (start < 0 || end < 0) throw new Error('block not found');
return html.slice(start, end);
}
// Response parser maps + lookupSw live between SW_MAP and updateRespCmd.
// Rewrite top-level const -> var so the maps leak out of sloppy-mode eval.
eval(extractBlock('const SW_MAP = {', 'function updateRespCmd').replace(/^const /gm, 'var '));
test('lookupSw wildcard 91XX resolves proactive pending (any length)', () => {
const desc = lookupSw('91', '14', 'uicc');
assert.ok(desc.includes('proactive'), desc);
assert.ok(!desc.includes('no response data'));
});
test('lookupSw 63CX extracts retry counter', () => {
const desc = lookupSw('63', 'C3', 'uicc');
assert.ok(desc.includes('3'), desc);
});
test('SW_MAP.generic covers ISO 6A85/6A89/6A8A', () => {
assert.ok(SW_MAP.generic['6A85']);
assert.ok(SW_MAP.generic['6A89']);
assert.ok(SW_MAP.generic['6A8A']);
});
test('gp 6310 label does not reference removed P2=42 option', () => {
assert.ok(!SW_MAP.gp['6310'].includes('42'));
});
test('LIFECYCLE_MAP per GPC v2.3 life cycles', () => {
assert.strictEqual(LIFECYCLE_MAP['01'], 'OP_READY (card) / LOADED (ELF)');
assert.strictEqual(LIFECYCLE_MAP['03'], 'INSTALLED');
assert.strictEqual(LIFECYCLE_MAP['07'], 'SELECTABLE');
assert.strictEqual(LIFECYCLE_MAP['0F'], 'SECURED (card)');
assert.strictEqual(LIFECYCLE_MAP['1F'], 'PERSONALIZED (SD)');
assert.strictEqual(LIFECYCLE_MAP['7F'], 'CARD_LOCKED');
assert.strictEqual(LIFECYCLE_MAP['FF'], 'TERMINATED');
assert.strictEqual(LIFECYCLE_MAP['83'], 'LOCKED (SD)');
});
test('PRIVILEGE_NAMES matches GPC v2.3 Tables 11-7/11-8/11-9', () => {
assert.strictEqual(PRIVILEGE_NAMES[0][7], 'Mandated DAP Verification');
assert.strictEqual(PRIVILEGE_NAMES[1][2], 'Token Verification');
assert.strictEqual(PRIVILEGE_NAMES[1][7], 'Global Service');
assert.strictEqual(PRIVILEGE_NAMES[2][0], 'Receipt Generation');
assert.strictEqual(PRIVILEGE_NAMES[2][3], 'Contactless Self-Activation');
});