mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2026-10-25 00:02:16 +00:00
217 lines
12 KiB
TypeScript
217 lines
12 KiB
TypeScript
import assert from "assert";
|
|
import { describe, it } from "mocha";
|
|
import {
|
|
TOOL_META, getToolMeta, getToolMetaForFilename, getPreloadFSName, getSkeletonName,
|
|
getIncludePatterns, getLinkPatterns, matchDependencyPatterns,
|
|
getSystemIncludePatterns, SYSTEM_INCLUDE_PATTERNS, getSharedFileSystemName, getToolHelpURL,
|
|
getPlatformToolHelpURL
|
|
} from "../../src/common/toolmeta";
|
|
// Node-friendly worker entry point (re-exports TOOLS without Worker wiring)
|
|
import { TOOLS } from "../../src/worker/workerlib";
|
|
|
|
describe('Tool metadata registry', function () {
|
|
it('every registry key matches its tool id', function () {
|
|
for (let id in TOOL_META) {
|
|
assert.strictEqual(TOOL_META[id].id, id, `TOOL_META['${id}'].id mismatch`);
|
|
}
|
|
});
|
|
|
|
it('every worker build tool is registered (and vice versa)', function () {
|
|
// worker TOOLS -> must exist in registry
|
|
for (let id of Object.keys(TOOLS)) {
|
|
assert.ok(TOOL_META[id], `worker TOOLS['${id}'] missing from TOOL_META`);
|
|
}
|
|
// registry -> must have a worker build fn, unless explicitly deferred
|
|
// or built on a remote server (llvm-mos)
|
|
for (let id in TOOL_META) {
|
|
let meta = TOOL_META[id];
|
|
if (meta.noWorkerBuild || meta.remote) continue;
|
|
assert.ok(TOOLS[id], `TOOL_META['${id}'] missing from worker TOOLS`);
|
|
}
|
|
});
|
|
|
|
it('getToolMeta strips the remote: transport prefix', function () {
|
|
assert.strictEqual(getToolMeta('remote:llvm-mos'), TOOL_META['llvm-mos']);
|
|
assert.strictEqual(getToolMeta('llvm-mos'), TOOL_META['llvm-mos']);
|
|
assert.strictEqual(getToolMeta('bogus'), undefined);
|
|
});
|
|
|
|
it('getToolMetaForFilename finds tools by extension', function () {
|
|
assert.ok(getToolMetaForFilename('foo.c').some(m => m.id === 'cc65'));
|
|
assert.ok(getToolMetaForFilename('foo.s').some(m => m.id === 'ca65'));
|
|
assert.ok(getToolMetaForFilename('foo.wiz').some(m => m.id === 'wiz'));
|
|
assert.ok(getToolMetaForFilename('foo.ecs').some(m => m.id === 'ecs'));
|
|
assert.ok(getToolMetaForFilename('foo.dg').some(m => m.id === 'dialog'));
|
|
// unknown extension -> no matches
|
|
assert.deepStrictEqual(getToolMetaForFilename('foo.xyz'), []);
|
|
});
|
|
|
|
it('getPreloadFSName resolves per-platform filesystems', function () {
|
|
assert.strictEqual(getPreloadFSName('cc65', 'nes'), undefined); // WASI zip, not preloadFS
|
|
assert.strictEqual(getSharedFileSystemName('cc65', 'nes'), 'wasi:cc65-fs-nes.zip');
|
|
assert.strictEqual(getSharedFileSystemName('cc65', 'c64'), 'wasi:cc65-fs-c64.zip');
|
|
assert.strictEqual(getSharedFileSystemName('cc65', 'nonexistent'), undefined);
|
|
assert.strictEqual(getPreloadFSName('sdcc'), 'sdcc'); // default config
|
|
assert.strictEqual(getPreloadFSName('dasm'), undefined);
|
|
});
|
|
|
|
it('getSharedFileSystemName resolves suffixed platform ids to their root base', function () {
|
|
// atari8 runs as 'atari8-800' / 'atari8-5200' / *.xlmame variants
|
|
assert.strictEqual(getSharedFileSystemName('cc65', 'atari8'), 'wasi:cc65-fs-atari8.zip');
|
|
assert.strictEqual(getSharedFileSystemName('cc65', 'atari8-800'), 'wasi:cc65-fs-atari8.zip');
|
|
assert.strictEqual(getSharedFileSystemName('cc65', 'atari8-800.xlmame'), 'wasi:cc65-fs-atari8.zip');
|
|
assert.strictEqual(getSharedFileSystemName('cc65', 'atari8-5200'), 'wasi:cc65-fs-atari8.zip');
|
|
assert.strictEqual(getSharedFileSystemName('fastbasic', 'atari8-800'), 'wasi:cc65-fs-atari8.zip');
|
|
assert.strictEqual(getSharedFileSystemName('ecs', 'nes'), 'wasi:cc65-fs-nes.zip');
|
|
});
|
|
|
|
it('getSkeletonName defaults to the tool id', function () {
|
|
assert.strictEqual(getSkeletonName('dasm'), 'dasm');
|
|
assert.strictEqual(getSkeletonName('remote:llvm-mos'), 'llvm-mos');
|
|
});
|
|
|
|
it('covers the previously-scattered editor styles and help URLs', function () {
|
|
// spot-check ids that used to live in TOOL_TO_SOURCE_STYLE / TOOL_TO_HELPURL
|
|
for (let id of ['dasm', 'acme', 'cc65', 'ca65', 'sdcc', 'cmoc', 'zmac',
|
|
'nesasm', 'bataribasic', 'fastbasic', 'wiz', 'silice', 'ecs', 'dialog']) {
|
|
assert.ok(TOOL_META[id], `expected tool '${id}' in registry`);
|
|
}
|
|
assert.strictEqual(TOOL_META['cc65'].editorStyle, 'text/x-csrc');
|
|
assert.strictEqual(TOOL_META['ca65'].editorStyle, '6502');
|
|
assert.ok(TOOL_META['dasm'].helpURL);
|
|
});
|
|
|
|
it('include patterns exist for tools that do dependency parsing', function () {
|
|
assert.ok(TOOL_META['cc65'].includePatterns.length > 0);
|
|
assert.ok(TOOL_META['verilator'].includePatterns.length > 0);
|
|
assert.ok(TOOL_META['acme'].includePatterns.length > 0);
|
|
assert.ok(TOOL_META['dialog'].includePatterns.length > 0);
|
|
assert.ok(TOOL_META['wiz'].includePatterns.length > 0);
|
|
});
|
|
|
|
it('matches include directives for the tool that builds the file', function () {
|
|
let deps = (text: string, tool?: string, platform?: string) =>
|
|
matchDependencyPatterns(text, getIncludePatterns(tool, platform));
|
|
assert.deepStrictEqual(deps('#include "foo.h"\n', 'cc65'), ['foo.h']);
|
|
assert.deepStrictEqual(deps('\t.include "foo.inc"\n', 'ca65'), ['foo.inc']);
|
|
assert.deepStrictEqual(deps('//#resource "foo.bin"\n', 'dasm'), ['foo.bin']);
|
|
// dasm also accepts unquoted include/incbin names
|
|
assert.deepStrictEqual(deps('\tINCLUDE VCS.h\n\tINCLUDE macro.h\n', 'dasm'),
|
|
['VCS.h', 'macro.h']);
|
|
assert.deepStrictEqual(deps(' .include foo.inc\n incbin table.bin\n', 'dasm'),
|
|
['foo.inc', 'table.bin']);
|
|
// quoted names stay matched by the shared pattern only (no duplicates)
|
|
assert.deepStrictEqual(deps('\tinclude "vcs.h"\n', 'dasm'), ['vcs.h']);
|
|
assert.deepStrictEqual(deps('!src "foo.acme"\n', 'acme'), ['foo.acme']);
|
|
assert.deepStrictEqual(deps('%% #include "foo.dg"\n', 'dialog'), ['foo.dg']);
|
|
assert.deepStrictEqual(deps(' USE foo.xasm\n', 'xasm6809'), ['foo.xasm']);
|
|
// ecs uses both its own import and the shared .include directive
|
|
assert.deepStrictEqual(deps('.include "vcs.h"\nimport "lib.ecs"\n', 'ecs'),
|
|
['vcs.h', 'lib.ecs']);
|
|
// wiz: import gets an implicit .wiz extension, embed does not
|
|
assert.deepStrictEqual(deps('import "nes";\nembed "map.bin";\n', 'wiz'),
|
|
['nes.wiz', 'map.bin']);
|
|
// verilog: .arch names a .json file
|
|
assert.deepStrictEqual(deps('`include "hvsync.v"\n.arch mynes\n', 'verilator'),
|
|
['hvsync.v', 'mynes.json']);
|
|
// unknown tool falls back to the platform
|
|
assert.deepStrictEqual(deps('`include "hvsync.v"\n', null, 'verilog'), ['hvsync.v']);
|
|
assert.deepStrictEqual(deps('#include "foo.h"\n', null, 'c64'), ['foo.h']);
|
|
// system includes (<foo.h>) are NOT build dependencies
|
|
assert.deepStrictEqual(deps('#include <stdio.h>\n', 'cc65'), []);
|
|
assert.deepStrictEqual(deps('#include <stdio.h>\n', 'sdcc'), []);
|
|
});
|
|
|
|
it('matches system include patterns for UI links only', function () {
|
|
// tools with a bundled filesystem get system-include link patterns
|
|
assert.deepStrictEqual(getSystemIncludePatterns('cc65'), SYSTEM_INCLUDE_PATTERNS);
|
|
assert.deepStrictEqual(getSystemIncludePatterns('sdcc'), SYSTEM_INCLUDE_PATTERNS);
|
|
// tools without one do not (dasm has no includeDirs)
|
|
assert.deepStrictEqual(getSystemIncludePatterns('dasm'), []);
|
|
assert.deepStrictEqual(getSystemIncludePatterns('bogus'), []);
|
|
// ...and they extract the filename from <...>
|
|
let deps = (text: string, tool?: string) =>
|
|
matchDependencyPatterns(text, getSystemIncludePatterns(tool));
|
|
assert.deepStrictEqual(deps('#include <stdio.h>\n', 'cc65'), ['stdio.h']);
|
|
assert.deepStrictEqual(deps(' # include <atari7800.h>\n', 'cc65'), ['atari7800.h']);
|
|
// quoted includes are not matched by the system patterns
|
|
assert.deepStrictEqual(deps('#include "foo.h"\n', 'cc65'), []);
|
|
});
|
|
|
|
it('resolves shared filesystem names for all tools with includeDirs', function () {
|
|
assert.equal(getSharedFileSystemName('cc65', 'nes'), 'wasi:cc65-fs-nes.zip');
|
|
// preloadFS-backed tools
|
|
assert.equal(getSharedFileSystemName('sdcc', 'coleco'), 'sdcc');
|
|
assert.equal(getSharedFileSystemName('bataribasic', 'vcs'), 'wasi:bb-fs.zip');
|
|
assert.equal(getSharedFileSystemName('wiz'), 'wiz');
|
|
// WASI zip-backed tools (cc2600/cc7800/armtcc/oscar64/dialog)
|
|
assert.equal(getSharedFileSystemName('cc2600'), 'wasi:cc2600-fs.zip');
|
|
assert.equal(getSharedFileSystemName('cc7800'), 'wasi:cc7800-fs.zip');
|
|
assert.equal(getSharedFileSystemName('armtcc'), 'wasi:arm32-fs.zip');
|
|
assert.equal(getSharedFileSystemName('oscar64'), 'wasi:oscar64-fs.zip');
|
|
assert.equal(getSharedFileSystemName('dialog'), 'wasi:dialog-fs.zip');
|
|
// tools without a bundled filesystem
|
|
assert.equal(getSharedFileSystemName('cmoc'), undefined);
|
|
assert.equal(getSharedFileSystemName('smlrc'), undefined);
|
|
assert.equal(getSharedFileSystemName('dasm'), undefined);
|
|
});
|
|
|
|
it('matches link directives only for tools that link', function () {
|
|
let deps = (text: string, tool?: string, platform?: string) =>
|
|
matchDependencyPatterns(text, getLinkPatterns(tool, platform));
|
|
assert.deepStrictEqual(deps('//#link "foo.c"\n', 'cc65'), ['foo.c']);
|
|
assert.deepStrictEqual(deps(';#link "foo.s"\n', 'ca65'), ['foo.s']);
|
|
assert.deepStrictEqual(deps('//#link "foo.v"\n', 'verilator'), []); // hdl tools don't link
|
|
assert.deepStrictEqual(deps('//#link "foo.v"\n', null, 'verilog'), []);
|
|
});
|
|
|
|
it('parses verilog directives in .asm files built by jsasm', function () {
|
|
// presets/verilog/test2.asm: .include "*.v" plus ".arch femto16"
|
|
let text = '.include "cpu16.v"\n.arch femto16\n';
|
|
let files = matchDependencyPatterns(text, getIncludePatterns('jsasm', 'verilog'));
|
|
assert.deepStrictEqual(files, ['cpu16.v', 'femto16.json']);
|
|
// and no shared-pattern duplicate of the .include
|
|
assert.strictEqual(files.filter(f => f == 'cpu16.v').length, 1);
|
|
});
|
|
|
|
it('falls back to the platform when a tool declares no patterns', function () {
|
|
// 'basic' has no includePatterns of its own -> platform default
|
|
assert.deepStrictEqual(
|
|
matchDependencyPatterns('#include "foo.h"\n', getIncludePatterns('basic', 'c64')),
|
|
['foo.h']);
|
|
// an explicit empty list means "this tool has no such directives"
|
|
assert.deepStrictEqual(getLinkPatterns('jsasm', 'verilog'), []);
|
|
});
|
|
|
|
it('resolves platform-specific tool help pages', function () {
|
|
// cc65 publishes per-platform manuals; those win over the generic page
|
|
assert.strictEqual(getToolHelpURL('cc65', 'atari8'), 'https://cc65.github.io/doc/atari.html');
|
|
assert.strictEqual(getToolHelpURL('cc65', 'c64'), 'https://cc65.github.io/doc/c64.html');
|
|
// suffixed platform ids resolve through their root base
|
|
assert.strictEqual(getToolHelpURL('cc65', 'atari8-800.xlmame'), 'https://cc65.github.io/doc/atari.html');
|
|
// no platform-specific page -> the tool's generic helpURL
|
|
assert.strictEqual(getToolHelpURL('cc65', 'vector'), TOOL_META['cc65'].helpURL);
|
|
assert.strictEqual(getToolHelpURL('dasm', 'atari8'), TOOL_META['dasm'].helpURL);
|
|
// tools with no docs at all, or unknown tools
|
|
assert.strictEqual(getToolHelpURL('ld65', 'atari8'), undefined);
|
|
assert.strictEqual(getToolHelpURL('bogus', 'atari8'), undefined);
|
|
});
|
|
|
|
it('getPlatformToolHelpURL only returns platform-specific pages', function () {
|
|
assert.strictEqual(getPlatformToolHelpURL('cc65', 'atari8'), 'https://cc65.github.io/doc/atari.html');
|
|
assert.strictEqual(getPlatformToolHelpURL('cc65', 'atari8-800.xlmame'), 'https://cc65.github.io/doc/atari.html');
|
|
// generic-only tools have no platform-specific page
|
|
assert.strictEqual(getPlatformToolHelpURL('dasm', 'atari8'), undefined);
|
|
assert.strictEqual(getPlatformToolHelpURL('cc65', 'vector'), undefined);
|
|
assert.strictEqual(getPlatformToolHelpURL('bogus', 'atari8'), undefined);
|
|
});
|
|
|
|
it('rewinds shared global patterns between files', function () {
|
|
// patterns are shared between tools and have the /g flag, so a stale
|
|
// lastIndex would make the second scan miss the directive
|
|
let pats = getIncludePatterns('cc65');
|
|
assert.deepStrictEqual(matchDependencyPatterns('#include "a.h"\n', pats), ['a.h']);
|
|
assert.deepStrictEqual(matchDependencyPatterns('#include "b.h"\n', pats), ['b.h']);
|
|
});
|
|
});
|