From c7e84cdff794a974e30bf766990411375cb3ca5c Mon Sep 17 00:00:00 2001 From: Joshua Horton Date: Fri, 8 Aug 2025 09:40:31 -0500 Subject: [PATCH] change(web): moves isSubstitutionAlignable unit tests --- .../cases/edit-distance/alignment-helpers.js | 76 +++++++++++++++++++ .../edit-distance/context-tokenization.js | 73 ------------------ 2 files changed, 76 insertions(+), 73 deletions(-) create mode 100644 web/src/engine/predictive-text/worker-thread/src/tests/mocha/cases/edit-distance/alignment-helpers.js diff --git a/web/src/engine/predictive-text/worker-thread/src/tests/mocha/cases/edit-distance/alignment-helpers.js b/web/src/engine/predictive-text/worker-thread/src/tests/mocha/cases/edit-distance/alignment-helpers.js new file mode 100644 index 0000000000..d36c0a8a79 --- /dev/null +++ b/web/src/engine/predictive-text/worker-thread/src/tests/mocha/cases/edit-distance/alignment-helpers.js @@ -0,0 +1,76 @@ +import { assert } from 'chai'; +import { getEditPathLastMatch, isSubstitutionAlignable } from '#./correction/alignment-helpers.js'; + + +describe('isSubstitutionAlignable', () => { + it(`returns true: 'ca' => 'can'`, () => { + assert.isTrue(isSubstitutionAlignable('can', 'ca')); + }); + + // Leading word in context window starts sliding out of said window. + it(`returns true: 'can' => 'an'`, () => { + assert.isTrue(isSubstitutionAlignable('an', 'can')); + }); + + // Same edits on both sides: not valid. + it(`returns false: 'apple' => 'grapples'`, () => { + assert.isFalse(isSubstitutionAlignable('grapples', 'apple')); + }); + + // Edits on one side: valid. + it(`returns true: 'apple' => 'grapple'`, () => { + assert.isTrue(isSubstitutionAlignable('grapple', 'apple')); + }); + + // Edits on one side: valid. + it(`returns true: 'apple' => 'grapple'`, () => { + assert.isTrue(isSubstitutionAlignable('apples', 'apple')); + }); + + // Same edits on both sides: not valid. + it(`returns false: 'grapples' => 'apple'`, () => { + assert.isFalse(isSubstitutionAlignable('apple', 'grapples')); + }); + + // Substitution: not valid when not permitted via parameter. + it(`returns false: 'apple' => 'banana'`, () => { + // edit path: 'insert' ('b' of banana), 'match' (on leading a), rest are 'substitute'. + assert.isFalse(isSubstitutionAlignable('banana', 'apple')); + }); + + // Substitution: not valid if too much is substituted, even if allowed via parameter. + it(`returns false: 'apple' => 'banana' (subs allowed)`, () => { + // edit path: 'insert' ('b' of banana), 'match' (on leading a), rest are 'substitute'. + // 1 match vs 4 substitute = no bueno. It'd require too niche of a keyboard rule. + assert.isFalse(isSubstitutionAlignable('banana', 'apple', true)); + }); + + it(`returns true: 'a' => 'à' (subs allowed)`, () => { + assert.isTrue(isSubstitutionAlignable('à', 'a', true)); + }); + + // Leading substitution: valid if enough of the remaining word matches. + // Could totally happen from a legit Keyman keyboard rule. + it(`returns true: 'can' => 'van' (subs allowed)`, () => { + assert.isTrue(isSubstitutionAlignable('van', 'can', true)); + }); + + // Trailing substitution: invalid if not allowed. + it(`returns false: 'can' => 'cap' (subs not allowed)`, () => { + assert.isFalse(isSubstitutionAlignable('cap', 'can')); + }); + + // Trailing substitution: valid. + it(`returns false: 'can' => 'cap' (subs allowed)`, () => { + assert.isTrue(isSubstitutionAlignable('cap', 'can', true)); + }); + + it(`returns true: 'clasts' => 'clasps' (subs allowed)`, () => { + assert.isTrue(isSubstitutionAlignable('clasps', 'clasts', true)); + }); + + // random deletion at the start + later substitution = still permitted + it(`returns false: 'clasts' => 'lasps' (subs allowed)`, () => { + assert.isTrue(isSubstitutionAlignable('lasps', 'clasts', true)); + }); +}); \ No newline at end of file diff --git a/web/src/engine/predictive-text/worker-thread/src/tests/mocha/cases/edit-distance/context-tokenization.js b/web/src/engine/predictive-text/worker-thread/src/tests/mocha/cases/edit-distance/context-tokenization.js index a263c233c4..e1ee95654f 100644 --- a/web/src/engine/predictive-text/worker-thread/src/tests/mocha/cases/edit-distance/context-tokenization.js +++ b/web/src/engine/predictive-text/worker-thread/src/tests/mocha/cases/edit-distance/context-tokenization.js @@ -20,79 +20,6 @@ function toToken(text) { return token; } -describe('isSubstitutionAlignable', () => { - it(`returns true: 'ca' => 'can'`, () => { - assert.isTrue(isSubstitutionAlignable('can', 'ca')); - }); - - // Leading word in context window starts sliding out of said window. - it(`returns true: 'can' => 'an'`, () => { - assert.isTrue(isSubstitutionAlignable('an', 'can')); - }); - - // Same edits on both sides: not valid. - it(`returns false: 'apple' => 'grapples'`, () => { - assert.isFalse(isSubstitutionAlignable('grapples', 'apple')); - }); - - // Edits on one side: valid. - it(`returns true: 'apple' => 'grapple'`, () => { - assert.isTrue(isSubstitutionAlignable('grapple', 'apple')); - }); - - // Edits on one side: valid. - it(`returns true: 'apple' => 'grapple'`, () => { - assert.isTrue(isSubstitutionAlignable('apples', 'apple')); - }); - - // Same edits on both sides: not valid. - it(`returns false: 'grapples' => 'apple'`, () => { - assert.isFalse(isSubstitutionAlignable('apple', 'grapples')); - }); - - // Substitution: not valid when not permitted via parameter. - it(`returns false: 'apple' => 'banana'`, () => { - // edit path: 'insert' ('b' of banana), 'match' (on leading a), rest are 'substitute'. - assert.isFalse(isSubstitutionAlignable('banana', 'apple')); - }); - - // Substitution: not valid if too much is substituted, even if allowed via parameter. - it(`returns false: 'apple' => 'banana' (subs allowed)`, () => { - // edit path: 'insert' ('b' of banana), 'match' (on leading a), rest are 'substitute'. - // 1 match vs 4 substitute = no bueno. It'd require too niche of a keyboard rule. - assert.isFalse(isSubstitutionAlignable('banana', 'apple', true)); - }); - - it(`returns true: 'a' => 'à' (subs allowed)`, () => { - assert.isTrue(isSubstitutionAlignable('à', 'a', true)); - }); - - // Leading substitution: valid if enough of the remaining word matches. - // Could totally happen from a legit Keyman keyboard rule. - it(`returns true: 'can' => 'van' (subs allowed)`, () => { - assert.isTrue(isSubstitutionAlignable('van', 'can', true)); - }); - - // Trailing substitution: invalid if not allowed. - it(`returns false: 'can' => 'cap' (subs not allowed)`, () => { - assert.isFalse(isSubstitutionAlignable('cap', 'can')); - }); - - // Trailing substitution: valid. - it(`returns false: 'can' => 'cap' (subs allowed)`, () => { - assert.isTrue(isSubstitutionAlignable('cap', 'can', true)); - }); - - it(`returns true: 'clasts' => 'clasps' (subs allowed)`, () => { - assert.isTrue(isSubstitutionAlignable('clasps', 'clasts', true)); - }); - - // random deletion at the start + later substitution = still permitted - it(`returns false: 'clasts' => 'lasps' (subs allowed)`, () => { - assert.isTrue(isSubstitutionAlignable('lasps', 'clasts', true)); - }); -}); - describe('ContextTokenization', function() { describe("", () => { it("constructs from just a token array", () => {