Files
sonya/Sources/sonyalib/Tests/sonyalibTests/sonyalibTests.swift
T
sonya 96ba9e3a56 0.1v: basic features
added lexer, parser, Shell, Executor.
added tests for sonyalib
it already works! will be implementing more features soon.
2026-04-21 23:11:14 +09:00

113 lines
3.3 KiB
Swift

import Testing
@testable import sonyalib
// MARK: - Lexer
@Test func lexer_tokenizes_recipe_with_no_deps() {
let tokens = Lexer().tokenize("build:")
#expect(tokens == [.recipe("build")])
}
@Test func lexer_tokenizes_recipe_with_deps() {
let tokens = Lexer().tokenize("test: build lint")
#expect(tokens == [.recipe("test"), .dependency("build"), .dependency("lint")])
}
@Test func lexer_tokenizes_command() {
let tokens = Lexer().tokenize(" echo hello")
#expect(tokens == [.command("echo hello")])
}
@Test func lexer_tokenizes_variable() {
let tokens = Lexer().tokenize("CC = clang")
#expect(tokens == [.variable(name: "CC", value: "clang")])
}
@Test func lexer_tokenizes_comment() {
let tokens = Lexer().tokenize("# this is a comment")
#expect(tokens == [.comment(" this is a comment")])
}
@Test func lexer_empty_line_produces_newline() {
let tokens = Lexer().tokenize("")
#expect(tokens == [.newline])
}
@Test func lexer_multiline_sonyafile() {
let input = """
build:
swift build
"""
let tokens = Lexer().tokenize(input)
#expect(tokens == [.recipe("build"), .command("swift build")])
}
// MARK: - Parser
@Test func parser_single_recipe_with_command() {
let tokens: [Token] = [.recipe("build"), .command("swift build")]
let ast = Parcer().parce(tokens)
#expect(ast != nil)
#expect(ast?.rules["build"]?.commands == ["swift build"])
}
@Test func parser_recipe_with_dependency() {
let tokens: [Token] = [
.recipe("test"), .dependency("build"),
.command("swift test")
]
let ast = Parcer().parce(tokens)
#expect(ast?.rules["test"]?.dependencies == ["build"])
#expect(ast?.rules["test"]?.commands == ["swift test"])
}
@Test func parser_variable_is_stored() {
let tokens: [Token] = [.variable(name: "CC", value: "clang")]
let ast = Parcer().parce(tokens)
#expect(ast?.vars["CC"] == "clang")
}
@Test func parser_multiple_recipes() {
let tokens: [Token] = [
.recipe("build"), .command("swift build"),
.newline,
.recipe("test"), .command("swift test"),
]
let ast = Parcer().parce(tokens)
#expect(ast?.rules["build"]?.commands == ["swift build"])
#expect(ast?.rules["test"]?.commands == ["swift test"])
}
@Test func parser_variable_before_recipe_flushes_context() {
// A variable declaration after a recipe must flush the current recipe first.
let tokens: [Token] = [
.recipe("build"), .command("swift build"),
.variable(name: "X", value: "1"),
]
let ast = Parcer().parce(tokens)
#expect(ast?.rules["build"]?.commands == ["swift build"])
#expect(ast?.vars["X"] == "1")
}
// MARK: - Variable resolution
@Test func resolve_substitutes_known_variable() {
let result = resolve("$(CC) main.c", vars: ["CC": "clang"])
#expect(result == "clang main.c")
}
@Test func resolve_returns_nil_for_unknown_variable() {
let result = resolve("$(MISSING) main.c", vars: [:])
#expect(result == nil)
}
@Test func resolve_no_variables_passes_through() {
let result = resolve("echo hello", vars: [:])
#expect(result == "echo hello")
}
@Test func resolve_multiple_substitutions() {
let result = resolve("$(CC) $(FLAGS) main.c", vars: ["CC": "clang", "FLAGS": "-O2"])
#expect(result == "clang -O2 main.c")
}