From 128d5c513b7a5c50a65f03480fc61b06fb5ef8e8 Mon Sep 17 00:00:00 2001 From: Rose Hogenson Date: Tue, 11 Nov 2025 11:27:17 -0800 Subject: Use subcommands package This reduces a little bit of complexity. (does it?) --- sym_test.go | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 2 deletions(-) (limited to 'sym_test.go') diff --git a/sym_test.go b/sym_test.go index 3da9fc1..8ae82cc 100644 --- a/sym_test.go +++ b/sym_test.go @@ -2,9 +2,13 @@ package main import ( "bytes" + "context" + "flag" "os" "path/filepath" "testing" + + "github.com/google/subcommands" ) func init() { @@ -59,11 +63,11 @@ func TestEncryptDecrypt(t *testing.T) { fileName := filepath.Join(t.TempDir(), "file") mustWriteFile(t, fileName, buf) const password = "karp cache tidal mars fed rajah uses graze pobox flew" - if err := (&encryptOptions{}).encryptFile(fileName, password); err != nil { + if err := (&encCmd{}).encryptFile(fileName, password); err != nil { t.Fatalf("EncryptFile failed: %s", err) } mustRemove(t, fileName) - if err := (&decryptOptions{}).decryptFile(fileName+".enc", password); err != nil { + if err := (&decCmd{}).decryptFile(fileName+".enc", password); err != nil { t.Fatalf("DecryptFile failed: %s", err) } gotContents := mustReadFile(t, fileName) @@ -71,3 +75,81 @@ func TestEncryptDecrypt(t *testing.T) { t.Errorf("contents differ") } } + +func run(ctx context.Context, t *testing.T, cmd ...string) subcommands.ExitStatus { + t.Helper() + + fs := flag.NewFlagSet("test", flag.ContinueOnError) + commander := subcommands.NewCommander(fs, "test") + registerCommands(commander, nil, nil, nil, nil) + if err := fs.Parse(cmd); err != nil { + t.Fatalf("Failed to parse command %q: %s", cmd, err) + } + return commander.Execute(ctx) +} + +func TestCommander(t *testing.T) { + t.Parallel() + + ctx := t.Context() + fileName := filepath.Join(t.TempDir(), "file.txt") + const fileContent = "test file content" + mustWriteFile(t, fileName, []byte(fileContent)) + const password = "asdf" + if st := run(ctx, t, "enc", "-p="+password, fileName); st != subcommands.ExitSuccess { + t.Fatalf("enc failed: status %d", st) + } + mustRemove(t, fileName) + if st := run(ctx, t, "dec", "-p="+password, fileName+".enc"); st != subcommands.ExitSuccess { + t.Fatalf("dec failed: status %d", st) + } + gotContents := mustReadFile(t, fileName) + if !bytes.Equal(gotContents, []byte(fileContent)) { + t.Errorf("dec returned invalid content, got %q, want %q", gotContents, fileContent) + } +} + +func TestCommander_Errors(t *testing.T) { + t.Parallel() + + for _, tc := range []struct { + desc string + cmd []string + wantStatus subcommands.ExitStatus + } {{ + desc: "EncUsageError", + cmd: []string{"enc", "-g", "-p=asdf", "file.txt"}, + wantStatus: subcommands.ExitUsageError, + }, { + desc: "EncNoSuchFile", + cmd: []string{"enc", "-p=asdf", "nonexistent-file.txt"}, + wantStatus: subcommands.ExitFailure, + }, { + desc: "DecUsageError", + cmd: []string{"dec"}, + wantStatus: subcommands.ExitUsageError, + }, { + desc: "DecNoSuchFile", + cmd: []string{"dec", "-p=asdf", "nonexistent-file.txt.enc"}, + wantStatus: subcommands.ExitFailure, + }} { + t.Run(tc.desc, func(t *testing.T) { + t.Parallel() + + ctx := t.Context() + st := run(ctx, t, tc.cmd...) + if st != tc.wantStatus { + t.Errorf("command %q returned status %d, want %d", tc.cmd, st, tc.wantStatus) + } + }) + } +} + +func TestUsage(t *testing.T) { + t.Parallel() + + ctx := t.Context() + run(ctx, t, "help") + run(ctx, t, "enc", "-h") + run(ctx, t, "dec", "-h") +} -- cgit v1.3.1