Skip to content

Commit

Permalink
Expose some fixture abstractions
Browse files Browse the repository at this point in the history
  • Loading branch information
pokey committed Jul 4, 2024
1 parent 45b42d6 commit 0e7897c
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 69 deletions.
2 changes: 2 additions & 0 deletions packages/common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export * from "./types/ScopeProvider";
export * from "./types/SpokenForm";
export * from "./types/commandHistory";
export * from "./util/textFormatters";
export * from "./util/serializedMarksToTokenHats";
export * from "./types/snippet.types";
export * from "./testUtil/fromPlainObject";
export * from "./testUtil/spyToPlainObject";
Expand All @@ -68,6 +69,7 @@ export * from "./testUtil/serialize";
export * from "./testUtil/shouldUpdateFixtures";
export * from "./testUtil/TestCaseSnapshot";
export * from "./testUtil/serializeTestFixture";
export * from "./testUtil/getResultStateForComparison";
export * from "./testUtil/asyncSafety";
export * from "./testUtil/getScopeTestPathsRecursively";
export * from "./util/typeUtils";
Expand Down
10 changes: 10 additions & 0 deletions packages/common/src/testUtil/getFixturePaths.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import * as yaml from "js-yaml";
import * as path from "path";
import { walkFilesSync } from "../util/walkSync";
import { getCursorlessRepoRoot } from "./getCursorlessRepoRoot";
import { TestCaseFixtureLegacy } from "../types/TestCaseFixture";
import { readFile } from "node:fs/promises";

