diff options
| author | Rose Hogenson <rosehogenson@posteo.net> | 2025-10-23 21:02:22 -0700 |
|---|---|---|
| committer | Rose Hogenson <rosehogenson@posteo.net> | 2025-10-23 21:02:22 -0700 |
| commit | 3c2c07a69daf75d377ba196c28524c0fc6a16db6 (patch) | |
| tree | 83a1c9ea49bc8c0927f8de2ed9f3b933f29759f0 /enc_test.go | |
| parent | Get rid of the base64 encoding (diff) | |
| download | sym-3c2c07a69daf75d377ba196c28524c0fc6a16db6.tar.zst | |
Move sym files into the root directory
Diffstat (limited to 'enc_test.go')
| -rw-r--r-- | enc_test.go | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/enc_test.go b/enc_test.go new file mode 100644 index 0000000..3a0c493 --- /dev/null +++ b/enc_test.go @@ -0,0 +1,242 @@ +package sym + +import ( + "bytes" + "errors" + "flag" + "path/filepath" + "strings" + "testing" +) + +func TestEncryptFile_Force(t *testing.T) { + t.Parallel() + + for _, tc := range []struct { + desc string + force bool + wantErr bool + }{{ + desc: "OutputExists", + force: false, + wantErr: true, + }, { + desc: "Force", + force: true, + wantErr: false, + }} { + t.Run(tc.desc, func(t *testing.T) { + t.Parallel() + + fileName := filepath.Join(t.TempDir(), "file") + mustWriteFile(t, fileName, []byte("test file content")) + mustWriteFile(t, fileName+".enc", []byte("file already exists")) + encOpts := testEncryptOptions + encOpts.force = tc.force + err := encOpts.encryptFile(fileName, "asdf") + if gotErr := err != nil; gotErr != tc.wantErr { + t.Errorf("EncryptFile(force=%t) returned returned error %v when output file exists, want error? %t", tc.force, err, tc.wantErr) + } + }) + } +} + +func TestEncryptFile_NotFound(t *testing.T) { + t.Parallel() + + err := testEncryptOptions.encryptFile("my-nonexistent-file.txt", "asdf") + if err == nil { + t.Fatal("encryptFile succeeded for nonexistent file, want error") + } +} + +func TestEncryptFile_NoPermission(t *testing.T) { + t.Parallel() + + fileName := filepath.Join(t.TempDir(), "file") + mustWriteFile(t, fileName, []byte("test file content")) + mustWriteFile(t, fileName+".enc", nil) + mustChmod(t, fileName+".enc", 0400) + opts := testEncryptOptions + opts.force = true + err := opts.encryptFile(fileName, "asdf") + if err == nil { + t.Fatal("encryptFile succeeded for unwritable file, want error") + } +} + +func TestEncryptOptions_RegisterFlags(t *testing.T) { + t.Parallel() + + var o EncryptOptions + fs := flag.NewFlagSet("test", flag.ContinueOnError) + o.RegisterFlags(fs) + const cmd = "-g -p asdf -f" + fs.Parse(strings.Split(cmd, " ")) + want := encryptFlags{ + generatePassword: true, + password: "asdf", + force: true, + } + if o.encryptFlags != want { + t.Errorf("Command line %q parsed incorrect EncryptOptions, got %+v, want %+v", cmd, o, want) + } +} + +func TestEncryptOptions_Run(t *testing.T) { + t.Parallel() + + const password = "asdf" + fileContent := []byte("test file content") + fileName := filepath.Join(t.TempDir(), "file") + mustWriteFile(t, fileName, fileContent) + opts := testEncryptOptions + opts.password = password + if err := opts.Run(fileName); err != nil { + t.Fatalf("enc failed: %s", err) + } + mustRemove(t, fileName) + if err := DefaultDecryptOptions.decryptFile(fileName+".enc", password); err != nil { + t.Fatalf("Failed to decrypt encrypted file: %s", err) + } + gotFileContents := mustReadFile(t, fileName) + if !bytes.Equal(gotFileContents, fileContent) { + t.Errorf("encrypt round trip returned incorrect contents %q, want %q", gotFileContents, fileContent) + } +} + +func TestEncryptOptions_Run_UsageError(t *testing.T) { + t.Parallel() + + for _, tc := range []struct { + desc string + generatePassword bool + password string + files []string + }{{ + desc: "GeneratePasswordAndPassword", + generatePassword: true, + password: "asdf", + }, { + desc: "MissingPasswordStdin", + generatePassword: false, + password: "", + }, { + desc: "NonexistentFile", + password: "asdf", + files: []string{"my-nonexistent-file.txt"}, + }} { + t.Run(tc.desc, func(t *testing.T) { + t.Parallel() + + opts := testEncryptOptions + opts.generatePassword = tc.generatePassword + opts.password = tc.password + if err := opts.Run(tc.files...); err == nil { + t.Errorf("Run(%+v) succeeded, want error", opts) + } + }) + } +} + +func TestEncryptOptions_Run_GeneratePassword(t *testing.T) { + t.Parallel() + + fileContent := []byte("test file content") + fileName := filepath.Join(t.TempDir(), "file") + mustWriteFile(t, fileName, fileContent) + + password := new(strings.Builder) + opts := testEncryptOptions + opts.generatePassword = true + opts.passwordOut = password + if err := opts.Run(fileName); err != nil { + t.Fatalf("enc(%+v) failed: %s", opts, err) + } + pw := password.String() + mustRemove(t, fileName) + if err := DefaultDecryptOptions.decryptFile(fileName+".enc", pw); err != nil { + t.Fatalf("Failed to decrypt encrypted file with generated password %q: %s", pw, err) + } + gotFileContents := mustReadFile(t, fileName) + if !bytes.Equal(gotFileContents, fileContent) { + t.Errorf("encrypt round trip returned incorrect contents %q, want %q", gotFileContents, fileContent) + } +} + +func TestEncryptOptions_Run_Stdin(t *testing.T) { + t.Parallel() + + const ( + input = "test input" + password = "asdf" + ) + stdout := new(strings.Builder) + opts := testEncryptOptions + opts.password = password + opts.stdin = strings.NewReader(input) + opts.stdout = stdout + if err := opts.Run(); err != nil { + t.Errorf("enc(+%v) failed: %s", opts, err) + } + got := new(strings.Builder) + if err := decrypt(got, strings.NewReader(stdout.String()), password); err != nil { + t.Errorf("Failed to decrypt stdout content %q: %s", stdout, err) + } + if got, want := got.String(), input; got != want { + t.Errorf("Encrypt round-trip to stdout returned incorrect contents: %q, want %q", got, want) + } +} + +func TestEncryptOptions_Run_ReadPassword(t *testing.T) { + t.Parallel() + + for _, tc := range []struct { + desc string + passwords []string + err error + wantErr bool + }{{ + desc: "Ok", + passwords: []string{"asdf"}, + }, { + desc: "EmptyPassword", + passwords: []string{""}, + wantErr: true, + }, { + desc: "PasswordsDoNotMatch", + passwords: []string{"asdf", "jkl"}, + wantErr: true, + }, { + desc: "ReadPasswordErr", + err: errors.New("test error"), + wantErr: true, + }, { + desc: "RepeatPasswordErr", + passwords: []string{"asdf"}, + err: errors.New("test error"), + wantErr: true, + }} { + t.Run(tc.desc, func(t *testing.T) { + t.Parallel() + + fileName := filepath.Join(t.TempDir(), "file") + mustWriteFile(t, fileName, []byte("test file content")) + + opts := testEncryptOptions + passwordI := 0 + opts.passwordIn = func() (string, error) { + if passwordI == len(tc.passwords) && tc.err != nil { + return "", tc.err + } + pw := tc.passwords[passwordI%len(tc.passwords)] + passwordI++ + return pw, nil + } + err := opts.Run(fileName) + if gotErr := err != nil; gotErr != tc.wantErr { + t.Errorf("EncryptOptions.Run returned error %v, want error? %t", err, tc.wantErr) + } + }) + } +} |
