80 lines
3.5 KiB
TypeScript
80 lines
3.5 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import {
|
|
DEFAULT_MAX_INTEL_HEX_RECORDS,
|
|
MAX_UINT32_ADDRESS,
|
|
parseIntelHex,
|
|
} from '../src/lib/intelHex'
|
|
|
|
function record(address: number, type: number, data: number[]): string {
|
|
const bytes = [data.length, Math.floor(address / 0x100) & 0xff, address & 0xff, type, ...data]
|
|
const checksum = (-bytes.reduce((sum, byte) => sum + byte, 0)) & 0xff
|
|
return `:${[...bytes, checksum].map((byte) => byte.toString(16).padStart(2, '0')).join('').toUpperCase()}`
|
|
}
|
|
|
|
const eof = record(0, 1, [])
|
|
|
|
describe('Intel HEX 32-bit boundaries', () => {
|
|
it('accepts a single byte at the highest uint32 address', () => {
|
|
const parsed = parseIntelHex([
|
|
record(0, 4, [0xff, 0xff]),
|
|
record(0xffff, 0, [0xaa]),
|
|
eof,
|
|
].join('\n'))
|
|
expect(parsed.blocks).toEqual([{ startAddress: MAX_UINT32_ADDRESS, data: Uint8Array.of(0xaa) }])
|
|
})
|
|
|
|
it('merges adjacent records ending exactly at the address-space boundary', () => {
|
|
const parsed = parseIntelHex([
|
|
record(0, 4, [0xff, 0xff]),
|
|
record(0xfffd, 0, [0x11, 0x22]),
|
|
record(0xffff, 0, [0x33]),
|
|
eof,
|
|
].join('\n'))
|
|
expect(parsed.blocks).toEqual([{
|
|
startAddress: 0xfffffffd,
|
|
data: Uint8Array.of(0x11, 0x22, 0x33),
|
|
}])
|
|
})
|
|
|
|
it('rejects a data record that extends beyond the uint32 address space', () => {
|
|
expect(() => parseIntelHex([
|
|
record(0, 4, [0xff, 0xff]),
|
|
record(0xffff, 0, [0xaa, 0xbb]),
|
|
eof,
|
|
].join('\n'))).toThrow('地址范围超出 32 位空间')
|
|
})
|
|
|
|
it('calculates segment and linear base addresses without signed bitwise overflow', () => {
|
|
const segment = parseIntelHex([record(0, 2, [0xff, 0xff]), record(0xffff, 0, [1]), eof].join('\n'))
|
|
const linear = parseIntelHex([record(0, 4, [0x80, 0x00]), record(0, 0, [2]), eof].join('\n'))
|
|
expect(segment.blocks[0].startAddress).toBe(0x0010ffef)
|
|
expect(linear.blocks[0].startAddress).toBe(0x80000000)
|
|
})
|
|
})
|
|
|
|
describe('Intel HEX structural limits', () => {
|
|
it('counts all non-empty records, including control records', () => {
|
|
expect(DEFAULT_MAX_INTEL_HEX_RECORDS).toBeGreaterThan(0)
|
|
expect(() => parseIntelHex([record(0, 0, [1]), eof].join('\n'), { maxRecords: 1 })).toThrow('记录不能超过 1 条')
|
|
})
|
|
|
|
it('rejects invalid limits before parsing', () => {
|
|
expect(() => parseIntelHex(record(0, 0, [1]), { maxRecords: 0 })).toThrow('正整数')
|
|
expect(() => parseIntelHex(record(0, 0, [1]), { maxRecords: 1.5 })).toThrow('正整数')
|
|
expect(() => parseIntelHex(record(0, 0, [1]), { maxRecords: Number.POSITIVE_INFINITY })).toThrow('正整数')
|
|
expect(() => parseIntelHex(record(0, 0, [1]), { maxRecords: Number.MAX_SAFE_INTEGER + 1 })).toThrow('正整数')
|
|
})
|
|
|
|
it('rejects records after EOF and malformed control records', () => {
|
|
expect(() => parseIntelHex([record(0, 0, [1]), eof, record(1, 0, [2])].join('\n'))).toThrow('EOF 记录之后')
|
|
expect(() => parseIntelHex([record(1, 1, []), record(0, 0, [1])].join('\n'))).toThrow('EOF 记录格式无效')
|
|
expect(() => parseIntelHex([record(0, 4, [0]), record(0, 0, [1]), eof].join('\n'))).toThrow('扩展线性地址记录格式无效')
|
|
expect(() => parseIntelHex([record(0, 6, []), record(0, 0, [1]), eof].join('\n'))).toThrow('不支持的记录类型')
|
|
})
|
|
|
|
it('rejects files without effective data and lines with inconsistent declared lengths', () => {
|
|
expect(() => parseIntelHex(eof)).toThrow('不包含有效数据记录')
|
|
expect(() => parseIntelHex(':0200000001FC')).toThrow('数据长度与记录声明不一致')
|
|
})
|
|
})
|