Skip to content

Commit

Permalink
Step out and inner frame state checks
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonpaulos committed Oct 18, 2023
1 parent a345eff commit 6e48656
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 11 deletions.
166 changes: 165 additions & 1 deletion tests/adapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ describe('Debug Adapter Tests', () => {

const programPath = path.join(DATA_ROOT, 'slot-machine/slot-machine.teal');

await client.hitBreakpoint({ program: programPath }, { path: programPath, line: 2 });
await client.hitBreakpoint({ program: simulateTracePath }, { path: programPath, line: 2 });

const label5Callsub = [
{ line: 97, column: 1 },
Expand Down Expand Up @@ -593,6 +593,170 @@ describe('Debug Adapter Tests', () => {
assert.notStrictEqual(currentFrame.source?.name, "slot-machine.teal", "Program has step locations beyond expected");
});
});

describe('Step out', () => {
it('should pause at the correct locations', async () => {
const simulateTracePath = path.join(DATA_ROOT, 'slot-machine/simulate-response.json');
await fixture.init(
simulateTracePath,
path.join(DATA_ROOT, 'slot-machine/sources.json')
);
const { client } = fixture;

const fakeRandomPath = path.join(DATA_ROOT, 'slot-machine/fake-random.teal');
const randomBytePath = path.join(DATA_ROOT, 'slot-machine/random-byte.teal');
const slotMachinePath = path.join(DATA_ROOT, 'slot-machine/slot-machine.teal');

await client.hitBreakpoint({ program: simulateTracePath }, { path: fakeRandomPath, line: 13 });

// clear breakpoint
await client.setBreakpointsRequest({
source: { path: fakeRandomPath },
breakpoints: []
});

interface LocationAndFrameState {
location: Location,
frameStates: Array<{
pc: number,
stack: Array<number | bigint | Uint8Array>,
} | null>,
}

const expectedLocations: LocationAndFrameState[] = [
{
location: {
program: fakeRandomPath,
name: "fake-random.teal",
line: 13,
column: 1
},
frameStates: [
{
pc: 33,
stack: [
Buffer.from('0000000001fa5f5d23', 'hex'),
Buffer.from('counter'),
],
},
null,
{
pc: 45,
stack: [],
},
null,
{
pc: 108,
stack: [],
},
null
],
},
{
location: {
program: randomBytePath,
name: "random-byte.teal",
line: 22,
column: 1
},
frameStates: [
{
pc: 46,
stack: [],
},
null,
{
pc: 108,
stack: [],
},
null
],
},
{
location: {
name: "inner-transaction-group-0-0.json",
line: 20,
column: 0
},
frameStates: [
null,
{
pc: 108,
stack: [],
},
null
],
},
{
location: {
program: slotMachinePath,
name: "slot-machine.teal",
line: 52,
column: 1
},
frameStates: [
{
pc: 109,
stack: [],
},
null
],
},
{
location: {
name: "transaction-group-0.json",
line: 40,
column: 0
},
frameStates: [
null
],
},
];

for (let i = 0; i < expectedLocations.length; i++) {
const expectedLocation = expectedLocations[i];
const stackTraceResponse = await client.stackTraceRequest({ threadId: 1 });
const currentFrame = stackTraceResponse.body.stackFrames[0];
const actualLocation: Location = {
name: currentFrame.source?.name!,
line: currentFrame.line,
column: currentFrame.column,
};
if (currentFrame.source?.path) {
actualLocation.program = currentFrame.source.path;
}
assert.deepStrictEqual(actualLocation, expectedLocation.location);

assert.strictEqual(stackTraceResponse.body.stackFrames.length, expectedLocation.frameStates.length);

for (let frameIndex = 0; frameIndex < expectedLocation.frameStates.length; frameIndex++) {
const expectedFrameState = expectedLocation.frameStates[frameIndex];
const frameId = stackTraceResponse.body.stackFrames[frameIndex].id;

if (expectedFrameState) {
await assertVariables(client, expectedFrameState, frameId);
} else {
const scopesResponse = await client.scopesRequest({ frameId });
assert.ok(scopesResponse.success);
const scopes = scopesResponse.body.scopes;

const executionScope = scopes.find(scope => scope.name.startsWith('Program State'));
assert.strictEqual(executionScope, undefined);
}
}

// Move to next location
await client.stepOutRequest({ threadId: 1 });
if (i + 1 < expectedLocations.length) {
const stoppedEvent = await client.waitForStop();
assert.strictEqual(stoppedEvent.body.reason, 'step');
} else {
await client.waitForEvent('terminated');
}
}
});
});
});

