// tests/infra/scan.test.js import { describe, it, expect } from 'vitest'; import { isRandomizedMac, parseArpScan, runScan } from '../../lib/infra/scan.js'; const SAMPLE = [ 'Interface: eth0, type: EN10MB, MAC: bc:24:11:9b:b7:3a, IPv4: 192.168.1.216', 'Starting arp-scan 1.10.0', '192.168.1.13\tbc:a5:11:3e:06:88\tNetgear', '192.168.1.171\t5a:da:61:7a:0f:12\t(Unknown)', '192.168.1.1\t44:A5:6E:68:D0:E9\tNetgear Inc.', 'garbage line that is not a host', '', '3 packets received by filter, 0 packets dropped' ].join('\n'); describe('scan parsing', () => { it('isRandomizedMac flags locally-administered MACs', () => { expect(isRandomizedMac('5a:da:61:7a:0f:12')).toBe(true); // 0x5a & 0x02 expect(isRandomizedMac('bc:a5:11:3e:06:88')).toBe(false); // 0xbc & 0x02 == 0 expect(isRandomizedMac('44:A5:6E:68:D0:E9')).toBe(false); }); it('parseArpScan keeps only host lines, lowercases MAC, flags randomized', () => { const rows = parseArpScan(SAMPLE); expect(rows).toHaveLength(3); expect(rows[0]).toEqual({ ip: '192.168.1.13', mac: 'bc:a5:11:3e:06:88', vendor: 'Netgear', randomized: false }); expect(rows[1]).toEqual({ ip: '192.168.1.171', mac: '5a:da:61:7a:0f:12', vendor: '(Unknown)', randomized: true }); expect(rows[2].mac).toBe('44:a5:6e:68:d0:e9'); // lowercased }); it('runScan parses the injected exec stdout', async () => { const rows = await runScan({ exec: async () => ({ stdout: SAMPLE }) }); expect(rows.map(r => r.ip)).toEqual(['192.168.1.13', '192.168.1.171', '192.168.1.1']); }); });