Skip to content

Commit 171db17

Browse files
committed
tests - add TestMainCommand
1 parent 9369e21 commit 171db17

File tree

1 file changed

+222
-0
lines changed

1 file changed

+222
-0
lines changed

phredsort_test.go

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"io"
66
"math"
77
"os"
8+
"path/filepath"
89
"reflect"
910
"sort"
1011
"strings"
@@ -846,3 +847,224 @@ func TestSortStdin(t *testing.T) {
846847
})
847848
}
848849
}
850+
851+
// TestMainCommand tests the main command functionality
852+
func TestMainCommand(t *testing.T) {
853+
// Create temporary directory for test files
854+
tmpDir, err := os.MkdirTemp("", "phredsort_test_*")
855+
if err != nil {
856+
t.Fatal(err)
857+
}
858+
defer os.RemoveAll(tmpDir)
859+
860+
// Helper function to create test FASTQ file
861+
createTestFastq := func(name string) string {
862+
path := filepath.Join(tmpDir, name)
863+
f, err := os.Create(path)
864+
if err != nil {
865+
t.Fatal(err)
866+
}
867+
defer f.Close()
868+
869+
// Write some test FASTQ data
870+
fmt.Fprintf(f, "@seq1\nACGT\n+\nIIII\n")
871+
fmt.Fprintf(f, "@seq2\nACGT\n+\n$$$$\n")
872+
return path
873+
}
874+
875+
// Helper function to capture stdout/stderr
876+
captureOutput := func(f func()) (string, string) {
877+
oldStdout := os.Stdout
878+
oldStderr := os.Stderr
879+
rOut, wOut, _ := os.Pipe()
880+
rErr, wErr, _ := os.Pipe()
881+
os.Stdout = wOut
882+
os.Stderr = wErr
883+
884+
f()
885+
886+
wOut.Close()
887+
wErr.Close()
888+
os.Stdout = oldStdout
889+
os.Stderr = oldStderr
890+
891+
stdout, _ := io.ReadAll(rOut)
892+
stderr, _ := io.ReadAll(rErr)
893+
return string(stdout), string(stderr)
894+
}
895+
896+
tests := []struct {
897+
name string
898+
args []string
899+
expectedCode int
900+
checkStdout bool
901+
checkStderr bool
902+
wantStdout string
903+
wantStderr string
904+
setupFiles bool
905+
validateFiles bool
906+
}{
907+
{
908+
name: "Version flag",
909+
args: []string{"--version"},
910+
expectedCode: 0,
911+
checkStdout: true,
912+
wantStdout: fmt.Sprintf("phredsort %s\n", VERSION),
913+
},
914+
{
915+
name: "Missing required flags",
916+
args: []string{},
917+
expectedCode: 1,
918+
checkStderr: true,
919+
wantStderr: red("Error: input and output files are required") + "\n" +
920+
red("Try 'phredsort --help' for more information") + "\n",
921+
},
922+
{
923+
name: "Invalid metric",
924+
args: []string{"--in", "input.fq", "--out", "output.fq", "--metric", "invalid"},
925+
expectedCode: 1,
926+
checkStderr: true,
927+
wantStderr: red("Error: invalid metric 'invalid'. Must be one of: avgphred, maxee, meep, lqcount, lqpercent"),
928+
},
929+
{
930+
name: "Invalid compression level",
931+
args: []string{"--in", "input.fq", "--out", "output.fq", "--compress", "23"},
932+
expectedCode: 1,
933+
checkStderr: true,
934+
wantStderr: red("Error: compression level must be between 0 and 22") + "\n",
935+
},
936+
{
937+
name: "Invalid header metrics",
938+
args: []string{"--in", "input.fq", "--out", "output.fq", "--header", "invalid,metrics"},
939+
expectedCode: 1,
940+
checkStderr: true,
941+
wantStderr: red("Error: invalid header metric: invalid") + "\n",
942+
},
943+
{
944+
name: "Basic file processing",
945+
args: []string{"--in", "input.fq", "--out", "output.fq"},
946+
expectedCode: 0,
947+
setupFiles: true,
948+
validateFiles: true,
949+
},
950+
{
951+
name: "Complex command with multiple options",
952+
args: []string{
953+
"--in", "input.fq",
954+
"--out", "output.fq",
955+
"--metric", "avgphred",
956+
"--minphred", "20",
957+
"--minqual", "15",
958+
"--maxqual", "40",
959+
"--header", "avgphred,maxee,length",
960+
"--ascending",
961+
"--compress", "1",
962+
},
963+
expectedCode: 0,
964+
setupFiles: true,
965+
validateFiles: true,
966+
},
967+
}
968+
969+
for _, tt := range tests {
970+
t.Run(tt.name, func(t *testing.T) {
971+
if tt.setupFiles {
972+
inFile := createTestFastq("input.fq")
973+
outFile := filepath.Join(tmpDir, "output.fq")
974+
975+
// Update args with actual file paths
976+
for i, arg := range tt.args {
977+
switch arg {
978+
case "input.fq":
979+
tt.args[i] = inFile
980+
case "output.fq":
981+
tt.args[i] = outFile
982+
}
983+
}
984+
}
985+
986+
// Reset os.Args and set test arguments
987+
oldArgs := os.Args
988+
os.Args = append([]string{"phredsort"}, tt.args...)
989+
990+
// Capture exit code
991+
var exitCode int
992+
oldExit := exitFunc
993+
exitFunc = func(code int) {
994+
exitCode = code
995+
panic(fmt.Sprintf("exit %d", code))
996+
}
997+
defer func() {
998+
exitFunc = oldExit
999+
os.Args = oldArgs
1000+
1001+
if r := recover(); r != nil {
1002+
if exitStr, ok := r.(string); !ok || !strings.HasPrefix(exitStr, "exit ") {
1003+
t.Errorf("Unexpected panic: %v", r)
1004+
}
1005+
}
1006+
}()
1007+
1008+
// Run main and capture output
1009+
stdout, stderr := captureOutput(func() {
1010+
defer func() {
1011+
if r := recover(); r != nil {
1012+
if exitStr, ok := r.(string); !ok || !strings.HasPrefix(exitStr, "exit ") {
1013+
panic(r)
1014+
}
1015+
}
1016+
}()
1017+
main()
1018+
})
1019+
1020+
// Check exit code
1021+
if exitCode != tt.expectedCode {
1022+
t.Errorf("Expected exit code %d, got %d", tt.expectedCode, exitCode)
1023+
}
1024+
1025+
// Check stdout if required
1026+
if tt.checkStdout && stdout != tt.wantStdout {
1027+
t.Errorf("Expected stdout:\n%s\nGot:\n%s", tt.wantStdout, stdout)
1028+
}
1029+
1030+
// Check stderr if required (including non-printable characters)
1031+
if tt.checkStderr && stderr != tt.wantStderr {
1032+
t.Errorf("Expected stderr:\n%q\nGot:\n%q", tt.wantStderr, stderr)
1033+
}
1034+
1035+
// Validate output file if required
1036+
if tt.validateFiles {
1037+
outPath := filepath.Join(tmpDir, "output.fq")
1038+
if _, err := os.Stat(outPath); os.IsNotExist(err) {
1039+
t.Error("Expected output file was not created")
1040+
}
1041+
1042+
// Optional: Add more specific file content validation here
1043+
// For example, check if the file is valid FASTQ format
1044+
reader, err := fastx.NewReader(seq.DNAredundant, outPath, fastx.DefaultIDRegexp)
1045+
if err != nil {
1046+
t.Errorf("Failed to read output file: %v", err)
1047+
}
1048+
defer reader.Close()
1049+
1050+
// Try to read at least one record
1051+
_, err = reader.Read()
1052+
if err != nil && err != io.EOF {
1053+
t.Errorf("Failed to read record from output file: %v", err)
1054+
}
1055+
}
1056+
})
1057+
}
1058+
}
1059+
1060+
func TestMain(m *testing.M) {
1061+
// Store original exit function
1062+
originalExit := exitFunc
1063+
// Replace exit function with mock during tests
1064+
exitFunc = func(code int) {
1065+
panic(fmt.Sprintf("exit %d", code))
1066+
}
1067+
defer func() { exitFunc = originalExit }()
1068+
1069+
m.Run()
1070+
}

0 commit comments

Comments
 (0)