spiegel-keyman/developer/src/kmc-kmn/test/compiler.tests.ts
Marc Durdin 2f60544835
Some checks failed
Keyman Build Summary / Summarize build status checks (push) Has been cancelled
docs(developer): tweak comments
Co-authored-by: Eberhard Beilharz <ermshiperete@users.noreply.github.com>
Co-authored-by: Sabine Schmitt <SabineSIL@users.noreply.github.com>
2026-08-28 17:31:06 +02:00

163 lines
5.9 KiB
TypeScript

/*
* Keyman is copyright (C) SIL Global. MIT License.
*/
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import fs from 'node:fs';
import 'mocha';
import { assert } from 'chai';
import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers';
import { KmxFileReader } from '@keymanapp/common-types';
import { compileTestKeyboard } from './helpers/index.js';
import { KmnCompiler } from '../src/main.js';
const __dirname = dirname(fileURLToPath(import.meta.url)).replace(/\\/g, '/');
const keyboardsDir = __dirname + '/../../../../../common/test/keyboards/';
const baselineDir = keyboardsDir + 'baseline/';
describe('Compiler class', function() {
const callbacks = new TestCompilerCallbacks(this);
this.beforeEach(function() {
callbacks.clear();
});
this.afterEach(function() {
if(this.currentTest?.isFailed()) {
callbacks.printMessages();
}
});
it('should throw on failure', async function() {
const compiler = new KmnCompiler();
const callbacks : any = null; // ERROR
try {
await compiler.init(callbacks, null)
assert.fail('Expected exception');
} catch(e) {
assert.ok(e);
}
assert.throws(() => compiler.verifyInitialized());
});
it('should start', async function() {
const compiler = new KmnCompiler();
assert(await compiler.init(callbacks, null));
assert(compiler.verifyInitialized());
});
it('should compile a basic keyboard', async function() {
const compiler = new KmnCompiler();
assert(await compiler.init(callbacks, {saveDebug: true, shouldAddCompilerVersion: false}));
assert(compiler.verifyInitialized());
const fixtureName = baselineDir + 'k_0000___null_keyboard.kmx';
const infile = baselineDir + 'k_0000___null_keyboard.kmn';
const outFile = __dirname + '/k_0000___null_keyboard.kmx';
if(fs.existsSync(outFile)) {
fs.rmSync(outFile);
}
const result = await compiler.run(infile, outFile);
assert.isNotNull(result);
assert.isTrue(await compiler.write(result.artifacts));
assert(fs.existsSync(outFile));
const outfileData = fs.readFileSync(outFile);
const fixtureData = fs.readFileSync(fixtureName);
assert.equal(outfileData.byteLength, fixtureData.byteLength);
assert.deepEqual(outfileData, fixtureData);
});
// Note, above test case is essentially a subset of this one, but will leave both because
// the basic keyboard test is slightly simpler to read
it('should build all baseline fixtures', async function() {
this.timeout(10000); // there are quite a few fixtures, sometimes CI agents are slow
const compiler = new KmnCompiler();
assert(await compiler.init(callbacks, {saveDebug: true, shouldAddCompilerVersion: false}));
assert(compiler.verifyInitialized());
const files = fs.readdirSync(baselineDir);
for(const file of files) {
if(file.match(/\.kmx$/)) {
const fixtureName = baselineDir + file;
const infile = baselineDir + file.replace(/x$/, 'n');
const outFile = __dirname + '/' + file;
if(fs.existsSync(outFile)) {
fs.rmSync(outFile);
}
const result = await compiler.run(infile, outFile);
assert.isNotNull(result);
assert.isTrue(await compiler.write(result.artifacts));
assert(fs.existsSync(outFile));
const outfileData = fs.readFileSync(outFile);
const fixtureData = fs.readFileSync(fixtureName);
assert.equal(outfileData.byteLength, fixtureData.byteLength, `file ${file} has the wrong byte length`);
assert.deepEqual(outfileData, fixtureData, `file ${file} does not match fixture`);
}
}
});
it('should compile a keyboard with visual keyboard', async function() {
const compiler = new KmnCompiler();
assert.isTrue(await compiler.init(callbacks, {
saveDebug: true,
shouldAddCompilerVersion: false,
}));
assert.isTrue(compiler.verifyInitialized());
const fixtureDir = keyboardsDir + 'caps_lock_layer_3620/'
const infile = fixtureDir + 'source/caps_lock_layer_3620.kmn';
const kmxFixture = fixtureDir + '/binary/caps_lock_layer_3620.kmx';
const kvkFixture = fixtureDir + '/binary/caps_lock_layer_3620.kvk';
const resultingKmxfile = __dirname + '/caps_lock_layer_3620.kmx';
const resultingKvkfile = __dirname + '/caps_lock_layer_3620.kvk';
if(fs.existsSync(resultingKmxfile)) {
fs.rmSync(resultingKmxfile);
}
if(fs.existsSync(resultingKvkfile)) {
fs.rmSync(resultingKvkfile);
}
const result = await compiler.run(infile, resultingKmxfile);
assert.isNotNull(result);
assert.isTrue(await compiler.write(result.artifacts));
assert.isTrue(fs.existsSync(resultingKmxfile));
assert.isTrue(fs.existsSync(resultingKvkfile));
const kmxData = fs.readFileSync(resultingKmxfile);
const kmxFixtureData = fs.readFileSync(kmxFixture);
assert.equal(kmxData.byteLength, kmxFixtureData.byteLength);
assert.deepEqual(kmxData, kmxFixtureData);
const kvkData = fs.readFileSync(resultingKvkfile);
const kvkFixtureData = fs.readFileSync(kvkFixture);
assert.equal(kvkData.byteLength, kvkFixtureData.byteLength);
assert.deepEqual(kvkData, kvkFixtureData);
});
it('should trim all whitespace for `&targets` store', async function() {
const result = await compileTestKeyboard(callbacks, ['keyboards', 'targets-with-whitespace.kmn']);
assert.isNotNull(result);
// Verify implictly that `&targets` store was interpreted correctly as 'any'
// because the compiler generated both JS and KMX targets (#13721)
assert.isNotNull(result.artifacts.js);
assert.isNotNull(result.artifacts.kmx);
// Then verify directly that the `&targets` store was trimmed by looking at
// the final value in the kmx data
const reader = new KmxFileReader();
const keyboard = reader.read(result.artifacts.kmx.data);
assert.equal(keyboard.targets, 'any');
});
});