aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/rosa/azalea/azalea_test.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-05-15 06:48:04 +0900
committerOphestra <cat@gensokyo.uk>2026-05-16 14:29:28 +0900
commitd38d306147979cbc7f161d1150d6786572598497 (patch)
tree4e8a4e493333ff7a171baf4eb2547ab3dfc6449f /internal/rosa/azalea/azalea_test.go
parentc32c06b2e88f7ccc21bf05c2ebfb12bf884e335c (diff)
internal/rosa/azalea: ast and parser
This syntax is not final, but acts as a stopgap solution and a proof of concept. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/rosa/azalea/azalea_test.go')
-rw-r--r--internal/rosa/azalea/azalea_test.go156
1 files changed, 156 insertions, 0 deletions
diff --git a/internal/rosa/azalea/azalea_test.go b/internal/rosa/azalea/azalea_test.go
new file mode 100644
index 00000000..f2dec252
--- /dev/null
+++ b/internal/rosa/azalea/azalea_test.go
@@ -0,0 +1,156 @@
+package azalea_test
+
+import (
+ _ "embed"
+ "reflect"
+ "strings"
+ "testing"
+ "text/scanner"
+
+ . "hakurei.app/internal/rosa/azalea"
+)
+
+//go:embed testdata/gcc.az
+var sample string
+
+func TestParse(t *testing.T) {
+ t.Parallel()
+
+ testCases := []struct {
+ name string
+ data string
+ want []any
+ err error
+ }{
+ {"invalid", "}", nil, ExprError('}')},
+ {"bad sep", "f{v?}", nil, TokenError{'=', '?'}},
+ {"bad ident", "f{9}", nil, TokenError{scanner.Ident, scanner.Int}},
+ {"share bad sep", "f { v,,v = v; }", nil, ExprError(',')},
+ {"share missing sep", "f { v v }", nil, TokenError{',', scanner.Ident}},
+
+ {"ident", `v`, []any{Ident("v")}, nil},
+ {"concat", `f { v = v+"\xfd"+p{}+9; }`, []any{Func{
+ Ident: "f",
+
+ Args: []Arg{{K: []Ident{"v"}, V: Val{
+ Ident("v"),
+ String("\xfd"),
+ Func{Ident: "p"},
+ Int(9),
+ }}},
+ }}, nil},
+ {"truncated string concat", `f { v = v+; }`, nil,
+ ExprError(';')},
+
+ {"empty pairs", `{}`, []any{[]KV(nil)}, nil},
+ {"short kv", `{"\x00":v;}`, []any{[]KV{
+ {K: "\x00", V: Val{Ident("v")}},
+ }}, nil},
+ {"truncated kv", `{"\x00"`, nil, ExprError(scanner.EOF)},
+ {"ident kv", `{v="";}`, nil, ExprError(scanner.Ident)},
+
+ {"empty array", `[]`, []any{Array(nil)}, nil},
+ {"integer array", `[9]`, []any{Array{{Int(9)}}}, nil},
+ {"short array", `[ "\x00" ]`, []any{
+ Array{{String("\x00")}},
+ }, nil},
+ {"short array delim", `[ "\x00", ]`, []any{
+ Array{{String("\x00")}},
+ }, nil},
+ {"missing array value", `[ "\x00", , v ]`, nil, ExprError(',')},
+ {"missing array delimiter", `[ v0 v1 ]`, nil, TokenError{',', scanner.Ident}},
+ {"truncated array", `[ "\x00"`, nil,
+ ExprError(scanner.EOF)},
+
+ {"gcc", sample, []any{Func{
+ Ident: Ident("gcc"),
+ Package: true,
+
+ Args: []Arg{
+ {K: []Ident{Ident("description")}, V: Val{String("The GNU Compiler Collection")}},
+ {K: []Ident{Ident("website")}, V: Val{String("https://www.gnu.org/software/gcc")}},
+ {K: []Ident{Ident("anitya")}, V: Val{Int(6502)}},
+
+ {K: []Ident{Ident("version")}, V: Val{String("16.1.0")}, R: true},
+ {K: []Ident{Ident("source")}, V: Val{Func{
+ Ident: Ident("remoteTar"),
+
+ Args: []Arg{
+ {K: []Ident{Ident("url")}, V: Val{
+ String("https://ftp.tsukuba.wide.ad.jp/software/gcc/releases/"),
+ String("gcc-"),
+ Ident("version"),
+ String("/gcc-"),
+ Ident("version"),
+ String(".tar.gz"),
+ }},
+ {K: []Ident{Ident("checksum")}, V: Val{String("4ASoWbxaA2FW7PAB0zzHDPC5XnNhyaAyjtDPpGzceSLeYnEIXsNYZR3PA_Zu5P0K")}},
+ {K: []Ident{Ident("compress")}, V: Val{Ident("gzip")}},
+ },
+ }}},
+ {K: []Ident{Ident("patches")}, V: Val{Array{
+ {String("musl-off64_t-loff_t.patch")},
+ {String("musl-legacy-lfs.patch")},
+ }}},
+
+ {K: []Ident{Ident("exclusive")}, V: Val{Ident("true")}},
+
+ {K: []Ident{Ident("exec")}, V: Val{Func{
+ Ident: Ident("make"),
+
+ Args: []Arg{
+ {K: []Ident{Ident("configure")}, V: Val{[]KV{
+ {K: String("disable-multilib")},
+ {K: String("enable-default-pie")},
+ {K: String("disable-nls")},
+ {K: String("with-gnu-as")},
+ {K: String("with-gnu-ld")},
+ {K: String("with-system-zlib")},
+ {K: String("enable-languages"), V: Val{String("c,c++,go")}},
+ {K: String("with-native-system-header-dir"), V: Val{String("/system/include")}},
+ {K: String("with-multilib-list"), V: Val{Func{
+ Ident: Ident("arch"),
+
+ Args: []Arg{
+ {K: []Ident{Ident("amd64"), Ident("arm64")}, V: Val{String("''")}},
+ {K: []Ident{Ident("default")}, V: Val{Ident("unset")}},
+ },
+ }}},
+ }}},
+ {K: []Ident{Ident("make")}, V: Val{Array{
+ {String("BOOT_CFLAGS='-O2 -g'")},
+ {
+ Func{Ident: Ident("noop"), Args: []Arg{{K: []Ident{Ident("key")}, V: Val{Ident("value")}}}},
+ String("\x00"),
+ },
+ {String("bootstrap")},
+ }}},
+
+ {K: []Ident{Ident("skip-check")}, V: Val{Ident("true")}},
+ },
+ }}},
+
+ {K: []Ident{Ident("inputs")}, V: Val{Array{
+ {Ident("binutils")},
+ {Ident("mpc")},
+ {Ident("zlib")},
+ {Ident("libucontext")},
+ {Ident("kernel-headers")},
+ }}},
+ },
+ }}, nil},
+ }
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ p, err := Parse(strings.NewReader(tc.data))
+ if !reflect.DeepEqual(p, tc.want) {
+ t.Errorf("Parse: %#v, want %#v", p, tc.want)
+ }
+ if !reflect.DeepEqual(err, tc.err) {
+ t.Errorf("Parse: error = %v, want %v", err, tc.err)
+ }
+ })
+ }
+}