Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 27 additions & 102 deletions packages/pyright-scip/src/assertions.ts
Original file line number Diff line number Diff line change
@@ -1,126 +1,51 @@
import { normalizePathCase, isFileSystemCaseSensitive } from 'pyright-internal/common/pathUtils';
import { normalizePathCase } from 'pyright-internal/common/pathUtils';
import { PyrightFileSystem } from 'pyright-internal/pyrightFileSystem';
import { createFromRealFileSystem } from 'pyright-internal/common/realFileSystem';

export enum SeenCondition {
AlwaysFalse = 'always-false',
AlwaysTrue = 'always-true',
Mixed = 'mixed',
}

export class AssertionError extends Error {
constructor(message: string) {
super(message);
this.name = 'AssertionError';
}
}

// Private global state - never export directly
let _assertionFlags = {
pathNormalizationChecks: false,
otherChecks: false,
};
let _context = '';
const _sometimesResults = new Map<string, Map<string, SeenCondition>>();

export function setGlobalAssertionFlags(pathNormalizationChecks: boolean, otherChecks: boolean): void {
_assertionFlags.pathNormalizationChecks = pathNormalizationChecks;
_assertionFlags.otherChecks = otherChecks;
}

export function setGlobalContext(context: string): void {
_context = context;
}

// Internal implementation functions
function assertAlwaysImpl(enableFlag: boolean, check: () => boolean, message: () => string): void {
if (!enableFlag) return;

if (!check()) {
throw new AssertionError(message());
}
}

function assertSometimesImpl(enableFlag: boolean, check: () => boolean, key: string): void {
if (!enableFlag) return;

const ctx = _context;
if (ctx === '') {
throw new AssertionError('Context must be set before calling assertSometimes');
}

let ctxMap = _sometimesResults.get(key);
if (!ctxMap) {
ctxMap = new Map();
_sometimesResults.set(key, ctxMap);
}

const result = check() ? SeenCondition.AlwaysTrue : SeenCondition.AlwaysFalse;
const prev = ctxMap.get(ctx);

if (prev === undefined) {
ctxMap.set(ctx, result);
} else if (prev !== result) {
ctxMap.set(ctx, SeenCondition.Mixed);
}
}

const _fs = new PyrightFileSystem(createFromRealFileSystem());
const sometimesResults = new Map<string, Set<boolean>>();

export function assertAlways(check: () => boolean, message: () => string): void {
assertAlwaysImpl(_assertionFlags.otherChecks, check, message);
}

export function assertSometimes(check: () => boolean, key: string): void {
assertSometimesImpl(_assertionFlags.otherChecks, check, key);
}
// Only enable assertions in test mode
const isTestMode = process.env.NODE_ENV === 'test' || process.env.JEST_WORKER_ID !== undefined;

export function assertNeverNormalized(path: string): void {
if (!isTestMode) return;

const normalized = normalizePathCase(_fs, path);
assertAlwaysImpl(
_assertionFlags.pathNormalizationChecks,
() => normalized !== path,
() => `Path should not be normalized but was: ${path}`
);
if (normalized === path) {
throw new Error(`Path should not be normalized but was: ${path}`);
}
}

export function assertAlwaysNormalized(path: string): void {
if (!isTestMode) return;

const normalized = normalizePathCase(_fs, path);
assertAlwaysImpl(
_assertionFlags.pathNormalizationChecks,
() => normalized === path,
() => `Path should be normalized but was not: ${path} -> ${normalized}`
);
if (normalized !== path) {
throw new Error(`Path should be normalized but was not: ${path} -> ${normalized}`);
}
}

export function assertSometimesNormalized(path: string, key: string): void {
if (!isTestMode) return;

const normalized = normalizePathCase(_fs, path);
assertSometimesImpl(_assertionFlags.pathNormalizationChecks, () => normalized === path, key);
}
const isNormalized = normalized === path;

// Monoidal combination logic
function combine(a: SeenCondition, b: SeenCondition): SeenCondition {
if (a === b) return a;
if (a === SeenCondition.Mixed || b === SeenCondition.Mixed) {
return SeenCondition.Mixed;
if (!sometimesResults.has(key)) {
sometimesResults.set(key, new Set());
}
// AlwaysTrue + AlwaysFalse = Mixed
return SeenCondition.Mixed;
sometimesResults.get(key)!.add(isNormalized);
}

export function checkSometimesAssertions(): Map<string, SeenCondition> {
const summary = new Map<string, SeenCondition>();
export function checkSometimesAssertions(): void {
if (!isTestMode) return;

for (const [key, ctxMap] of _sometimesResults) {
let agg: SeenCondition | undefined;
for (const state of ctxMap.values()) {
agg = agg === undefined ? state : combine(agg, state);
if (agg === SeenCondition.Mixed) break;
}
if (agg !== undefined) {
summary.set(key, agg);
for (const [key, values] of sometimesResults) {
// We should see both true and false for "sometimes" assertions
if (values.size <= 1) {
console.warn(`Assertion '${key}' was not mixed across test contexts`);
}
}

return summary;
sometimesResults.clear();
}
187 changes: 0 additions & 187 deletions packages/pyright-scip/src/test-runner.ts

This file was deleted.

Loading
Loading