136 lines
3.7 KiB
Go
136 lines
3.7 KiB
Go
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package format
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"sourcedock.dev/petrbalvin/gasm-devkit/lexer"
|
|
"sourcedock.dev/petrbalvin/gasm-devkit/parser"
|
|
"sourcedock.dev/petrbalvin/gasm-devkit/token"
|
|
)
|
|
|
|
func TestGolden(t *testing.T) {
|
|
in := "#include \"textflag.h\"\n" +
|
|
"\n" +
|
|
"TEXT ·f(SB), NOSPLIT, $0\n" +
|
|
"MOVQ swin_base+0(FP), SI\n" +
|
|
"LEAQ (SI)(BX*4), R9\n" +
|
|
"ANDQ $-8, R10\n" +
|
|
"VFMADD231PD Z14, Z12, Z10\n" +
|
|
"RET\n"
|
|
|
|
want := "#include \"textflag.h\"\n" +
|
|
"\n" +
|
|
"TEXT ·f(SB), NOSPLIT, $0\n" +
|
|
"\tMOVQ swin_base+0(FP), SI\n" +
|
|
"\tLEAQ (SI)(BX*4), R9\n" +
|
|
"\tANDQ $-8, R10\n" +
|
|
"\tVFMADD231PD Z14, Z12, Z10\n" +
|
|
"\tRET\n"
|
|
|
|
got := Source("f_amd64.s", in)
|
|
if got != want {
|
|
t.Fatalf("formatting mismatch:\n--- got ---\n%q\n--- want ---\n%q", got, want)
|
|
}
|
|
}
|
|
|
|
// TestDocCommentIndent checks that a doc comment preceding a TEXT directive
|
|
// sits at column 0 even when another function (ending in RET) precedes it —
|
|
// the RET must terminate the previous body for indentation purposes.
|
|
func TestDocCommentIndent(t *testing.T) {
|
|
in := "#include \"textflag.h\"\n" +
|
|
"\n" +
|
|
"// func first()\n" +
|
|
"TEXT ·first(SB), NOSPLIT, $0\n" +
|
|
"XORQ AX, AX\n" +
|
|
"RET\n" +
|
|
"\n" +
|
|
"// func second()\n" +
|
|
"TEXT ·second(SB), NOSPLIT, $0\n" +
|
|
"RET\n"
|
|
|
|
want := "#include \"textflag.h\"\n" +
|
|
"\n" +
|
|
"// func first()\n" +
|
|
"TEXT ·first(SB), NOSPLIT, $0\n" +
|
|
"\tXORQ AX, AX\n" +
|
|
"\tRET\n" +
|
|
"\n" +
|
|
"// func second()\n" +
|
|
"TEXT ·second(SB), NOSPLIT, $0\n" +
|
|
"\tRET\n"
|
|
|
|
got := Source("d_amd64.s", in)
|
|
if got != want {
|
|
t.Fatalf("formatting mismatch:\n--- got ---\n%q\n--- want ---\n%q", got, want)
|
|
}
|
|
// Body comments stay indented.
|
|
body := "#include \"textflag.h\"\nTEXT ·f(SB), NOSPLIT, $0\n// inside the body\nXORQ AX, AX\nRET\n"
|
|
gotBody := Source("b_amd64.s", body)
|
|
if !strings.Contains(gotBody, "\t// inside the body\n") {
|
|
t.Fatalf("body comment must stay indented:\n%q", gotBody)
|
|
}
|
|
}
|
|
|
|
func TestOperandSpacing(t *testing.T) {
|
|
cases := map[string]string{
|
|
"4(SI)": "4(SI)",
|
|
"(SI)(BX*4)": "(SI)(BX*4)",
|
|
"$-8": "$-8",
|
|
"$0x80020100": "$0x80020100",
|
|
"swin_base+0(FP)": "swin_base+0(FP)",
|
|
"mask24<>(SB)": "mask24<>(SB)",
|
|
"·idx16+0(SB)/4": "·idx16+0(SB)/4",
|
|
}
|
|
for in, want := range cases {
|
|
toks := lexOperands(in)
|
|
if got := renderOps(toks); got != want {
|
|
t.Errorf("renderOps(%q) = %q, want %q", in, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// lexOperands lexes a single operand string and drops the EOF token.
|
|
func lexOperands(s string) []token.Token {
|
|
toks := lexer.Tokenize(s)
|
|
return toks[:len(toks)-1] // drop trailing EOF
|
|
}
|
|
|
|
func TestIdempotent(t *testing.T) {
|
|
src, err := os.ReadFile("../testdata/sample_amd64.s")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
once := Source("sample_amd64.s", string(src))
|
|
twice := Source("sample_amd64.s", once)
|
|
if once != twice {
|
|
t.Fatal("formatting is not idempotent on the fixture")
|
|
}
|
|
}
|
|
|
|
// TestRoundTrip checks that formatting produces source that still parses
|
|
// cleanly, on the fixture and on the real go-flac kernels when present.
|
|
func TestRoundTrip(t *testing.T) {
|
|
files := []string{"../testdata/sample_amd64.s"}
|
|
real, _ := filepath.Glob("../../go-libraries/go-*/*.s")
|
|
files = append(files, real...)
|
|
for _, path := range files {
|
|
src, err := os.ReadFile(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
formatted := Source(path, string(src))
|
|
if _, errs := parser.Parse(path, formatted); len(errs) > 0 {
|
|
t.Errorf("formatted %s no longer parses: %v", path, errs)
|
|
}
|
|
if strings.TrimSpace(formatted) == "" {
|
|
t.Errorf("formatted %s is empty", path)
|
|
}
|
|
}
|
|
}
|