Files
simple/frontend/tests/pli_dict.test.js
T
catarrh ad2a253f2a PLI date/time responses default to the host clock
Live finding (Network rejection events): the card asks the terminal for the
current date and time (PROVIDE LOCAL INFORMATION, qualifier 03) and our TR
answered "performed successfully" with no data.  TS 102 223 6.4.15 says the
terminal shall return the current date and time, and the 6.8.0 TR structure
requires the Date-Time and Time zone object (8.39) for that qualifier.

- _pli_data_hex(qual): the TR Config dictionary entry wins; when it is empty
  the date/time qualifier is answered from the host clock via _encode_scts
  (the SMS timestamp builder, TP-SCTS coding).
- _build_tr and _DefaultProactiveHandler put the command-specific data objects
  after the Result TLV per the 6.8.0 order (the POLL INTERVAL Duration echo
  too; real terminal responses pin the order: 8103010300 02028281 030100
  0402011E).
- _decode_tr decodes qualifier 03 with the same 8.39 coding (swapped
  semi-octet BCD digits, time-zone sign bit 0x08, 'FF' = unknown); it read
  plain decimal bytes and a 0x80 sign before.
- The PWA PLI dictionary codec for the date/time entry writes the same coding
  (it wrote plain hex bytes and a 0x80 sign), and the TR Config panel notes
  the empty-entry default.  sw cache simple-v351.

Tests: builder vectors (east/west/unknown zone) + dictionary override + the
empty non-date/time qualifier + the object order (PLI and POLL INTERVAL) + the
handler path + the TR decode + a frontend codec round-trip test.
2026-10-01 23:37:26 +03:00

40 lines
1.8 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: ' + startMarker);
return html.slice(start, end);
}
// The codec map's select fields reference ACCESSTECH; only the date/time
// codec is exercised here, but the map literal still evaluates that list.
eval(extractBlock('const ACCESSTECH = [', 'const EVENT_FORMS = {').replace(/^const /gm, 'var '));
eval(extractBlock('// ===== PLI data dictionary =====', 'async function pysimPliRender')
.replace(/^const /gm, 'var '));
test('the PLI date/time codec uses the 8.39 TP-SCTS coding', () => {
const c = PLI_CODECS['03'];
assert.strictEqual(c.tlv, '2607');
// +03:00: swapped semi-octet BCD digits, the time zone in quarters of an
// hour (0x21 = 12 quarters) - the eventDateTimeTlv / _encode_scts vectors
assert.strictEqual(c.encode({ dt: '2026-09-30', tm: '21:55:00', tz: '+03:00' }),
'260762900312550021');
assert.deepStrictEqual(c.decode('260762900312550021'),
{ dt: '2026-09-30', tm: '21:55:00', tz: '+03:00' });
// negative zones carry the sign bit 0x08: -2:30 = 10 quarters -> 0x09
assert.strictEqual(c.encode({ dt: '2026-01-05', tm: '08:07:09', tz: '-02:30' }),
'260762105080709009');
assert.deepStrictEqual(c.decode('260762105080709009'),
{ dt: '2026-01-05', tm: '08:07:09', tz: '-02:30' });
// 'FF' time zone = unknown (TS 123 040 9.2.3.11), never a bogus offset
assert.strictEqual(c.decode('2607629003125500FF').tz, 'unknown');
// a truncated value still returns null instead of throwing
assert.strictEqual(c.decode('2607123'), null);
});