export function getFixturesPath() {
return path.join(getCursorlessRepoRoot(), "data", "fixtures");
Expand Down Expand Up @@ -67,3 +70,10 @@ function pathToName(relativeDir: string, filePath: string) {
.relative(relativeDir, filePath.substring(0, filePath.lastIndexOf(".")))
.replaceAll("\\", "/");
}

export async function loadFixture(
path: string,
): Promise<TestCaseFixtureLegacy> {
const buffer = await readFile(path);
return yaml.load(buffer.toString()) as TestCaseFixtureLegacy;
}
46 changes: 46 additions & 0 deletions packages/common/src/testUtil/getResultStateForComparison.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { storedTargetKeys } from "../StoredTargetKey";
import SpyIDE from "../ide/spy/SpyIDE";
import { ReadOnlyHatMap } from "../types/HatTokenMap";
import { marksToPlainObject } from "../util/toPlainObject";
import { ExcludableSnapshotField, TestCaseSnapshot } from "./TestCaseSnapshot";
import { extractTargetedMarks } from "./extractTargetedMarks";
import { TestHelpers } from "./runRecordedTest";

export async function getResultStateForComparison(
finalState: TestCaseSnapshot | undefined,
readableHatMap: ReadOnlyHatMap,
spyIde: SpyIDE,
takeSnapshot: TestHelpers["takeSnapshot"],
) {
const excludeFields: ExcludableSnapshotField[] = [];

const marks =
finalState?.marks == null
? undefined
: marksToPlainObject(
extractTargetedMarks(Object.keys(finalState.marks), readableHatMap),
);

if (finalState?.clipboard == null) {
excludeFields.push("clipboard");
}

for (const storedTargetKey of storedTargetKeys) {
const key = `${storedTargetKey}Mark` as const;
if (finalState?.[key] == null) {
excludeFields.push(key);
}
}

// FIXME Visible ranges are not asserted, see:
// https://github.com/cursorless-dev/cursorless/issues/160
const { visibleRanges, ...resultState } = await takeSnapshot(
excludeFields,
[],
spyIde.activeTextEditor!,
spyIde,
marks,
);

return resultState;
}
80 changes: 12 additions & 68 deletions packages/common/src/testUtil/runRecordedTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,21 @@ import {
TestCaseFixtureLegacy,
TestCaseSnapshot,
TextEditor,
TokenHat,
clientSupportsFallback,
extractTargetedMarks,
marksToPlainObject,
loadFixture,
omitByDeep,
plainObjectToRange,
rangeToPlainObject,
serializeTestFixture,
serializedMarksToTokenHats,
shouldUpdateFixtures,
splitKey,
spyIDERecordedValuesToPlainObject,
storedTargetKeys,
} from "@cursorless/common";
import { assert } from "chai";
import * as yaml from "js-yaml";
import { isUndefined } from "lodash";
import { promises as fsp } from "node:fs";
import { getResultStateForComparison } from "./getResultStateForComparison";

function createPosition(position: PositionPlainObject) {
return new Position(position.line, position.character);
Expand Down Expand Up @@ -123,9 +121,7 @@ export async function runRecordedTest({
testHelpers,
runCursorlessCommand,
}: RunRecordedTestOpts) {
const buffer = await fsp.readFile(path);
const fixture = yaml.load(buffer.toString()) as TestCaseFixtureLegacy;
const excludeFields: ExcludableSnapshotField[] = [];
const fixture = await loadFixture(path);

// FIXME The snapshot gets messed up with timing issues when running the recorded tests
// "Couldn't find token default.a"
Expand Down Expand Up @@ -162,7 +158,10 @@ export async function runRecordedTest({

// Ensure that the expected hats are present
await hatTokenMap.allocateHats(
getTokenHats(fixture.initialState.marks, spyIde.activeTextEditor!),
serializedMarksToTokenHats(
fixture.initialState.marks,
spyIde.activeTextEditor!,
),
);

const readableHatMap = await hatTokenMap.getReadableMap(usePrePhraseSnapshot);
Expand Down Expand Up @@ -217,35 +216,11 @@ export async function runRecordedTest({
await sleepWithBackoff(fixture.postCommandSleepTimeMs);
}

const marks =
fixture.finalState?.marks == null
? undefined
: marksToPlainObject(
extractTargetedMarks(
Object.keys(fixture.finalState.marks),
readableHatMap,
),
);

if (fixture.finalState?.clipboard == null) {
excludeFields.push("clipboard");
}

for (const storedTargetKey of storedTargetKeys) {
const key = `${storedTargetKey}Mark` as const;
if (fixture.finalState?.[key] == null) {
excludeFields.push(key);
}
}

// FIXME Visible ranges are not asserted, see:
// https://github.com/cursorless-dev/cursorless/issues/160
const { visibleRanges, ...resultState } = await takeSnapshot(
excludeFields,
[],
spyIde.activeTextEditor!,
const resultState = await getResultStateForComparison(
fixture.finalState,
readableHatMap,
spyIde,
marks,
takeSnapshot,
);

const rawSpyIdeValues = spyIde.getSpyValues(fixture.ide?.flashes != null);
Expand Down Expand Up @@ -313,34 +288,3 @@ function checkMarks(
assert.deepStrictEqual(rangeToPlainObject(currentToken.range), token);
});
}

function getTokenHats(
marks: SerializedMarks | undefined,
editor: TextEditor,
): TokenHat[] {
if (marks == null) {
return [];
}

return Object.entries(marks).map(([key, token]) => {
const { hatStyle, character } = splitKey(key);
const range = plainObjectToRange(token);

return {
hatStyle,
grapheme: character,
token: {
editor,
range,
offsets: {
start: editor.document.offsetAt(range.start),
end: editor.document.offsetAt(range.end),
},
text: editor.document.getText(range),
},

// NB: We don't care about the hat range for this test
hatRange: range,
};
});
}
36 changes: 36 additions & 0 deletions packages/common/src/util/serializedMarksToTokenHats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { plainObjectToRange } from "../testUtil/fromPlainObject";
import { splitKey } from "./splitKey";
import { SerializedMarks } from "./toPlainObject";
import { TextEditor } from "../types/TextEditor";
import { TokenHat } from "../types/HatTokenMap";

export function serializedMarksToTokenHats(
marks: SerializedMarks | undefined,
editor: TextEditor,
): TokenHat[] {
if (marks == null) {
return [];
}

return Object.entries(marks).map(([key, token]) => {
const { hatStyle, character } = splitKey(key);
const range = plainObjectToRange(token);

return {
hatStyle,
grapheme: character,
token: {
editor,
range,
offsets: {
start: editor.document.offsetAt(range.start),
end: editor.document.offsetAt(range.end),
},
text: editor.document.getText(range),
},

// NB: We don't care about the hat range for this test
hatRange: range,
};
});
}
2 changes: 1 addition & 1 deletion packages/cursorless-engine/src/core/IndividualHatMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export class IndividualHatMap implements ReadOnlyHatMap {
}

/**
* Overwrites the hat assignemnt for this hat token map.
* Overwrites the hat assignment for this hat token map.
*
* @param tokenHats The new hat assignments
*/
Expand Down

0 comments on commit 0e7897c

Please sign in to comment.