Skip to content

Commit

Permalink
Properly normalize paths on windows
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonpaulos committed Dec 14, 2023
1 parent 00f7a19 commit 3dc62bb
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 72 deletions.
20 changes: 8 additions & 12 deletions src/common/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import {
TraceReplayStackFrame,
} from './traceReplayEngine';
import { FileAccessor } from './fileAccessor';
import { AvmDebuggingAssets, ProgramSourceDescriptor } from './utils';
import {
AvmDebuggingAssets,
ProgramSourceDescriptor,
normalizePathAndCasing,
} from './utils';

export interface IRuntimeBreakpoint {
id: number;
Expand Down Expand Up @@ -249,7 +253,7 @@ export class AvmRuntime extends EventEmitter {
line: number,
column?: number,
): IRuntimeBreakpoint {
path = this.normalizePathAndCasing(path);
path = normalizePathAndCasing(this.fileAccessor, path);

const bp: IRuntimeBreakpoint = {
verified: false,
Expand All @@ -269,7 +273,7 @@ export class AvmRuntime extends EventEmitter {
}

public clearBreakpoints(path: string): void {
this.breakPoints.delete(this.normalizePathAndCasing(path));
this.breakPoints.delete(normalizePathAndCasing(this.fileAccessor, path));
}

public getAppStateReferences(): number[] {
Expand Down Expand Up @@ -359,14 +363,6 @@ export class AvmRuntime extends EventEmitter {
}, 0);
}

private normalizePathAndCasing(filePath: string) {
if (this.fileAccessor.isWindows) {
return filePath.replace(/\//g, '\\');
} else {
return filePath.replace(/\\/g, '/');
}
}

private isFrameLocationOnBreakpoint(
location: FrameSourceLocation,
bp: IRuntimeBreakpointLocation,
Expand All @@ -386,7 +382,7 @@ export class AvmRuntime extends EventEmitter {
private findSourceDescriptorsForPath(
filePath: string,
): Array<{ descriptor: ProgramSourceDescriptor; sourceIndex: number }> {
filePath = this.normalizePathAndCasing(filePath);
filePath = normalizePathAndCasing(this.fileAccessor, filePath);

const sourceDescriptors: Array<{
descriptor: ProgramSourceDescriptor;
Expand Down
33 changes: 27 additions & 6 deletions src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,24 @@ export function utf8Decode(data: Uint8Array): string | undefined {
}
}

/**
* Normalize the given file path.
*
* On Windows, this will replace all forward slashes with backslashes and convert
* the path to lowercase, since Windows paths are case-insensitive.
*/
export function normalizePathAndCasing(
fileAccessor: FileAccessor,
filePath: string,
) {
if (fileAccessor.isWindows) {
// Normalize path to lowercase on Windows, since it is case-insensitive
return filePath.replace(/\//g, '\\').toLowerCase();
} else {
return filePath.replace(/\\/g, '/');
}
}

export function limitArray<T>(
array: Array<T>,
start?: number,
Expand Down Expand Up @@ -160,9 +178,12 @@ export class ProgramSourceDescriptor {
}

public getFullSourcePath(index: number): string {
return this.fileAccessor.filePathRelativeTo(
this.sourcemapFileLocation,
this.sourcemap.sources[index],
return normalizePathAndCasing(
this.fileAccessor,
this.fileAccessor.filePathRelativeTo(
this.sourcemapFileLocation,
this.sourcemap.sources[index],
),
);
}

Expand All @@ -171,9 +192,9 @@ export class ProgramSourceDescriptor {
originFile: string,
data: ProgramSourceEntry,
): Promise<ProgramSourceDescriptor> {
const sourcemapFileLocation = fileAccessor.filePathRelativeTo(
originFile,
data['sourcemap-location'],
const sourcemapFileLocation = normalizePathAndCasing(
fileAccessor,
fileAccessor.filePathRelativeTo(originFile, data['sourcemap-location']),
);
const rawSourcemap = await prefixPotentialError(
fileAccessor.readFile(sourcemapFileLocation),
Expand Down
137 changes: 84 additions & 53 deletions tests/adapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import * as assert from 'assert';
import * as path from 'path';
import * as algosdk from '../algosdk';
import { DebugProtocol } from '@vscode/debugprotocol';
import { ByteArrayMap } from '../src/common/utils';
import { ByteArrayMap, normalizePathAndCasing } from '../src/common/utils';
import { nodeFileAccessor } from '../src/node';
import { TestFixture, assertVariables, advanceTo, DATA_ROOT } from './testing';

describe('Debug Adapter Tests', () => {
Expand Down Expand Up @@ -209,9 +210,9 @@ describe('Debug Adapter Tests', () => {

describe('setBreakpoints', () => {
it('should stop on a breakpoint', async () => {
const PROGRAM = path.join(
DATA_ROOT,
'app-state-changes/state-changes.teal',
const PROGRAM = normalizePathAndCasing(
nodeFileAccessor,
path.join(DATA_ROOT, 'app-state-changes/state-changes.teal'),
);
const BREAKPOINT_LINE = 2;

Expand Down Expand Up @@ -275,9 +276,9 @@ describe('Debug Adapter Tests', () => {

let expectedStepOverLocationsSlotMachine: Location[];
{
const slotMachinePath = path.join(
DATA_ROOT,
'slot-machine/slot-machine.teal',
const slotMachinePath = normalizePathAndCasing(
nodeFileAccessor,
path.join(DATA_ROOT, 'slot-machine/slot-machine.teal'),
);

const label5Callsub = [
Expand Down Expand Up @@ -484,8 +485,14 @@ describe('Debug Adapter Tests', () => {
client.assertStoppedLocation('entry', {}),
]);

const lsigPath = path.join(DATA_ROOT, 'stepping-test/lsig.teal');
const appPath = path.join(DATA_ROOT, 'stepping-test/app.teal');
const lsigPath = normalizePathAndCasing(
nodeFileAccessor,
path.join(DATA_ROOT, 'stepping-test/lsig.teal'),
);
const appPath = normalizePathAndCasing(
nodeFileAccessor,
path.join(DATA_ROOT, 'stepping-test/app.teal'),
);
const expectedLocations: Location[] = [
{
name: 'transaction-group-0.json',
Expand Down Expand Up @@ -748,9 +755,9 @@ describe('Debug Adapter Tests', () => {
);
const { client } = fixture;

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

await client.hitBreakpoint(
Expand Down Expand Up @@ -812,17 +819,17 @@ describe('Debug Adapter Tests', () => {
);
const { client } = fixture;

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

await client.hitBreakpoint(
Expand Down Expand Up @@ -1125,7 +1132,10 @@ describe('Debug Adapter Tests', () => {
const currentFrame = stackTraceResponse.body.stackFrames[0];
assert.notStrictEqual(
currentFrame.source?.path,
path.join(DATA_ROOT, 'slot-machine/slot-machine.teal'),
normalizePathAndCasing(
nodeFileAccessor,
path.join(DATA_ROOT, 'slot-machine/slot-machine.teal'),
),
'Program has step locations beyond expected',
);
assert.notStrictEqual(
Expand All @@ -1150,7 +1160,10 @@ describe('Debug Adapter Tests', () => {
);

const { client } = fixture;
const PROGRAM = path.join(DATA_ROOT, 'stepping-test/lsig.teal');
const PROGRAM = normalizePathAndCasing(
nodeFileAccessor,
path.join(DATA_ROOT, 'stepping-test/lsig.teal'),
);

await client.hitBreakpoint(
{ simulateTraceFile, programSourcesDescriptionFile },
Expand Down Expand Up @@ -1192,9 +1205,9 @@ describe('Debug Adapter Tests', () => {
);
const { client } = fixture;

const PROGRAM = path.join(
DATA_ROOT,
'stack-scratch/stack-scratch.teal',
const PROGRAM = normalizePathAndCasing(
nodeFileAccessor,
path.join(DATA_ROOT, 'stack-scratch/stack-scratch.teal'),
);

await client.hitBreakpoint(
Expand Down Expand Up @@ -1307,9 +1320,9 @@ describe('Debug Adapter Tests', () => {
);

const { client } = fixture;
const PROGRAM = path.join(
DATA_ROOT,
'app-state-changes/state-changes.teal',
const PROGRAM = normalizePathAndCasing(
nodeFileAccessor,
path.join(DATA_ROOT, 'app-state-changes/state-changes.teal'),
);

await client.hitBreakpoint(
Expand Down Expand Up @@ -1404,9 +1417,9 @@ describe('Debug Adapter Tests', () => {
);

const { client } = fixture;
const PROGRAM = path.join(
DATA_ROOT,
'app-state-changes/state-changes.teal',
const PROGRAM = normalizePathAndCasing(
nodeFileAccessor,
path.join(DATA_ROOT, 'app-state-changes/state-changes.teal'),
);

await client.hitBreakpoint(
Expand Down Expand Up @@ -1537,9 +1550,9 @@ describe('Debug Adapter Tests', () => {
);

const { client } = fixture;
const PROGRAM = path.join(
DATA_ROOT,
'app-state-changes/state-changes.teal',
const PROGRAM = normalizePathAndCasing(
nodeFileAccessor,
path.join(DATA_ROOT, 'app-state-changes/state-changes.teal'),
);

await client.hitBreakpoint(
Expand Down Expand Up @@ -1630,7 +1643,10 @@ describe('Debug Adapter Tests', () => {

const testSources: SourceInfo[] = [
{
path: path.join(DATA_ROOT, 'sourcemap-test/sourcemap-test.teal'),
path: normalizePathAndCasing(
nodeFileAccessor,
path.join(DATA_ROOT, 'sourcemap-test/sourcemap-test.teal'),
),
validBreakpoints: [
{ line: 4, column: 1 },
{ line: 4, column: 20 },
Expand All @@ -1647,7 +1663,10 @@ describe('Debug Adapter Tests', () => {
],
},
{
path: path.join(DATA_ROOT, 'sourcemap-test/lib.teal'),
path: normalizePathAndCasing(
nodeFileAccessor,
path.join(DATA_ROOT, 'sourcemap-test/lib.teal'),
),
validBreakpoints: [
{ line: 2, column: 22 },
{ line: 2, column: 26 },
Expand Down Expand Up @@ -1808,7 +1827,10 @@ describe('Debug Adapter Tests', () => {

const result = await client.setBreakpointsRequest({
source: {
path: path.join(DATA_ROOT, 'sourcemap-test/sourcemap-test.teal'),
path: normalizePathAndCasing(
nodeFileAccessor,
path.join(DATA_ROOT, 'sourcemap-test/sourcemap-test.teal'),
),
},
breakpoints: [
{ line: 0, column: 0 },
Expand Down Expand Up @@ -1840,7 +1862,10 @@ describe('Debug Adapter Tests', () => {
);
const { client } = fixture;

const program = path.join(DATA_ROOT, 'errors/inner-app/inner.teal');
const program = normalizePathAndCasing(
nodeFileAccessor,
path.join(DATA_ROOT, 'errors/inner-app/inner.teal'),
);

await Promise.all([
client.configurationSequence(),
Expand Down Expand Up @@ -1989,7 +2014,10 @@ describe('Debug Adapter Tests', () => {
// And backwards again
await client.stepBackRequest({ threadId: 1 });
await client.assertStoppedLocation('step', {
path: path.join(DATA_ROOT, 'errors/inner-app/outer.teal'),
path: normalizePathAndCasing(
nodeFileAccessor,
path.join(DATA_ROOT, 'errors/inner-app/outer.teal'),
),
line: 12,
column: 1,
});
Expand Down Expand Up @@ -2020,7 +2048,10 @@ describe('Debug Adapter Tests', () => {
);
const { client } = fixture;

const program = path.join(DATA_ROOT, 'errors/logicsig/lsig-err.teal');
const program = normalizePathAndCasing(
nodeFileAccessor,
path.join(DATA_ROOT, 'errors/logicsig/lsig-err.teal'),
);

await Promise.all([
client.configurationSequence(),
Expand Down Expand Up @@ -2110,13 +2141,13 @@ describe('Debug Adapter Tests', () => {
);
const { client } = fixture;

const lsigProgram = path.join(
DATA_ROOT,
'errors/app-from-logicsig/nine.teal',
const lsigProgram = normalizePathAndCasing(
nodeFileAccessor,
path.join(DATA_ROOT, 'errors/app-from-logicsig/nine.teal'),
);
const appProgram = path.join(
DATA_ROOT,
'errors/app-from-logicsig/inner.teal',
const appProgram = normalizePathAndCasing(
nodeFileAccessor,
path.join(DATA_ROOT, 'errors/app-from-logicsig/inner.teal'),
);

await client.hitBreakpoint(
Expand Down Expand Up @@ -2164,13 +2195,13 @@ describe('Debug Adapter Tests', () => {
);
const { client } = fixture;

const lsigProgram = path.join(
DATA_ROOT,
'errors/logicsig-after-error/nine.teal',
const lsigProgram = normalizePathAndCasing(
nodeFileAccessor,
path.join(DATA_ROOT, 'errors/logicsig-after-error/nine.teal'),
);
const appProgram = path.join(
DATA_ROOT,
'errors/logicsig-after-error/inner.teal',
const appProgram = normalizePathAndCasing(
nodeFileAccessor,
path.join(DATA_ROOT, 'errors/logicsig-after-error/inner.teal'),
);

await Promise.all([
Expand Down
2 changes: 1 addition & 1 deletion tests/node/fileAccessor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ describe('Node FileAccessor Tests', () => {
function getExampleAbsolutePathFor(filename: string): string {
let base: string;
if (nodeFileAccessor.isWindows) {
base = 'C:\\somelongpath\\sources';
base = 'c:\\somelongpath\\sources';
} else {
base = '/somelongpath/sources';
}
Expand Down

0 comments on commit 3dc62bb

Please sign in to comment.