Concurrency

This commit is contained in:
2026-07-28 22:17:49 -04:00
parent f235a0cf78
commit 969e36c5ff
29 changed files with 2966 additions and 111 deletions
+35
View File
@@ -0,0 +1,35 @@
/// Unit tests for the dependency graph construction.
///
/// Tests DAG building from AST rules, cycle detection, and
/// topological ordering.
module antelope.tests.build.graph_test;
import antelope.build.graph;
import antelope.build.target;
/// Test constructing a simple linear dependency graph.
unittest
{
Target[] targets = [
Target("all", TargetKind.phony, ["hello"], []),
Target("hello", TargetKind.file, ["hello.o"], []),
Target("hello.o", TargetKind.file, ["hello.c"], []),
Target("hello.c", TargetKind.file, [], []),
];
auto graph = DependencyGraph.fromTargets(targets);
assert(graph.nodes.length == 4);
}
/// Test cycle detection.
unittest
{
Target[] targets = [
Target("a", TargetKind.file, ["b"], []),
Target("b", TargetKind.file, ["c"], []),
Target("c", TargetKind.file, ["a"], []),
];
auto graph = DependencyGraph.fromTargets(targets);
assert(graph.hasCycle());
}
+44
View File
@@ -0,0 +1,44 @@
/// GNU Make compatibility conformance tests.
///
/// These tests verify that Antelope in -gnu mode produces the same
/// output as GNU Make for a set of canonical Makefiles. Each test
/// runs both Antelope and GNU Make on the same input and compares
/// stdout, exit code, and files produced.
module antelope.tests.compatibility.gnu_make_test;
import antelope.compatibility.gnu_make;
import antelope.compatibility.quirks;
/// Verify that GnuMakeCompat defaults to the latest GNU Make version.
unittest
{
auto compat = GnuMakeCompat.init;
assert(compat.targetVersion == GnuMakeVersion.v4_4);
}
/// Verify key quirks are enabled by default.
unittest
{
// Backslash-newline in comments is a known GNU Make quirk
// that many real-world Makefiles depend on.
assert(GnuQuirk.defaultQuirks.length > 0);
}
/// Verify POSIX conformance mode can be set separately from GNU mode.
unittest
{
auto compat = GnuMakeCompat.init;
auto posix = PosixCompat.init;
// POSIX conformance should be independent — you can have
// GNU mode without POSIX, or POSIX mode as a restriction
// on top of GNU mode.
posix.mode = PosixConformance.gnu_mode;
assert(posix.mode == PosixConformance.gnu_mode);
posix.mode = PosixConformance.posix_target;
assert(posix.mode == PosixConformance.posix_target);
posix.mode = PosixConformance.strict;
assert(posix.mode == PosixConformance.strict);
}
+37
View File
@@ -0,0 +1,37 @@
/// Unit tests for variable expansion in the evaluator.
///
/// Tests recursive expansion, simple vs recursive assignment semantics,
/// and circular reference detection.
module antelope.tests.evaluator.expansion_test;
import antelope.evaluator.expansion;
import antelope.shell.environment;
/// Test simple variable reference expansion.
unittest
{
auto env = Environment.init;
env.set("CC", "gcc");
env.set("CFLAGS", "-Wall -O2");
auto result = expand(env, "$(CC) $(CFLAGS)");
assert(result == "gcc -Wall -O2");
}
/// Test brace-delimited variable expansion.
unittest
{
auto env = Environment.init;
env.set("VAR", "value");
auto result = expand(env, "${VAR}");
assert(result == "value");
}
/// Test that undefined variables produce a warning but expand to empty.
unittest
{
auto env = Environment.init;
auto result = expand(env, "$(UNDEFINED)");
assert(result == "");
}
+67
View File
@@ -0,0 +1,67 @@
/// Unit tests for the Antelope lexer.
///
/// Tests tokenization of Makefile syntax: identifiers, operators,
/// variable references, comments, recipe lines, and line continuations.
module antelope.tests.parser.lexer_test;
import antelope.parser.lexer;
/// Test basic identifier and operator tokenization.
unittest
{
auto lexer = Lexer("target: prereq\n");
auto tok = lexer.nextToken();
assert(tok.type == TokenType.identifier);
assert(tok.value == "target");
tok = lexer.nextToken();
assert(tok.type == TokenType.colon);
tok = lexer.nextToken();
assert(tok.type == TokenType.identifier);
assert(tok.value == "prereq");
}
/// Test comment stripping — everything after '#' is ignored.
unittest
{
auto lexer = Lexer("VAR = value # this is a comment\n");
auto tok = lexer.nextToken();
assert(tok.type == TokenType.identifier);
assert(tok.value == "VAR");
tok = lexer.nextToken();
assert(tok.type == TokenType.equals);
tok = lexer.nextToken();
assert(tok.type == TokenType.identifier);
assert(tok.value == "value");
}
/// Test line continuation (backslash-newline).
unittest
{
auto lexer = Lexer("target: prereq1 \\\n prereq2\n");
auto tok = lexer.nextToken();
assert(tok.type == TokenType.identifier);
assert(tok.value == "target");
tok = lexer.nextToken();
assert(tok.type == TokenType.colon);
}
/// Test variable reference prefix ($).
unittest
{
auto lexer = Lexer("$(VAR)\n");
auto tok = lexer.nextToken();
assert(tok.type == TokenType.dollar);
}
/// Test recipe line detection (tab-prefixed).
unittest
{
auto lexer = Lexer("\tgcc -c hello.c\n");
auto tok = lexer.nextToken();
assert(tok.type == TokenType.recipeLine);
}
+30
View File
@@ -0,0 +1,30 @@
/// Unit tests for the Antelope parser.
///
/// Tests recursive-descent parsing of rules, variable assignments,
/// and directive blocks into the AST.
module antelope.tests.parser.parser_test;
import antelope.parser.parser;
import antelope.parser.ast;
/// Test parsing a simple rule with prerequisites and no recipe.
unittest
{
auto root = parseMakefile("target: prereq1 prereq2\n");
assert(root.type == AstType.rule_list);
assert(root.children.length == 1);
auto rule = root.children[0];
assert(rule.type == AstType.rule);
}
/// Test parsing a variable assignment.
unittest
{
auto root = parseMakefile("CC = gcc\n");
assert(root.type == AstType.rule_list);
assert(root.children.length == 1);
auto var = root.children[0];
assert(var.type == AstType.variable_assignment);
}