Files
WebTools/tests/intelHexBoundaries.test.ts

91 lines
4.0 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import {
DEFAULT_MAX_INTEL_HEX_BYTES,
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('正整数')
expect(() => parseIntelHex(record(0, 0, [1]), { maxBytes: 0 })).toThrow('正整数')
expect(DEFAULT_MAX_INTEL_HEX_BYTES).toBe(64 * 1024 * 1024)
})
it('rejects a merged data block before allocating beyond the byte limit', () => {
expect(() => parseIntelHex([
record(0, 0, [0xaa]),
record(1, 0, [0xbb]),
eof,
].join('\n'), { maxBytes: 1 })).toThrow('有效数据不能超过 1 bytes')
})
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('数据长度与记录声明不一致')
})
})