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) } }) } }