import { describe, it, expect } from 'vitest'; import { buildCR, buildCC, buildDR, buildDT, isCR, isCC, isDR, isDT, isDTEot, extractDTPayload, computeRemoteTSAP, computeLocalTSAP } from '../../src/protocol/cotp.js'; import { COTP_CR, COTP_CC, COTP_DR, COTP_DT, COTP_DT_EOT, CONNTYPE_PG, CONNTYPE_OP, CONNTYPE_BASIC } from '../../src/protocol/constants.js'; describe('COTP', () => { describe('computeRemoteTSAP', () => { it('should compute TSAP from rack and slot', () => { expect(computeRemoteTSAP(0, 1)).toBe(0x0001); expect(computeRemoteTSAP(1, 2)).toBe(0x0102); expect(computeRemoteTSAP(0, 0)).toBe(0x0000); }); }); describe('computeLocalTSAP', () => { it('should compute PG connection TSAP', () => { expect(computeLocalTSAP(CONNTYPE_PG, 0)).toBe(0x0100); expect(computeLocalTSAP(CONNTYPE_PG, 1)).toBe(0x0101); }); it('should compute OP connection TSAP', () => { expect(computeLocalTSAP(CONNTYPE_OP, 0)).toBe(0x0200); expect(computeLocalTSAP(CONNTYPE_OP, 5)).toBe(0x0205); }); it('should compute Basic connection TSAP', () => { expect(computeLocalTSAP(CONNTYPE_BASIC, 0)).toBe(0x0300); }); }); describe('buildCR', () => { it('should build a valid CR PDU', () => { const cr = buildCR(0x0100, 0x0001); expect(cr[1]).toBe(COTP_CR); // Check Source TSAP parameter expect(cr.length).toBeGreaterThan(7); }); it('should contain source TSAP', () => { const localTSAP = 0x0100; const cr = buildCR(localTSAP, 0x0001); const crStr = cr.toString('hex'); // Source TSAP 0x0100 should be in the buffer expect(crStr).toContain('c10201'); // COTP_SRC_TSAP(0xC1) + len(0x02) + 0x01 + 0x00 }); it('should contain destination TSAP', () => { const remoteTSAP = 0x0102; const cr = buildCR(0x0100, remoteTSAP); const crStr = cr.toString('hex'); expect(crStr).toContain('c20201'); // COTP_DST_TSAP(0xC2) + len(0x02) + high byte }); }); describe('buildCC', () => { it('should build a valid CC PDU', () => { const cc = buildCC(); expect(cc[1]).toBe(COTP_CC); expect(cc.length).toBeGreaterThan(7); }); }); describe('buildDR', () => { it('should build a valid DR PDU', () => { const dr = buildDR(); expect(dr[0]).toBe(6); // LI expect(dr[1]).toBe(COTP_DR); }); }); describe('buildDT', () => { it('should build DT with EOT flag by default', () => { const payload = Buffer.from([0x32, 0x01]); const dt = buildDT(payload); expect(dt[0]).toBe(2); // LI expect(dt[1]).toBe(COTP_DT | COTP_DT_EOT); }); it('should build DT without EOT flag', () => { const payload = Buffer.from([0x32, 0x01]); const dt = buildDT(payload, false); expect(dt[1]).toBe(COTP_DT); }); it('should include payload', () => { const payload = Buffer.from([0xAA, 0xBB]); const dt = buildDT(payload); expect(dt.subarray(3)).toEqual(payload); // LI(1) + Code(1) + NR(1) = 3 header bytes }); }); describe('isCR/isCC/isDR/isDT/isDTEot', () => { it('should identify CR', () => { const cr = buildCR(0x0100, 0x0001); expect(isCR(cr)).toBe(true); expect(isCC(cr)).toBe(false); }); it('should identify CC', () => { const cc = buildCC(); expect(isCC(cc)).toBe(true); expect(isCR(cc)).toBe(false); }); it('should identify DR', () => { const dr = buildDR(); expect(isDR(dr)).toBe(true); expect(isDT(dr)).toBe(false); }); it('should identify DT with EOT', () => { const dt = buildDT(Buffer.alloc(10)); expect(isDT(dt)).toBe(true); expect(isDTEot(dt)).toBe(true); }); it('should identify DT without EOT', () => { const dt = buildDT(Buffer.alloc(10), false); expect(isDT(dt)).toBe(true); expect(isDTEot(dt)).toBe(false); }); it('should return false for too short buffer', () => { expect(isCR(Buffer.alloc(0))).toBe(false); expect(isCC(Buffer.alloc(0))).toBe(false); expect(isDR(Buffer.alloc(0))).toBe(false); expect(isDT(Buffer.alloc(0))).toBe(false); }); }); describe('extractDTPayload', () => { it('should extract payload from DT frame', () => { const payload = Buffer.from([0x32, 0x01, 0x00, 0x00]); const dt = buildDT(payload); const extracted = extractDTPayload(dt); expect(extracted).toEqual(payload); }); it('should handle LI correctly', () => { const payload = Buffer.from([0xAA, 0xBB]); const dt = buildDT(payload); // LI = 2, so headerLen = LI + 1 = 3 expect(dt[0]).toBe(2); const extracted = extractDTPayload(dt); expect(extracted).toEqual(payload); }); }); });