Skip to content

Commit

Permalink
fix(developer): support loose match for CompilerEvents
Browse files Browse the repository at this point in the history
Fixes: feat(developer): tests CompilerMessage  matching should be loose #10943

(also gets us working on Node 20)
  • Loading branch information
srl295 committed Mar 5, 2024
1 parent bc01a01 commit de50372
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 11 deletions.
67 changes: 59 additions & 8 deletions developer/src/kmc-ldml/test/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,55 @@ export function checkMessages() {
assert.isEmpty(compilerTestCallbacks.messages, compilerEventFormat(compilerTestCallbacks.messages));
}

/**
* Like CompilerEvent, but supports regex matching.
*/
interface CompilerMatch {
/** code of the event */
code: number;
/** regex that matches 'message' */
matchMessage: RegExp;
};

/** Union type for a CompilerEvent or a CompilerMatch */
export type CompilerEventOrMatch = CompilerEvent | CompilerMatch;

/** @returns true if 'm' matches 'e' */
export function matchCompilerEvent(e: CompilerEvent, m: CompilerMatch): boolean {
return (e.code === m.code) && (m.matchMessage.test(e.message));
}

/** @returns the first of events which matches m. Or m, if it's a CompilerEvent */
function findMatchingCompilerEvent(events: CompilerEvent[], m: CompilerEventOrMatch): CompilerEventOrMatch {
const asMatch = <CompilerMatch> m;
if (!asMatch.matchMessage) {
// it's not a valid CompilerMatch, just return it
return m;
}

for (const e of events) {
if (matchCompilerEvent(e, asMatch)) {
return e;
}
}
return null;
}
/**
* for any matched events, substitute them with the original CompilerEvent
* for any non-matching item, leave as is so that tests will fail
*/
export function matchCompilerEvents(events: CompilerEvent[], matches?: CompilerEventOrMatch[]): CompilerEventOrMatch[] {
// pass through if there's no processing to be done
if (!events || !matches) return matches;
return matches.map(e => findMatchingCompilerEvent(events, e) || e);
}

/** as above, but passes through true/false */
function matchCompilerEventsOrBoolean(events: CompilerEvent[], matches?: CompilerEventOrMatch[] | boolean) : CompilerEventOrMatch[] | boolean {
if(matches === true || matches === false) return matches;
return matchCompilerEvents(events, matches);
}

export interface CompilationCase {
/** if true, expect no further errors than what's in errors. */
strictErrors?: boolean;
Expand All @@ -195,11 +244,11 @@ export interface CompilationCase {
/**
* expected error messages. If falsy, expected to succeed. All must be present to pass.
*/
errors?: CompilerEvent[] | boolean;
errors?: CompilerEventOrMatch[] | boolean;
/**
* expected warning messages. All must be present to pass.
*/
warnings?: CompilerEvent[];
warnings?: CompilerEventOrMatch[];
/**
* optional callback with the section
*/
Expand Down Expand Up @@ -245,15 +294,17 @@ export function testCompilationCases(compiler: SectionCompilerNew, cases : Compi
assert.isNotNull(section, `failed with ${compilerEventFormat(callbacks.messages)}`);
}

const testcaseErrors = matchCompilerEventsOrBoolean(callbacks.messages, testcase.errors);
const testcaseWarnings = matchCompilerEvents(callbacks.messages, testcase.warnings);
// if we expected errors or warnings, show them
if (testcase.errors && testcase.errors !== true) {
assert.includeDeepMembers(callbacks.messages, <CompilerEvent[]> testcase.errors, 'expected errors to be included');
if (testcaseErrors && testcaseErrors !== true) {
assert.includeDeepMembers(callbacks.messages, <CompilerEventOrMatch[]>testcaseErrors, 'expected errors to be included');
}
if (testcase.errors && testcase.strictErrors) {
assert.sameDeepMembers(callbacks.messages, <CompilerEvent[]> testcase.errors, 'expected same errors to be included');
if (testcaseErrors && testcase.strictErrors) {
assert.sameDeepMembers(callbacks.messages, <CompilerEventOrMatch[]>testcaseErrors, 'expected same errors to be included');
}
if (testcase.warnings) {
assert.includeDeepMembers(callbacks.messages, testcase.warnings, 'expected warnings to be included');
if (testcaseWarnings) {
assert.includeDeepMembers(callbacks.messages, testcaseWarnings, 'expected warnings to be included');
} else if (!expectFailure) {
// no warnings, so expect zero messages
assert.sameDeepMembers(callbacks.messages, [], 'expected zero messages but got ' + callbacks.messages);
Expand Down
34 changes: 34 additions & 0 deletions developer/src/kmc-ldml/test/test-helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { CompilerEvent } from '@keymanapp/common-types';
import 'mocha';
import {assert} from 'chai';
import { CompilerEventOrMatch, matchCompilerEvents } from './helpers/index.js';
import { CompilerMessages } from '../src/compiler/messages.js';


describe('test of test/helpers/CompilerMatch', () => {
/** the message(s) to test */
const messages : CompilerEvent[] = [
CompilerMessages.Error_InvalidHardware({ formId: 'outdated' }),
CompilerMessages.Hint_NormalizationDisabled(),
];

it('should work for exact matches', () => {
const spec : CompilerEventOrMatch[] = [
CompilerMessages.Hint_NormalizationDisabled(),
CompilerMessages.Error_InvalidHardware({ formId: 'outdated' }),
];
const matched = matchCompilerEvents(messages, spec);
assert.sameDeepMembers(messages, spec); // exact match works here
assert.sameDeepMembers(messages, matched);
});
it('should work for a fuzzy matches', () => {
const spec : CompilerEventOrMatch[] = [
// mixed messages here - this one is a CompilerEvent
CompilerMessages.Hint_NormalizationDisabled(),
// fuzzy match on this one - CompilerMatch
{ code: CompilerMessages.ERROR_InvalidHardware, matchMessage: /(out|up|inun)dated/ },
];
const matched = matchCompilerEvents(messages, spec);
assert.sameDeepMembers(messages, matched);
});
});
6 changes: 3 additions & 3 deletions developer/src/kmc-ldml/test/test-tran.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,9 +286,9 @@ describe('tran', function () {
{
subpath: `sections/tran/fail-bad-tran-1.xml`,
errors: [
CompilerMessages.Error_UnparseableTransformFrom({ from: 'AB(now if only I would terminate this group..',
// this message is dependent on v8, so this test could be a little brittle.
message: 'Invalid regular expression: /AB(now if only I would terminate this group../: Unterminated group' }),
{ code: CompilerMessages.ERROR_UnparseableTransformFrom,
matchMessage: /Invalid regular expression.*Unterminated group/,
}
],
},
{
Expand Down

0 comments on commit de50372

Please sign in to comment.