import { describe, it, expect } from 'vitest'; import { getByteCount, getTransportSize, readFixedString, writeFixedString, s7DateToDate, dateToS7Date } from '../../src/utils/buffer-utils.js'; import { S7WLBit, S7WLByte, S7WLWord, S7WLDWord, S7WLReal, S7WLCounter, S7WLTimer } from '../../src/protocol/constants.js'; describe('buffer-utils', () => { describe('getByteCount', () => { it('should return correct byte count for each WordLen', () => { expect(getByteCount(S7WLBit)).toBe(1); expect(getByteCount(S7WLByte)).toBe(1); expect(getByteCount(S7WLWord)).toBe(2); expect(getByteCount(S7WLDWord)).toBe(4); expect(getByteCount(S7WLReal)).toBe(4); expect(getByteCount(S7WLCounter)).toBe(2); expect(getByteCount(S7WLTimer)).toBe(2); }); it('should return 0 for unknown WordLen', () => { expect(getByteCount(0x99)).toBe(0); }); }); describe('getTransportSize', () => { it('should return correct transport size for each WordLen', () => { expect(getTransportSize(S7WLBit)).toBe(0x01); expect(getTransportSize(S7WLByte)).toBe(0x02); expect(getTransportSize(S7WLWord)).toBe(0x04); expect(getTransportSize(S7WLDWord)).toBe(0x06); expect(getTransportSize(S7WLReal)).toBe(0x08); expect(getTransportSize(S7WLCounter)).toBe(0x1C); expect(getTransportSize(S7WLTimer)).toBe(0x1D); }); it('should return 0 for unknown WordLen', () => { expect(getTransportSize(0x99)).toBe(0x00); }); }); describe('readFixedString', () => { it('should read ASCII string from buffer', () => { const buf = Buffer.from('Hello World ', 'ascii'); expect(readFixedString(buf, 0, 15)).toBe('Hello World'); }); it('should trim trailing null bytes', () => { const buf = Buffer.alloc(10, 0); Buffer.from('Test', 'ascii').copy(buf); expect(readFixedString(buf, 0, 10)).toBe('Test'); }); it('should handle null-only buffer', () => { const buf = Buffer.alloc(10, 0); expect(readFixedString(buf, 0, 10)).toBe(''); }); it('should read from offset', () => { const buf = Buffer.from('XXHello ', 'ascii'); expect(readFixedString(buf, 2, 8)).toBe('Hello'); }); }); describe('writeFixedString', () => { it('should write string padded with spaces', () => { const buf = Buffer.alloc(10, 0x00); writeFixedString(buf, 0, 10, 'Hi'); expect(buf[0]).toBe(0x48); // 'H' expect(buf[1]).toBe(0x69); // 'i' expect(buf[2]).toBe(0x20); // space padding }); it('should truncate string that exceeds length', () => { const buf = Buffer.alloc(5, 0x00); writeFixedString(buf, 0, 5, 'HelloWorld'); expect(buf.toString('ascii')).toBe('Hello'); }); }); describe('s7DateToDate', () => { it('should convert S7 date components to Date', () => { const d = s7DateToDate(2025, 6, 15, 10, 30, 45); expect(d.getFullYear()).toBe(2025); expect(d.getMonth()).toBe(5); // 0-indexed expect(d.getDate()).toBe(15); expect(d.getHours()).toBe(10); expect(d.getMinutes()).toBe(30); expect(d.getSeconds()).toBe(45); }); }); describe('dateToS7Date', () => { it('should convert Date to S7 date components', () => { const d = new Date(2025, 5, 15, 10, 30, 45); const result = dateToS7Date(d); expect(result.year).toBe(2025); expect(result.month).toBe(6); expect(result.day).toBe(15); expect(result.hour).toBe(10); expect(result.minute).toBe(30); expect(result.second).toBe(45); }); }); describe('roundtrip date conversion', () => { it('should roundtrip date conversion', () => { const original = new Date(2025, 11, 25, 14, 30, 0); const s7 = dateToS7Date(original); const restored = s7DateToDate(s7.year, s7.month, s7.day, s7.hour, s7.minute, s7.second); expect(restored.getTime()).toBe(original.getTime()); }); }); });