diff options
| author | Ophestra <cat@gensokyo.uk> | 2026-04-16 16:00:32 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2026-04-16 17:43:52 +0900 |
| commit | 823575acaccfb34d908dad2ae14551fa425d7431 (patch) | |
| tree | f9df2fc4a28169e89a90a8477188e84bbe3077b2 /cmd/mbf/info_test.go | |
| parent | 136bc0917be7c02b818bfc8d4d54ec8ffbc8d21b (diff) | |
cmd/mbf: move info command
This is cleaner with less shared state.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'cmd/mbf/info_test.go')
| -rw-r--r-- | cmd/mbf/info_test.go | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/cmd/mbf/info_test.go b/cmd/mbf/info_test.go new file mode 100644 index 00000000..16e94364 --- /dev/null +++ b/cmd/mbf/info_test.go @@ -0,0 +1,170 @@ +package main + +import ( + "context" + "fmt" + "log" + "os" + "path/filepath" + "reflect" + "strings" + "syscall" + "testing" + "unsafe" + + "hakurei.app/internal/pkg" + "hakurei.app/internal/rosa" + "hakurei.app/message" +) + +func TestInfo(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + args []string + status map[string]string + report string + want string + wantErr any + }{ + {"qemu", []string{"qemu"}, nil, "", ` +name : qemu-` + rosa.Std.Version(rosa.QEMU) + ` +description : a generic and open source machine emulator and virtualizer +website : https://www.qemu.org +depends on : glib-` + rosa.Std.Version(rosa.GLib) + ` zstd-` + rosa.Std.Version(rosa.Zstd) + ` +`, nil}, + + {"multi", []string{"hakurei", "hakurei-dist"}, nil, "", ` +name : hakurei-` + rosa.Std.Version(rosa.Hakurei) + ` +description : low-level userspace tooling for Rosa OS +website : https://hakurei.app + +name : hakurei-dist-` + rosa.Std.Version(rosa.HakureiDist) + ` +description : low-level userspace tooling for Rosa OS (distribution tarball) +website : https://hakurei.app +`, nil}, + + {"nonexistent", []string{"zlib", "\x00"}, nil, "", ` +name : zlib-` + rosa.Std.Version(rosa.Zlib) + ` +description : lossless data-compression library +website : https://zlib.net + +`, fmt.Errorf("unknown artifact %q", "\x00")}, + + {"status cache", []string{"zlib", "zstd"}, map[string]string{ + "zstd": "internal/pkg (amd64) on satori\n", + "hakurei": "internal/pkg (amd64) on satori\n\n", + }, "", ` +name : zlib-` + rosa.Std.Version(rosa.Zlib) + ` +description : lossless data-compression library +website : https://zlib.net +status : not yet cured + +name : zstd-` + rosa.Std.Version(rosa.Zstd) + ` +description : a fast compression algorithm +website : https://facebook.github.io/zstd +status : internal/pkg (amd64) on satori +`, nil}, + + {"status cache perm", []string{"zlib"}, map[string]string{ + "zlib": "\x00", + }, "", ` +name : zlib-` + rosa.Std.Version(rosa.Zlib) + ` +description : lossless data-compression library +website : https://zlib.net +`, func(cm *cache) error { + return &os.PathError{ + Op: "open", + Path: filepath.Join(cm.base, "status", pkg.Encode(cm.c.Ident(rosa.Std.Load(rosa.Zlib)).Value())), + Err: syscall.EACCES, + } + }}, + + {"status report", []string{"zlib"}, nil, strings.Repeat("\x00", len(pkg.Checksum{})+8), ` +name : zlib-` + rosa.Std.Version(rosa.Zlib) + ` +description : lossless data-compression library +website : https://zlib.net +status : not in report +`, nil}, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + var ( + cm *cache + buf strings.Builder + rp string + ) + + if tc.status != nil || tc.report != "" { + cm = &cache{ + ctx: context.Background(), + msg: message.New(log.New(os.Stderr, "info: ", 0)), + base: t.TempDir(), + } + defer cm.Close() + } + + if tc.report != "" { + rp = filepath.Join(t.TempDir(), "report") + if err := os.WriteFile( + rp, + unsafe.Slice(unsafe.StringData(tc.report), len(tc.report)), + 0400, + ); err != nil { + t.Fatal(err) + } + } + + if tc.status != nil { + for name, status := range tc.status { + p, ok := rosa.ResolveName(name) + if !ok { + t.Fatalf("invalid name %q", name) + } + perm := os.FileMode(0400) + if status == "\x00" { + perm = 0 + } + if err := cm.Do(func(cache *pkg.Cache) error { + return os.WriteFile(filepath.Join( + cm.base, + "status", + pkg.Encode(cache.Ident(rosa.Std.Load(p)).Value()), + ), unsafe.Slice(unsafe.StringData(status), len(status)), perm) + }); err != nil { + t.Fatalf("Do: error = %v", err) + } + } + } + + var wantErr error + switch c := tc.wantErr.(type) { + case error: + wantErr = c + case func(cm *cache) error: + wantErr = c(cm) + default: + if tc.wantErr != nil { + t.Fatalf("invalid wantErr %#v", tc.wantErr) + } + } + + if err := commandInfo( + cm, + tc.args, + &buf, + cm != nil, + rp, + ); !reflect.DeepEqual(err, wantErr) { + t.Fatalf("commandInfo: error = %v, want %v", err, wantErr) + } + + if got := buf.String(); got != strings.TrimPrefix(tc.want, "\n") { + t.Errorf("commandInfo:\n%s\nwant\n%s", got, tc.want) + } + }) + } +} |
