Skip to content

Commit 4ec5b35

Browse files
committed
upd tests (for stdin sorting)
1 parent b1f29ea commit 4ec5b35

File tree

1 file changed

+148
-0
lines changed

1 file changed

+148
-0
lines changed

phredsort_test.go

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,154 @@ func TestSortStdin(t *testing.T) {
848848
}
849849
}
850850

851+
// TestRunDefaultCommand_Stdin verifies that runDefaultCommand calls sortStdin
852+
// when the input is set to "-" (stdin) and that sorting succeeds
853+
func TestRunDefaultCommand_Stdin(t *testing.T) {
854+
// Prepare temporary stdin FASTQ file
855+
tmpInFile, err := os.CreateTemp("", "default_cmd_stdin_*.fastq")
856+
if err != nil {
857+
t.Fatal(err)
858+
}
859+
defer os.Remove(tmpInFile.Name())
860+
861+
// Two simple records with different qualities so we can verify ordering
862+
fmt.Fprintf(tmpInFile, "@seq1\nACGT\n+\nIIII\n") // high quality
863+
fmt.Fprintf(tmpInFile, "@seq2\nACGT\n+\n$$$$\n") // low quality
864+
tmpInFile.Close()
865+
866+
// Redirect stdin to the temp file
867+
oldStdin := os.Stdin
868+
newStdin, err := os.Open(tmpInFile.Name())
869+
if err != nil {
870+
t.Fatal(err)
871+
}
872+
os.Stdin = newStdin
873+
defer func() {
874+
os.Stdin = oldStdin
875+
newStdin.Close()
876+
}()
877+
878+
// Prepare temporary output file
879+
tmpOutFile, err := os.CreateTemp("", "default_cmd_stdout_*.fastq")
880+
if err != nil {
881+
t.Fatal(err)
882+
}
883+
tmpOutFile.Close()
884+
defer os.Remove(tmpOutFile.Name())
885+
886+
// Set global flags used by runDefaultCommand
887+
inFile = "-"
888+
outFile = tmpOutFile.Name()
889+
metric = "avgphred"
890+
minPhred = DEFAULT_MIN_PHRED
891+
minQualFilter = -math.MaxFloat64
892+
maxQualFilter = math.MaxFloat64
893+
headerMetrics = ""
894+
ascending = false
895+
compLevel = 0
896+
version = false
897+
898+
// Call runDefaultCommand; on success it should not call exitFunc.
899+
// exitFunc is already mocked to panic in TestMain, but since we
900+
// expect no error, we can call directly without a recover wrapper
901+
runDefaultCommand(nil, nil)
902+
903+
// Verify output order (seq1 should come before seq2)
904+
reader, err := fastx.NewReader(seq.DNAredundant, tmpOutFile.Name(), fastx.DefaultIDRegexp)
905+
if err != nil {
906+
t.Fatal(err)
907+
}
908+
defer reader.Close()
909+
910+
var gotOrder []string
911+
for {
912+
record, err := reader.Read()
913+
if err == io.EOF {
914+
break
915+
}
916+
if err != nil {
917+
t.Fatal(err)
918+
}
919+
name := strings.Split(string(record.Name), " ")[0]
920+
gotOrder = append(gotOrder, name)
921+
}
922+
923+
wantOrder := []string{"seq1", "seq2"}
924+
if !reflect.DeepEqual(gotOrder, wantOrder) {
925+
t.Errorf("runDefaultCommand(stdin) produced order %v, want %v", gotOrder, wantOrder)
926+
}
927+
}
928+
929+
// TestSortStdin_ReadError covers the error path when reading from stdin fails
930+
// inside sortStdin (i.e. the "Error reading record" branch)
931+
func TestSortStdin_ReadError(t *testing.T) {
932+
// Capture stderr and recover from the expected panic triggered via exitFunc
933+
oldStderr := os.Stderr
934+
rErr, wErr, _ := os.Pipe()
935+
os.Stderr = wErr
936+
937+
defer func() {
938+
wErr.Close()
939+
os.Stderr = oldStderr
940+
}()
941+
942+
// Prepare a valid output path (we are testing read errors, not write errors)
943+
tmpDir, err := os.MkdirTemp("", "sortstdin_readerr_*")
944+
if err != nil {
945+
t.Fatal(err)
946+
}
947+
defer os.RemoveAll(tmpDir)
948+
outPath := filepath.Join(tmpDir, "out.fastq")
949+
950+
// Redirect stdin to a malformed FASTQ file to trigger a read error
951+
tmpInFile, err := os.CreateTemp("", "sortstdin_err_in_*.fastq")
952+
if err != nil {
953+
t.Fatal(err)
954+
}
955+
// Write clearly invalid FASTQ content (not following 4-line record structure)
956+
fmt.Fprintln(tmpInFile, "this_is_not_a_valid_fastq_record")
957+
tmpInFile.Close()
958+
defer os.Remove(tmpInFile.Name())
959+
960+
oldStdin := os.Stdin
961+
newStdin, err := os.Open(tmpInFile.Name())
962+
if err != nil {
963+
t.Fatal(err)
964+
}
965+
os.Stdin = newStdin
966+
defer func() {
967+
os.Stdin = oldStdin
968+
newStdin.Close()
969+
}()
970+
971+
// Call sortStdin and expect it to call exitFunc(1), which panics
972+
didPanic := false
973+
func() {
974+
defer func() {
975+
if r := recover(); r != nil {
976+
// exitFunc is configured to panic with "exit <code>"
977+
if s, ok := r.(string); ok && strings.HasPrefix(s, "exit ") {
978+
didPanic = true
979+
} else {
980+
t.Fatalf("Unexpected panic: %v", r)
981+
}
982+
}
983+
}()
984+
985+
sortStdin(outPath, false, AvgPhred, 0, nil, DEFAULT_MIN_PHRED, -math.MaxFloat64, math.MaxFloat64)
986+
}()
987+
988+
// Read captured stderr
989+
wErr.Close()
990+
errOutput, _ := io.ReadAll(rErr)
991+
992+
if !didPanic {
993+
t.Fatalf("Expected sortStdin to call exitFunc and panic, but it did not")
994+
}
995+
if !strings.Contains(string(errOutput), "Error reading record") {
996+
t.Errorf("Expected stderr to contain 'Error reading record', got: %s", string(errOutput))
997+
}
998+
}
851999
// TestMainCommand tests the main command functionality
8521000
func TestMainCommand(t *testing.T) {
8531001
// Create temporary directory for test files

0 commit comments

Comments
 (0)