describe('Stack and scratch changes', () => {
Expand Down
22 changes: 12 additions & 10 deletions tests/testing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,14 @@ export async function assertVariables(dc: DebugClient, {
}>,
boxState?: ByteArrayMap<number | bigint | Uint8Array>,
}>,
}) {
const stackResponse = await dc.stackTraceRequest({ threadId: 1 });
assert.ok(stackResponse.success);
const latestFrame = stackResponse.body.stackFrames[0].id;
}, frameId?: number) {
if (typeof frameId === 'undefined') {
const stackResponse = await dc.stackTraceRequest({ threadId: 1 });
assert.ok(stackResponse.success);
frameId = stackResponse.body.stackFrames[0].id;
}

const scopesResponse = await dc.scopesRequest({ frameId: latestFrame });
const scopesResponse = await dc.scopesRequest({ frameId });
assert.ok(scopesResponse.success);
const scopes = scopesResponse.body.scopes;

Expand Down Expand Up @@ -137,7 +139,7 @@ export async function assertVariables(dc: DebugClient, {
assert.strictEqual(pcVariable.type, 'uint64');
assert.strictEqual(pcVariable.value, pc.toString());

await assertEvaluationEquals(dc, latestFrame, 'pc', { value: pc.toString(), type: 'uint64' });
await assertEvaluationEquals(dc, frameId, 'pc', { value: pc.toString(), type: 'uint64' });
}

if (typeof stack !== 'undefined') {
Expand All @@ -157,9 +159,9 @@ export async function assertVariables(dc: DebugClient, {

await Promise.all(stack.map(async (expectedValue, i) => {
if (expectedValue instanceof Uint8Array) {
await assertEvaluationEquals(dc, latestFrame, `stack[${i}]`, { value: '0x' + Buffer.from(expectedValue).toString('hex'), type: 'byte[]' });
await assertEvaluationEquals(dc, frameId!, `stack[${i}]`, { value: '0x' + Buffer.from(expectedValue).toString('hex'), type: 'byte[]' });
} else if (typeof expectedValue === 'number' || typeof expectedValue === 'bigint') {
await assertEvaluationEquals(dc, latestFrame, `stack[${i}]`, { value: expectedValue.toString(), type: 'uint64' });
await assertEvaluationEquals(dc, frameId!, `stack[${i}]`, { value: expectedValue.toString(), type: 'uint64' });
} else {
throw new Error(`Improper expected stack value: ${expectedValue}`);
}
Expand Down Expand Up @@ -198,9 +200,9 @@ export async function assertVariables(dc: DebugClient, {
}

if (expectedValue instanceof Uint8Array) {
await assertEvaluationEquals(dc, latestFrame, `scratch[${i}]`, { value: '0x' + Buffer.from(expectedValue).toString('hex'), type: 'byte[]' });
await assertEvaluationEquals(dc, frameId!, `scratch[${i}]`, { value: '0x' + Buffer.from(expectedValue).toString('hex'), type: 'byte[]' });
} else if (typeof expectedValue === 'number' || typeof expectedValue === 'bigint') {
await assertEvaluationEquals(dc, latestFrame, `scratch[${i}]`, { value: expectedValue.toString(), type: 'uint64' });
await assertEvaluationEquals(dc, frameId!, `scratch[${i}]`, { value: expectedValue.toString(), type: 'uint64' });
} else {
throw new Error(`Improper expected scratch value: ${expectedValue}`);
}
Expand Down

0 comments on commit 6e48656

Please sign in to comment.