mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-15 21:29:23 +00:00
Merge branch 'change/web/context-tracker-backspaces-and-alignment' into fix/web/context-match-path-ordering
This commit is contained in:
commit
cbf86b355f
8 changed files with 560 additions and 15 deletions
29
HISTORY.md
29
HISTORY.md
|
|
@ -1,5 +1,21 @@
|
|||
# Keyman Version History
|
||||
|
||||
## 18.0.172 alpha 2025-01-19
|
||||
|
||||
* chore(common): Add 17.0.333 to version history (#12926)
|
||||
|
||||
## 18.0.171 alpha 2025-01-18
|
||||
|
||||
* fix(common/web): add StrsItem.isEqual() method (#12868)
|
||||
* fix(common/web): handle invalid order and tertiary arguments to ElementString.fromString() (#12882)
|
||||
|
||||
## 18.0.170 alpha 2025-01-17
|
||||
|
||||
* chore(linux): update copyright year (#12918)
|
||||
* fix(web): patch unit test with execution dependent on autocorrect state (#12940)
|
||||
* test(common/web): unit tests for element-string (#12811)
|
||||
* chore(linux): Update debian changelog (#12917)
|
||||
|
||||
## 18.0.169 alpha 2025-01-17
|
||||
|
||||
* chore(windows): remove `postinstall` state from mermaid diagram (#12923)
|
||||
|
|
@ -953,7 +969,7 @@
|
|||
## 18.0.41 alpha 2024-05-22
|
||||
|
||||
* fix(developer): handle `KM_CORE_IT_INVALIDATE_CONTEXT` in debugger (#11488)
|
||||
* chore(linux): Trigger GHA packaging for stable builds :cherries: (#11495)
|
||||
* chore(linux): Trigger GHA packaging for stable builds (#11495)
|
||||
* chore(android,mac,windows): Update crowdin strings for DE (#11497)
|
||||
* feat(web): custom infrastructure for @web/test-runner use (#11403)
|
||||
* chore(web): conversion of lm-worker browser-test for @web/test-runner use (#11404)
|
||||
|
|
@ -1149,6 +1165,17 @@
|
|||
* chore(common): move to 18.0 alpha (#10713)
|
||||
* chore: move to 18.0 alpha
|
||||
|
||||
## 17.0.333 stable 2025-01-16
|
||||
|
||||
* fix(core): permanently disable logging (#12674)
|
||||
* fix(linux): pushing of updated changelog branch (#12819)
|
||||
* fix(linux): work around Lintian errors (#12817)
|
||||
* fix(core): implement ldml_processor::get_key_list() (#12816)
|
||||
* chore(linux): Update debian changelog (#12022)
|
||||
* fix(android): use main looper to dispatch key events when OSK is hidden (#12875)
|
||||
* chore: use GitHub PR titles when writing HISTORY.md (#12908)
|
||||
* fix(developer): filter incorrect fonts out of .keyboard_info (#12913)
|
||||
|
||||
## 17.0.332 stable 2024-11-06
|
||||
|
||||
* fix(developer): create Server config directory before options save (#12609)
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
18.0.170
|
||||
18.0.173
|
||||
|
|
@ -19,8 +19,8 @@ export class ElemElement {
|
|||
order: number; // -128 to +127; used only by reorder element values
|
||||
tertiary: number; // -128 to +127; used only by reorder element values
|
||||
flags: ElemElementFlags;
|
||||
isEqual(a: ElemElement) {
|
||||
return a.value === this.value &&
|
||||
isEqual(a: ElemElement): boolean {
|
||||
return a.value.isEqual(this.value) &&
|
||||
a.order === this.order &&
|
||||
a.tertiary === this.tertiary &&
|
||||
a.flags === this.flags;
|
||||
|
|
@ -104,8 +104,8 @@ export class ElementString extends Array<ElemElement> {
|
|||
typeFlag |= constants.elem_flags_type_str;
|
||||
}
|
||||
}
|
||||
elem.order = orders.length ? parseInt(orders[i], 10) : 0;
|
||||
elem.tertiary = tertiaries.length ? parseInt(tertiaries[i], 10) : 0;
|
||||
elem.order = orders.length ? this.parseIntOrZero(orders[i]) : 0;
|
||||
elem.tertiary = tertiaries.length ? this.parseIntOrZero(tertiaries[i]) : 0;
|
||||
elem.flags = ElemElementFlags.none |
|
||||
(ElemElementFlags.type & typeFlag) |
|
||||
(tertiary_bases?.[i] == '1' /* TODO-LDML: or 'true'? */ ? ElemElementFlags.tertiary_base : 0) |
|
||||
|
|
@ -125,5 +125,9 @@ export class ElementString extends Array<ElemElement> {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
private static parseIntOrZero(str: string): number {
|
||||
const num = parseInt(str, 10);
|
||||
return !Number.isNaN(num) ? num : 0;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
|
|
|||
|
|
@ -131,6 +131,10 @@ export class StrsItem {
|
|||
get isOneChar() {
|
||||
return this.char !== undefined;
|
||||
}
|
||||
|
||||
isEqual(a: StrsItem): boolean {
|
||||
return a.value === this.value && a.char === this.char;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
498
common/web/types/tests/kmx/kmx-plus/element-string.tests.ts
Normal file
498
common/web/types/tests/kmx/kmx-plus/element-string.tests.ts
Normal file
|
|
@ -0,0 +1,498 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*
|
||||
* Created by Dr Mark C. Sinclair on 2024-12-09
|
||||
*
|
||||
* Test code for element-string.ts
|
||||
*/
|
||||
|
||||
import 'mocha';
|
||||
import { assert } from 'chai';
|
||||
import { constants } from '@keymanapp/ldml-keyboard-constants';
|
||||
import { ElemElementFlags, ElemElement, ElementString } from '../../../src/kmx/kmx-plus/element-string.js';
|
||||
import { StrsItem, UsetItem, Strs, StrsOptions, DependencySections, CharStrsItem, Uset } from '../../../src/kmx/kmx-plus/kmx-plus.js';
|
||||
import { UnicodeSet, UnicodeSetParser } from '../../../src/ldml-keyboard/unicodeset-parser-api.js';
|
||||
import { ElementParser, ElementSegment, ElementType } from '../../../src/ldml-keyboard/pattern-parser.js';
|
||||
|
||||
const GOTHIC_A = new StrsItem("𐌰", 0x10330);
|
||||
const GOTHIC_B = new StrsItem("𐌱", 0x10331);
|
||||
const GOTHIC_C = new StrsItem("𐌲", 0x10332);
|
||||
const GOTHIC_D = new StrsItem("𐌳", 0x10333);
|
||||
const HI_GOTHIC_A = new StrsItem('\ud800', 0xd800);
|
||||
const LO_GOTHIC_A = new StrsItem('\udf30', 0xdf30);
|
||||
const GOTHIC_PATTERN = "[𐌰-𐍊]";
|
||||
const GOTHIC_STRSITEM = new StrsItem(GOTHIC_PATTERN);
|
||||
const GOTHIC_SET = new UnicodeSet(GOTHIC_PATTERN, [[0x10330,0x1034A]]);
|
||||
const GOTHIC_USETITEM = new UsetItem(GOTHIC_SET, GOTHIC_STRSITEM);
|
||||
const UGARITIC_PATTERN = "[𐎀-𐎟]";
|
||||
const UGARITIC_STRSITEM = new StrsItem(UGARITIC_PATTERN);
|
||||
const UGARITIC_SET = new UnicodeSet(UGARITIC_PATTERN, [[0x10380,0x1039F]]);
|
||||
const UGARITIC_USETITEM = new UsetItem(UGARITIC_SET, UGARITIC_STRSITEM);
|
||||
|
||||
class TestUnicodeSetParser implements UnicodeSetParser {
|
||||
parseUnicodeSet = (pattern: string, rangeCount: number) : UnicodeSet | null => GOTHIC_SET;
|
||||
sizeUnicodeSet = (pattern: string) : number => 1;
|
||||
};
|
||||
|
||||
const origElementParserSegment = ElementParser.segment;
|
||||
let sections: DependencySections = null;
|
||||
|
||||
describe('Test of ElementString file', () => {
|
||||
describe('Test of ElemElement', () => {
|
||||
describe('Test of isEqual()', () => {
|
||||
it('returns true when elems identical', () => {
|
||||
const one = initElemElement();
|
||||
const two = initElemElement();
|
||||
assert.isTrue(one.isEqual(two));
|
||||
});
|
||||
it('returns true when elems are clones', () => {
|
||||
const one = initElemElement(new StrsItem("𐌰", 0x10330));
|
||||
const two = initElemElement(new StrsItem("𐌰", 0x10330));
|
||||
assert.isTrue(one.isEqual(two));
|
||||
});
|
||||
it('returns false when value differs', () => {
|
||||
const one = initElemElement(GOTHIC_A);
|
||||
const two = initElemElement(GOTHIC_B);
|
||||
assert.isFalse(one.isEqual(two));
|
||||
});
|
||||
it('returns false when order differs', () => {
|
||||
const one = initElemElement(GOTHIC_A, GOTHIC_USETITEM, 0);
|
||||
const two = initElemElement(GOTHIC_A, GOTHIC_USETITEM, 1);
|
||||
assert.isFalse(one.isEqual(two));
|
||||
});
|
||||
it('returns false when tertiary differs', () => {
|
||||
const one = initElemElement(GOTHIC_A, GOTHIC_USETITEM, 0, 0);
|
||||
const two = initElemElement(GOTHIC_A, GOTHIC_USETITEM, 0, 1);
|
||||
assert.isFalse(one.isEqual(two));
|
||||
});
|
||||
it('returns false when flags differs', () => {
|
||||
const one = initElemElement(GOTHIC_A, GOTHIC_USETITEM, 0, 0, ElemElementFlags.none);
|
||||
const two = initElemElement(GOTHIC_A, GOTHIC_USETITEM, 0, 0, ElemElementFlags.type);
|
||||
assert.isFalse(one.isEqual(two));
|
||||
});
|
||||
it('returns true even though uset differs', () => {
|
||||
const one = initElemElement(GOTHIC_A, GOTHIC_USETITEM);
|
||||
const two = initElemElement(GOTHIC_A, UGARITIC_USETITEM);
|
||||
assert.isTrue(one.isEqual(two));
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('Test of ElementString class', () => {
|
||||
beforeEach(() => {
|
||||
sections = {
|
||||
strs: new Strs(),
|
||||
uset: new Uset(),
|
||||
usetparser: new TestUnicodeSetParser(),
|
||||
};
|
||||
ElementParser.segment = stubElementParserSegment_CodePoint;
|
||||
});
|
||||
afterEach(() => {
|
||||
ElementParser.segment = origElementParserSegment;
|
||||
});
|
||||
describe('Test of fromStrings()', () => {
|
||||
it('returns an empty ElementString if source is null', () => {
|
||||
const es = ElementString.fromStrings({}, null);
|
||||
assert.deepEqual(es, new ElementString());
|
||||
});
|
||||
it('can create an ElementString from a string array', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(sections, ["𐌰", "𐌱", "𐌲"]);
|
||||
const expected = [
|
||||
initElemElement(GOTHIC_A),
|
||||
initElemElement(GOTHIC_B),
|
||||
initElemElement(GOTHIC_C),
|
||||
];
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
it('can create an ElementString from a string', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(sections, "𐌰𐌱𐌲");
|
||||
const expected = [
|
||||
initElemElement(GOTHIC_A),
|
||||
initElemElement(GOTHIC_B),
|
||||
initElemElement(GOTHIC_C),
|
||||
];
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
it('can apply order string', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
"𐌰𐌱𐌲",
|
||||
"1 2 3",
|
||||
);
|
||||
const expected = [
|
||||
initElemElement(GOTHIC_A, undefined, 1),
|
||||
initElemElement(GOTHIC_B, undefined, 2),
|
||||
initElemElement(GOTHIC_C, undefined, 3),
|
||||
];
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
it('can apply single order to all', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
"𐌰𐌱𐌲",
|
||||
"1",
|
||||
);
|
||||
const expected = [
|
||||
initElemElement(GOTHIC_A, undefined, 1),
|
||||
initElemElement(GOTHIC_B, undefined, 1),
|
||||
initElemElement(GOTHIC_C, undefined, 1),
|
||||
];
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
it('can handle order string that is too short', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
"𐌰𐌱𐌲",
|
||||
"1 2",
|
||||
);
|
||||
const expected = [
|
||||
initElemElement(GOTHIC_A, undefined, 1),
|
||||
initElemElement(GOTHIC_B, undefined, 2),
|
||||
initElemElement(GOTHIC_C, undefined, 0),
|
||||
];
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
it('can handle non-number in order string', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
"𐌰𐌱𐌲",
|
||||
"1 A 3",
|
||||
);
|
||||
const expected = [
|
||||
initElemElement(GOTHIC_A, undefined, 1),
|
||||
initElemElement(GOTHIC_B, undefined, 0),
|
||||
initElemElement(GOTHIC_C, undefined, 3),
|
||||
];
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
it('can apply tertiary string', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
"𐌰𐌱𐌲",
|
||||
null,
|
||||
"1 2 3",
|
||||
);
|
||||
const expected = [
|
||||
initElemElement(GOTHIC_A, undefined, 0, 1),
|
||||
initElemElement(GOTHIC_B, undefined, 0, 2),
|
||||
initElemElement(GOTHIC_C, undefined, 0, 3),
|
||||
];
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
it('can apply single tertiary to all', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
"𐌰𐌱𐌲",
|
||||
null,
|
||||
"1",
|
||||
);
|
||||
const expected = [
|
||||
initElemElement(GOTHIC_A, undefined, 0, 1),
|
||||
initElemElement(GOTHIC_B, undefined, 0, 1),
|
||||
initElemElement(GOTHIC_C, undefined, 0, 1),
|
||||
];
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
it('can handle tertiary string that is too short', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
"𐌰𐌱𐌲",
|
||||
null,
|
||||
"1 2",
|
||||
);
|
||||
const expected = [
|
||||
initElemElement(GOTHIC_A, undefined, 0, 1),
|
||||
initElemElement(GOTHIC_B, undefined, 0, 2),
|
||||
initElemElement(GOTHIC_C, undefined, 0, 0),
|
||||
];
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
it('can handle non-number in tertiary string', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
"𐌰𐌱𐌲",
|
||||
null,
|
||||
"1 A 3",
|
||||
);
|
||||
const expected = [
|
||||
initElemElement(GOTHIC_A, undefined, 0, 1),
|
||||
initElemElement(GOTHIC_B, undefined, 0, 0),
|
||||
initElemElement(GOTHIC_C, undefined, 0, 3),
|
||||
];
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
it('can apply tertiary_base string', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
"𐌰𐌱𐌲",
|
||||
null,
|
||||
null,
|
||||
"1 0 1",
|
||||
);
|
||||
const expected = [
|
||||
initElemElement(GOTHIC_A, undefined, 0, 0, ElemElementFlags.tertiary_base),
|
||||
initElemElement(GOTHIC_B, undefined, 0, 0, ElemElementFlags.none),
|
||||
initElemElement(GOTHIC_C, undefined, 0, 0, ElemElementFlags.tertiary_base),
|
||||
];
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
it('can apply single tertiary_base to all', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
"𐌰𐌱𐌲",
|
||||
null,
|
||||
null,
|
||||
"1",
|
||||
);
|
||||
const expected = [
|
||||
initElemElement(GOTHIC_A, undefined, 0, 0, ElemElementFlags.tertiary_base),
|
||||
initElemElement(GOTHIC_B, undefined, 0, 0, ElemElementFlags.tertiary_base),
|
||||
initElemElement(GOTHIC_C, undefined, 0, 0, ElemElementFlags.tertiary_base),
|
||||
];
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
it('can handle tertiary_base string that is too short', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
"𐌰𐌱𐌲",
|
||||
null,
|
||||
null,
|
||||
"1 0",
|
||||
);
|
||||
const expected = [
|
||||
initElemElement(GOTHIC_A, undefined, 0, 0, ElemElementFlags.tertiary_base),
|
||||
initElemElement(GOTHIC_B, undefined, 0, 0, ElemElementFlags.none),
|
||||
initElemElement(GOTHIC_C, undefined, 0, 0, ElemElementFlags.none),
|
||||
];
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
it('can apply prebase string', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
"𐌰𐌱𐌲",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
"1 0 1",
|
||||
);
|
||||
const expected = [
|
||||
initElemElement(GOTHIC_A, undefined, 0, 0, ElemElementFlags.prebase),
|
||||
initElemElement(GOTHIC_B, undefined, 0, 0, ElemElementFlags.none),
|
||||
initElemElement(GOTHIC_C, undefined, 0, 0, ElemElementFlags.prebase),
|
||||
];
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
it('can apply single prebase to all', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
"𐌰𐌱𐌲",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
"1",
|
||||
);
|
||||
const expected = [
|
||||
initElemElement(GOTHIC_A, undefined, 0, 0, ElemElementFlags.prebase),
|
||||
initElemElement(GOTHIC_B, undefined, 0, 0, ElemElementFlags.prebase),
|
||||
initElemElement(GOTHIC_C, undefined, 0, 0, ElemElementFlags.prebase),
|
||||
];
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
it('can handle prebase string that is too short', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
"𐌰𐌱𐌲",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
"1 0",
|
||||
);
|
||||
const expected = [
|
||||
initElemElement(GOTHIC_A, undefined, 0, 0, ElemElementFlags.prebase),
|
||||
initElemElement(GOTHIC_B, undefined, 0, 0, ElemElementFlags.none),
|
||||
initElemElement(GOTHIC_C, undefined, 0, 0, ElemElementFlags.none),
|
||||
];
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
it('can create an ElementString from a uset string', () => {
|
||||
ElementParser.segment = stubElementParserSegment_Uset;
|
||||
sections.strs.allocString = stubStrsAllocString_Str;
|
||||
sections.uset.allocUset = stubUsetAllocUset;
|
||||
const actual = ElementString.fromStrings(sections, "[𐌰-𐍊]");
|
||||
const expected = [
|
||||
initElemElement(
|
||||
new StrsItem(''),
|
||||
GOTHIC_USETITEM,
|
||||
0,
|
||||
0,
|
||||
constants.elem_flags_type_uset,
|
||||
),
|
||||
];
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
it('returns null for an invalid unicode set size', () => {
|
||||
ElementParser.segment = stubElementParserSegment_Uset;
|
||||
sections.usetparser.sizeUnicodeSet = (pattern: string) : number => -1;
|
||||
assert.isNull(ElementString.fromStrings(sections, "[𐌰-𐍊]"));
|
||||
});
|
||||
it('returns null if it cannot parse the unicode set', () => {
|
||||
ElementParser.segment = stubElementParserSegment_Uset;
|
||||
sections.usetparser.parseUnicodeSet = (pattern: string, rangeCount: number) : UnicodeSet | null => null;
|
||||
assert.isNull(ElementString.fromStrings(sections, "[𐌰-𐍊]"));
|
||||
});
|
||||
it('can handle quad strings', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
ElementParser.segment = stubElementParserSegment_Escaped;
|
||||
const actual = ElementString.fromStrings(sections, "\\ud800\\udf30");
|
||||
const expected = [
|
||||
initElemElement(HI_GOTHIC_A),
|
||||
initElemElement(LO_GOTHIC_A),
|
||||
];
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
it('can handle ElemElement of string type', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Str;
|
||||
const actual = ElementString.fromStrings(sections, ["𐌰𐌱𐌲",]);
|
||||
const expected = [
|
||||
initElemElement(
|
||||
new StrsItem("𐌰𐌱𐌲"),
|
||||
undefined,
|
||||
0,
|
||||
0,
|
||||
constants.elem_flags_type_str,
|
||||
),
|
||||
];
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
describe('Test of isEqual()', () => {
|
||||
it('returns true when ElementStrings are identical', () => {
|
||||
const es = initElementString([
|
||||
initElemElement(GOTHIC_A),
|
||||
initElemElement(GOTHIC_B),
|
||||
initElemElement(GOTHIC_C),
|
||||
]);
|
||||
assert.isTrue(es.isEqual(es));
|
||||
});
|
||||
it('returns true when ElementStrings are clones', () => {
|
||||
const one = initElementString([
|
||||
initElemElement(GOTHIC_A),
|
||||
initElemElement(GOTHIC_B),
|
||||
initElemElement(GOTHIC_C),
|
||||
]);
|
||||
const two = initElementString([
|
||||
initElemElement(GOTHIC_A),
|
||||
initElemElement(GOTHIC_B),
|
||||
initElemElement(GOTHIC_C),
|
||||
]);
|
||||
assert.isTrue(one.isEqual(two));
|
||||
});
|
||||
it('returns false when ElementStrings are different lengths', () => {
|
||||
const one = initElementString([
|
||||
initElemElement(GOTHIC_A),
|
||||
initElemElement(GOTHIC_B),
|
||||
initElemElement(GOTHIC_C),
|
||||
]);
|
||||
const two = initElementString([
|
||||
initElemElement(GOTHIC_A),
|
||||
initElemElement(GOTHIC_B),
|
||||
]);
|
||||
assert.isFalse(one.isEqual(two));
|
||||
});
|
||||
it('returns false when ElementStrings have different ElemElements', () => {
|
||||
const one = initElementString([
|
||||
initElemElement(GOTHIC_A),
|
||||
initElemElement(GOTHIC_B),
|
||||
initElemElement(GOTHIC_C),
|
||||
]);
|
||||
const two = initElementString([
|
||||
initElemElement(GOTHIC_A),
|
||||
initElemElement(GOTHIC_B),
|
||||
initElemElement(GOTHIC_D),
|
||||
]);
|
||||
assert.isFalse(one.isEqual(two));
|
||||
});
|
||||
});
|
||||
describe('Test of parseIntOrZero()', () => {
|
||||
it('returns a number for a valid string', () => {
|
||||
const num = ElementString['parseIntOrZero']('1');
|
||||
assert.equal(num, 1);
|
||||
});
|
||||
it('returns zero for an invalid string', () => {
|
||||
const num = ElementString['parseIntOrZero']('A');
|
||||
assert.equal(num, 0);
|
||||
});
|
||||
it('returns zero for undefined', () => {
|
||||
const num = ElementString['parseIntOrZero'](undefined);
|
||||
assert.equal(num, 0);
|
||||
});
|
||||
it('returns zero for a null string', () => {
|
||||
const num = ElementString['parseIntOrZero'](null);
|
||||
assert.equal(num, 0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function initElemElement(
|
||||
value: StrsItem = GOTHIC_A,
|
||||
uset: UsetItem = undefined,
|
||||
order: number = 0,
|
||||
tertiary: number = 0,
|
||||
flags: ElemElementFlags = ElemElementFlags.none,
|
||||
): ElemElement {
|
||||
const ee = new ElemElement();
|
||||
ee.value = value;
|
||||
ee.uset = uset;
|
||||
ee.order = order;
|
||||
ee.tertiary = tertiary;
|
||||
ee.flags = flags;
|
||||
return ee;
|
||||
};
|
||||
|
||||
function initElementString(elemElements: ElemElement[]): ElementString {
|
||||
const es: ElementString = new ElementString();
|
||||
elemElements.forEach((ee) => {es.push(ee)});
|
||||
return es;
|
||||
};
|
||||
|
||||
function stubStrsAllocString_Char(s?: string, opts?: StrsOptions, sections?: DependencySections): StrsItem {
|
||||
return new CharStrsItem(s);
|
||||
};
|
||||
|
||||
function stubStrsAllocString_Str(s?: string, opts?: StrsOptions, sections?: DependencySections): StrsItem {
|
||||
return new StrsItem(s);
|
||||
};
|
||||
|
||||
function stubElementParserSegment_CodePoint(str: string): ElementSegment[] {
|
||||
return [...str].map(s => new ElementSegment(s, ElementType.codepoint));
|
||||
};
|
||||
|
||||
function stubElementParserSegment_Uset(str: string): ElementSegment[] {
|
||||
return [new ElementSegment(str, ElementType.uset)];
|
||||
};
|
||||
|
||||
function stubElementParserSegment_Escaped(str: string): ElementSegment[] {
|
||||
const strs = str.match(/\\u[0-9a-fA-F]{4}/g);
|
||||
return strs.map((s) => new ElementSegment(s, ElementType.escaped));
|
||||
};
|
||||
|
||||
function stubUsetAllocUset(set: UnicodeSet, sections: DependencySections) : UsetItem {
|
||||
return new UsetItem(set, new StrsItem(set.pattern));
|
||||
};
|
||||
|
||||
|
|
@ -1,3 +1,9 @@
|
|||
keyman (17.0.333-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Eberhard Beilharz <eb1@sil.org> Thu, 16 Jan 2025 16:29:44 +0100
|
||||
|
||||
keyman (17.0.332-1) unstable; urgency=medium
|
||||
|
||||
* set environment variable for rendering of downloads dialog (#12617)
|
||||
|
|
|
|||
|
|
@ -4,24 +4,24 @@ Upstream-Contact: Keyman team <support@keyman.com>
|
|||
Source: https://github.com/keymanapp/keyman
|
||||
|
||||
Files: *
|
||||
Copyright: 2018-2024 SIL Global
|
||||
Copyright: 2018-2025 SIL Global
|
||||
License: MIT
|
||||
|
||||
Files: linux/ibus-keyman/*
|
||||
Copyright: 2004-2024 SIL Global
|
||||
Copyright: 2004-2025 SIL Global
|
||||
License: GPL-2+
|
||||
|
||||
Files: linux/ibus-keyman/src/keymanutil.c
|
||||
linux/ibus-keyman/src/keymanutil.h
|
||||
linux/ibus-keyman/src/kmpdetails.c
|
||||
linux/ibus-keyman/src/kmpdetails.h
|
||||
Copyright: 2009-2024 SIL Global
|
||||
Copyright: 2009-2025 SIL Global
|
||||
License: GPL-2+ or MIT
|
||||
|
||||
Files: linux/ibus-keyman/src/keyman-service.c
|
||||
linux/ibus-keyman/src/keyman-service.h
|
||||
linux/keyman-config/buildtools/help2md
|
||||
Copyright: 2018-2024 SIL Global
|
||||
Copyright: 2018-2025 SIL Global
|
||||
License: GPL-3+
|
||||
|
||||
Files: linux/ibus-keyman/tests/ibusimcontext.c
|
||||
|
|
@ -31,7 +31,7 @@ Copyright: 2008-2010, Peng Huang <shawn.p.huang@gmail.com>
|
|||
2008-2013, Peng Huang <shawn.p.huang@gmail.com>
|
||||
2008-2021, Red Hat, Inc.
|
||||
2015-2021, Takao Fujiwara <takao.fujiwara1@gmail.com>
|
||||
2021-2024, SIL Global
|
||||
2021-2025, SIL Global
|
||||
License: LGPL-2.1+
|
||||
|
||||
Files: linux/keyman-config/buildtools/help2man
|
||||
|
|
@ -41,7 +41,7 @@ License: GPL-3+
|
|||
Files: debian/com.keyman.config.appdata.xml
|
||||
debian/com.keyman.ibus_keyman.metainfo.xml
|
||||
Copyright: 2019 Daniel Glassey <wdg@debian.org>
|
||||
2022-2024 SIL Global
|
||||
2022-2025 SIL Global
|
||||
License: MIT
|
||||
|
||||
License: MIT
|
||||
|
|
|
|||
|
|
@ -161,15 +161,21 @@ describe("PredictionContext", () => {
|
|||
assert.equal(updateFake.callCount, 3);
|
||||
suggestions = updateFake.thirdCall.args[0];
|
||||
|
||||
// Note: this unit test was originally written with auto-correct on!
|
||||
// #11941 was written 2024-07-25 (added unit test for auto-correction method)
|
||||
// #12169 was written 2024-08-14, which is what added THIS unit test.
|
||||
|
||||
// This does re-use the apply-revert oriented mocking.
|
||||
// Should skip the (second) "apple", "apply", "apps" round, as it became outdated
|
||||
// by its following request before its response could be received.
|
||||
assert.deepEqual(suggestions.map((obj) => obj.displayAs), ['“apple”', 'applied']);
|
||||
assert.equal(suggestions.find((obj) => obj.tag == 'keep').displayAs, '“apple”');
|
||||
assert.deepEqual(suggestions.map((obj) => obj.displayAs), ['applied']); // '“apple”' included with auto-correct enabled.
|
||||
// Is not displayed; we only display it if auto-correct is on, as 'applied' would be automatic then.
|
||||
assert.equal(predictiveContext.keepSuggestion.displayAs, '“apple”');
|
||||
// assert.equal(suggestions.find((obj) => obj.tag == 'keep').displayAs, '“apple”'); // with auto-correct enabled.
|
||||
assert.equal(suggestions.find((obj) => obj.transform.deleteLeft != 0).displayAs, 'applied');
|
||||
// Our reused mocking doesn't directly provide the 'keep' suggestion; we
|
||||
// need to remove it before testing for set equality.
|
||||
assert.deepEqual(suggestions.splice(1), expected);
|
||||
assert.deepEqual(suggestions /*.splice(1)*/, expected);
|
||||
});
|
||||
|
||||
it('sendUpdateState retrieves the most recent suggestion set', async function() {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue