{
var test = tape.createHarness();
var str = "";
test.createStream({ objectMode: false }).on("data", function (row) {
str += row + "\n";
});
var mainTestPromise = test("Macro and Parser tests", (t) => {
t.test("simpleTexMacroExpand Tests", (t) => {
t.test("Basic definition and usage", (t) => {
const input = "\\def\\greet{Hello}\n\\greet World";
const expected = "\nHello World";
const actual = simpleTexMacroExpand(input);
t.equal(actual, expected, "Should replace defined macro");
t.end();
});
t.test("Multiple definitions and usage", (t) => {
const input =
"\\def\\adj{Wonderful}\\def\\noun{World}\nSuch a \\adj \\noun!";
const expected = "\nSuch a Wonderful World!";
const actual = simpleTexMacroExpand(input);
t.equal(actual, expected, "Should handle multiple definitions");
t.end();
});
t.test("No definitions", (t) => {
const input = "Just plain text.";
const expected = "Just plain text.";
const actual = simpleTexMacroExpand(input);
t.equal(actual, expected, "Should return input if no defs");
t.end();
});
t.test("Definitions but no usage", (t) => {
const input = "Text before.\\def\\unused{Secret}Text after.";
const expected = "Text before.Text after.";
const actual = simpleTexMacroExpand(input);
t.equal(actual, expected, "Should remove unused definitions");
t.end();
});
t.test("Multi-line definition", (t) => {
const input = "\\def\\multiline{Line 1\nLine 2}\nUsage: \\multiline";
const expected = "\nUsage: Line 1\nLine 2";
const actual = simpleTexMacroExpand(input);
t.equal(actual, expected, "Should handle multi-line def body");
t.end();
});
t.test("Nested/Iterative expansion", (t) => {
const input =
"\\def\\base{A}\\def\\level1{\\base B}\\def\\level2{\\level1 C}\nExpand: \\level2";
const expected = "\nExpand: A B C";
const actual = simpleTexMacroExpand(input);
t.equal(actual, expected, "Should expand macros within macros");
t.end();
});
t.test("Undefined macro usage", (t) => {
const input = "\\def\\defined{Yes}\nUsing \\defined and \\undefined.";
const expected = "\nUsing Yes and \\undefined.";
const actual = simpleTexMacroExpand(input);
t.equal(actual, expected, "Should leave undefined macros as is");
t.end();
});
t.test("Word boundary check", (t) => {
const input = "\\def\\short{One}\nUse \\short and \\shortAndLong.";
const expected = "\nUse One and \\shortAndLong.";
const actual = simpleTexMacroExpand(input);
t.equal(actual, expected, "Should respect word boundaries");
t.end();
});
t.test("Empty definition", (t) => {
const input = "Start\\def\\empty{}End\nUse it here: >\\empty<";
const expected = "StartEnd\nUse it here: ><";
const actual = simpleTexMacroExpand(input);
t.equal(
actual,
expected,
"Should replace with empty string for empty def"
);
t.end();
});
t.test("Single argument macro", (t) => {
const input = "\\def\\echo#1{Input: #1}\nCall: \\echo{Test}";
const expected = "\nCall: Input: Test";
const actual = simpleTexMacroExpand(input);
t.equal(actual, expected, "Should handle single argument");
t.end();
});
t.test("Multiple argument macro", (t) => {
const input = "\\def\\pair#1#2{(#1, #2)}\nCoords: \\pair{X}{Y}";
const expected = "\nCoords: (X, Y)";
const actual = simpleTexMacroExpand(input);
t.equal(actual, expected, "Should handle multiple arguments");
t.end();
});
t.test("Arguments containing macros", (t) => {
const input =
"\\def\\bold#1{{\\bf #1}}\\def\\bf{BOLD}\\Usage: \\bold{Text}";
const expected = "\nUsage: {BOLD Text}";
const actual = simpleTexMacroExpand(input);
t.equal(
actual,
expected,
"Should expand macros within arguments during subsequent passes"
);
t.end();
});
t.test("Argument contains hash character", (t) => {
const input = "\\def\\show#1{See: #1}\n\\show{Value # is important}";
const expected = "\nSee: Value # is important";
const actual = simpleTexMacroExpand(input);
t.equal(
actual,
expected,
"Should not replace '#' within argument text"
);
t.end();
});
t.test("Macro with args used without args", (t) => {
const input = "\\def\\needsone#1{Got #1}\nCall: \\needsone maybe?";
const expected = "\nCall: \\needsone maybe?";
const actual = simpleTexMacroExpand(input);
t.equal(
actual,
expected,
"Should not expand arg macro if called without args"
);
t.end();
});
t.test("Macro without args used with braces (incorrectly)", (t) => {
const input = "\\def\\noargs{NA}\nCall: \\noargs{stuff}";
const expected = "\nCall: NA{stuff}";
const actual = simpleTexMacroExpand(input);
t.equal(
actual,
expected,
"Should expand no-arg macro and leave subsequent braces"
);
t.end();
});
t.test("Nested arguments and expansion", (t) => {
const input =
"\\def\\outer#1{Outer<#1>}\\def\\inner#1{Inner(#1)}\nExpand: \\outer{\\inner{Value}}";
const expected = "\nExpand: Outer<Inner(Value)>";
const actual = simpleTexMacroExpand(input);
t.equal(
actual,
expected,
"Should handle nested macro calls within arguments"
);
t.end();
});
t.test("Argument order", (t) => {
const input = "\\def\\reorder#1#2{#2 before #1}\nUse: \\reorder{A}{B}";
const expected = "\nUse: B before A";
const actual = simpleTexMacroExpand(input);
t.equal(actual, expected, "Should respect argument numbering (#1, #2)");
t.end();
});
t.end();
});
});
var m = new Promise((resolve, reject) => {
let finished = false;
let timeoutId = setTimeout(() => {
if (!finished) {
console.error("Test harness timed out!");
reject("Timeout\n" + str);
}
}, 5000);
test.onFinish(() => {
if (!finished) {
finished = true;
clearTimeout(timeoutId);
console.log("--- TAP Output ---");
console.log(str.trim());
console.log("--- Test Finished ---");
if (str.includes("not ok")) {
reject("Test failures detected.\n" + str);
} else {
resolve(str);
}
}
});
});
return m;
}