274 lines
8.7 KiB
TypeScript
274 lines
8.7 KiB
TypeScript
/**
|
|
* Tests for memory write operations.
|
|
*/
|
|
|
|
import { MemoryContentProvider } from '../../src/frontend/memory_content_provider'
|
|
|
|
// Mock vscode with controllable debug session
|
|
const mockCustomRequest = jest.fn()
|
|
let hasActiveDebugSession = false
|
|
|
|
jest.mock('vscode', () => ({
|
|
window: {
|
|
createTextEditorDecorationType: jest.fn().mockReturnValue({
|
|
dispose: jest.fn()
|
|
}),
|
|
showErrorMessage: jest.fn().mockResolvedValue(undefined),
|
|
showInformationMessage: jest.fn().mockResolvedValue(undefined)
|
|
},
|
|
debug: {
|
|
get activeDebugSession() {
|
|
return hasActiveDebugSession ? {
|
|
customRequest: mockCustomRequest
|
|
} : undefined
|
|
}
|
|
},
|
|
EventEmitter: jest.fn().mockImplementation(() => ({
|
|
event: jest.fn(),
|
|
fire: jest.fn()
|
|
})),
|
|
Position: jest.fn().mockImplementation((line: number, character: number) => ({
|
|
line,
|
|
character
|
|
})),
|
|
Range: jest.fn(),
|
|
OverviewRulerLane: {
|
|
Right: 4
|
|
},
|
|
Uri: {
|
|
parse: jest.fn()
|
|
},
|
|
workspace: {
|
|
textDocuments: []
|
|
}
|
|
}))
|
|
|
|
describe('Memory Write Operations', () => {
|
|
let provider: MemoryContentProvider
|
|
|
|
beforeEach(() => {
|
|
provider = new MemoryContentProvider()
|
|
hasActiveDebugSession = true
|
|
mockCustomRequest.mockClear()
|
|
})
|
|
|
|
afterEach(() => {
|
|
hasActiveDebugSession = false
|
|
})
|
|
|
|
describe('writeByte', () => {
|
|
test('should write single byte successfully', async () => {
|
|
mockCustomRequest.mockResolvedValue({ success: true })
|
|
|
|
const success = await provider.writeByte(0x20000000, 0xAB)
|
|
|
|
expect(success).toBe(true)
|
|
expect(mockCustomRequest).toHaveBeenCalledWith('write-memory', {
|
|
address: 0x20000000,
|
|
data: 'ab'
|
|
})
|
|
})
|
|
|
|
test('should write byte 0x00', async () => {
|
|
mockCustomRequest.mockResolvedValue({ success: true })
|
|
|
|
const success = await provider.writeByte(0x20000000, 0x00)
|
|
|
|
expect(success).toBe(true)
|
|
expect(mockCustomRequest).toHaveBeenCalledWith('write-memory', {
|
|
address: 0x20000000,
|
|
data: '00'
|
|
})
|
|
})
|
|
|
|
test('should write byte 0xFF', async () => {
|
|
mockCustomRequest.mockResolvedValue({ success: true })
|
|
|
|
const success = await provider.writeByte(0x20000000, 0xFF)
|
|
|
|
expect(success).toBe(true)
|
|
expect(mockCustomRequest).toHaveBeenCalledWith('write-memory', {
|
|
address: 0x20000000,
|
|
data: 'ff'
|
|
})
|
|
})
|
|
|
|
test('should reject value > 0xFF with an error', async () => {
|
|
const success = await provider.writeByte(0x20000000, 0x1AB)
|
|
|
|
expect(success).toBe(false)
|
|
expect(mockCustomRequest).not.toHaveBeenCalled()
|
|
})
|
|
|
|
test('should reject negative values', async () => {
|
|
const success = await provider.writeByte(0x20000000, -1)
|
|
|
|
expect(success).toBe(false)
|
|
expect(mockCustomRequest).not.toHaveBeenCalled()
|
|
})
|
|
|
|
test('should reject fractional values', async () => {
|
|
const successA = await provider.writeByte(0x20000000, 1.5)
|
|
expect(successA).toBe(false)
|
|
expect(mockCustomRequest).not.toHaveBeenCalled()
|
|
|
|
const successB = await provider.writeByte(0x20000000, 0.5)
|
|
expect(successB).toBe(false)
|
|
expect(mockCustomRequest).not.toHaveBeenCalled()
|
|
})
|
|
|
|
test('should return false when no debug session', async () => {
|
|
hasActiveDebugSession = false
|
|
|
|
const success = await provider.writeByte(0x20000000, 0xAB)
|
|
|
|
expect(success).toBe(false)
|
|
expect(mockCustomRequest).not.toHaveBeenCalled()
|
|
})
|
|
|
|
test('should return false on write error', async () => {
|
|
mockCustomRequest.mockRejectedValue(new Error('Memory access denied'))
|
|
|
|
const success = await provider.writeByte(0x20000000, 0xAB)
|
|
|
|
expect(success).toBe(false)
|
|
})
|
|
|
|
test('should write to different addresses', async () => {
|
|
mockCustomRequest.mockResolvedValue({ success: true })
|
|
|
|
// Test various addresses
|
|
const addresses = [
|
|
0x00000000,
|
|
0x20000000,
|
|
0x40000000,
|
|
0x08000000,
|
|
0xFFFFFFFF
|
|
]
|
|
|
|
for (const address of addresses) {
|
|
mockCustomRequest.mockClear()
|
|
const success = await provider.writeByte(address, 0x42)
|
|
expect(success).toBe(true)
|
|
expect(mockCustomRequest).toHaveBeenCalledWith('write-memory', {
|
|
address,
|
|
data: '42'
|
|
})
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('writeBytes', () => {
|
|
test('should write multiple bytes successfully', async () => {
|
|
mockCustomRequest.mockResolvedValue({ success: true })
|
|
|
|
const success = await provider.writeBytes(0x20000000, [0x12, 0x34, 0x56, 0x78])
|
|
|
|
expect(success).toBe(true)
|
|
expect(mockCustomRequest).toHaveBeenCalledWith('write-memory', {
|
|
address: 0x20000000,
|
|
data: '12345678'
|
|
})
|
|
})
|
|
|
|
test('should write single byte array', async () => {
|
|
mockCustomRequest.mockResolvedValue({ success: true })
|
|
|
|
const success = await provider.writeBytes(0x20000000, [0xAB])
|
|
|
|
expect(success).toBe(true)
|
|
expect(mockCustomRequest).toHaveBeenCalledWith('write-memory', {
|
|
address: 0x20000000,
|
|
data: 'ab'
|
|
})
|
|
})
|
|
|
|
test('should write empty array', async () => {
|
|
mockCustomRequest.mockResolvedValue({ success: true })
|
|
|
|
const success = await provider.writeBytes(0x20000000, [])
|
|
|
|
expect(success).toBe(true)
|
|
expect(mockCustomRequest).toHaveBeenCalledWith('write-memory', {
|
|
address: 0x20000000,
|
|
data: ''
|
|
})
|
|
})
|
|
|
|
test('should reject array containing values > 0xFF with an error', async () => {
|
|
const success = await provider.writeBytes(0x20000000, [0x1FF, 0x2AB, 0x3CD])
|
|
|
|
expect(success).toBe(false)
|
|
expect(mockCustomRequest).not.toHaveBeenCalled()
|
|
})
|
|
|
|
test('should return false when no debug session', async () => {
|
|
hasActiveDebugSession = false
|
|
|
|
const success = await provider.writeBytes(0x20000000, [0x12, 0x34])
|
|
|
|
expect(success).toBe(false)
|
|
expect(mockCustomRequest).not.toHaveBeenCalled()
|
|
})
|
|
|
|
test('should return false on write error', async () => {
|
|
mockCustomRequest.mockRejectedValue(new Error('Target not halted'))
|
|
|
|
const success = await provider.writeBytes(0x20000000, [0x12, 0x34])
|
|
|
|
expect(success).toBe(false)
|
|
})
|
|
|
|
test('should write large byte arrays', async () => {
|
|
mockCustomRequest.mockResolvedValue({ success: true })
|
|
|
|
const largeArray = new Array(256).fill(0).map((_, i) => i)
|
|
const success = await provider.writeBytes(0x20000000, largeArray)
|
|
|
|
expect(success).toBe(true)
|
|
expect(mockCustomRequest).toHaveBeenCalledWith('write-memory', {
|
|
address: 0x20000000,
|
|
data: largeArray.map(v => v.toString(16).padStart(2, '0')).join('')
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('Hex Formatting', () => {
|
|
test('should format bytes as lowercase hex', async () => {
|
|
mockCustomRequest.mockResolvedValue({ success: true })
|
|
|
|
await provider.writeByte(0x20000000, 0xAB)
|
|
|
|
const callArgs = mockCustomRequest.mock.calls[0]
|
|
expect(callArgs[1].data).toBe('ab')
|
|
})
|
|
|
|
test('should pad single hex digit with zero', async () => {
|
|
mockCustomRequest.mockResolvedValue({ success: true })
|
|
|
|
await provider.writeByte(0x20000000, 0x5)
|
|
|
|
const callArgs = mockCustomRequest.mock.calls[0]
|
|
expect(callArgs[1].data).toBe('05')
|
|
})
|
|
|
|
test('should handle 0x00 correctly', async () => {
|
|
mockCustomRequest.mockResolvedValue({ success: true })
|
|
|
|
await provider.writeByte(0x20000000, 0x00)
|
|
|
|
const callArgs = mockCustomRequest.mock.calls[0]
|
|
expect(callArgs[1].data).toBe('00')
|
|
})
|
|
|
|
test('should handle 0xFF correctly', async () => {
|
|
mockCustomRequest.mockResolvedValue({ success: true })
|
|
|
|
await provider.writeByte(0x20000000, 0xFF)
|
|
|
|
const callArgs = mockCustomRequest.mock.calls[0]
|
|
expect(callArgs[1].data).toBe('ff')
|
|
})
|
|
})
|
|
})
|