code-intelligence.com/cifuzz@v0.40.0/internal/cmd/run/reporthandler/reporthandler_test.go (about) 1 package reporthandler 2 3 import ( 4 "bytes" 5 "io" 6 "os" 7 "testing" 8 "time" 9 10 "github.com/gookit/color" 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 14 "code-intelligence.com/cifuzz/internal/cmd/run/reporthandler/metrics" 15 "code-intelligence.com/cifuzz/internal/testutil" 16 "code-intelligence.com/cifuzz/pkg/finding" 17 "code-intelligence.com/cifuzz/pkg/log" 18 "code-intelligence.com/cifuzz/pkg/report" 19 ) 20 21 var ( 22 logOutput io.ReadWriter 23 testDir string 24 ) 25 26 func TestMain(m *testing.M) { 27 // Disable color for this test to allow comparing strings without 28 // having to add color to them 29 color.Disable() 30 31 logOutput = bytes.NewBuffer([]byte{}) 32 log.Output = logOutput 33 34 var cleanup func() 35 testDir, cleanup = testutil.ChdirToTempDir("report-handler-test-") 36 defer cleanup() 37 38 m.Run() 39 } 40 41 func TestReportHandler_EmptyCorpus(t *testing.T) { 42 h, err := NewReportHandler("", &ReportHandlerOptions{ProjectDir: testDir}) 43 require.NoError(t, err) 44 45 initStartedReport := &report.Report{ 46 Status: report.RunStatusInitializing, 47 NumSeeds: 0, 48 } 49 err = h.Handle(initStartedReport) 50 require.NoError(t, err) 51 checkOutput(t, logOutput, "Starting from an empty corpus") 52 require.True(t, h.initFinished) 53 } 54 55 func TestReportHandler_NonEmptyCorpus(t *testing.T) { 56 h, err := NewReportHandler("", &ReportHandlerOptions{ProjectDir: testDir}) 57 require.NoError(t, err) 58 59 initStartedReport := &report.Report{ 60 Status: report.RunStatusInitializing, 61 NumSeeds: 1, 62 } 63 err = h.Handle(initStartedReport) 64 require.NoError(t, err) 65 checkOutput(t, logOutput, "Initializing fuzzer with") 66 67 initFinishedReport := &report.Report{Status: report.RunStatusRunning} 68 err = h.Handle(initFinishedReport) 69 require.NoError(t, err) 70 checkOutput(t, logOutput, "Successfully initialized fuzzer") 71 } 72 73 func TestReportHandler_Metrics(t *testing.T) { 74 h, err := NewReportHandler("", &ReportHandlerOptions{ProjectDir: testDir}) 75 require.NoError(t, err) 76 77 printerOut := bytes.NewBuffer([]byte{}) 78 h.printer.(*metrics.LinePrinter).BasicTextPrinter.Writer = printerOut 79 80 metricsReport := &report.Report{ 81 Status: report.RunStatusRunning, 82 Metric: &report.FuzzingMetric{ 83 Timestamp: time.Now(), 84 ExecutionsPerSecond: 1234, 85 Features: 12, 86 }, 87 } 88 err = h.Handle(metricsReport) 89 require.NoError(t, err) 90 checkOutput(t, printerOut, metrics.MetricsToString(metricsReport.Metric)) 91 } 92 93 func TestReportHandler_Finding(t *testing.T) { 94 h, err := NewReportHandler("", &ReportHandlerOptions{ProjectDir: testDir, ManagedSeedCorpusDir: "seed_corpus"}) 95 require.NoError(t, err) 96 97 // create an input file 98 testfile := "crash_123_test" 99 err = os.WriteFile(testfile, []byte("TEST"), 0o644) 100 require.NoError(t, err) 101 102 findingReport := &report.Report{ 103 Status: report.RunStatusRunning, 104 Finding: &finding.Finding{ 105 InputFile: testfile, 106 }, 107 } 108 err = h.Handle(findingReport) 109 require.NoError(t, err) 110 111 expectedOutputs := []string{findingReport.Finding.Name} 112 checkOutput(t, logOutput, expectedOutputs...) 113 } 114 115 func TestReportHandler_CorpusDirs(t *testing.T) { 116 h, err := NewReportHandler("", &ReportHandlerOptions{}) 117 require.NoError(t, err) 118 119 seedCorpusDir := "/seed/corpus/dir" 120 seedCorpusReport := &report.Report{ 121 SeedCorpus: seedCorpusDir, 122 } 123 generatedCorpusDir := "/generated/corpus/dir" 124 generatedCorpusReport := &report.Report{ 125 GeneratedCorpus: generatedCorpusDir, 126 } 127 128 err = h.Handle(seedCorpusReport) 129 require.NoError(t, err) 130 assert.Equal(t, seedCorpusDir, h.ManagedSeedCorpusDir) 131 132 err = h.Handle(generatedCorpusReport) 133 require.NoError(t, err) 134 assert.Equal(t, generatedCorpusDir, h.GeneratedCorpusDir) 135 } 136 137 func TestReportHandler_PrintJSON(t *testing.T) { 138 h, err := NewReportHandler("", &ReportHandlerOptions{ProjectDir: testDir, PrintJSON: true}) 139 require.NoError(t, err) 140 141 jsonOut := bytes.NewBuffer([]byte{}) 142 h.jsonOutput = jsonOut 143 144 findingLogs := []string{"Oops", "The program crashed"} 145 findingReport := &report.Report{ 146 Status: report.RunStatusRunning, 147 Finding: &finding.Finding{ 148 Logs: findingLogs, 149 }, 150 } 151 err = h.Handle(findingReport) 152 require.NoError(t, err) 153 checkOutput(t, jsonOut, findingLogs...) 154 } 155 156 func TestReportHandler_GenerateName(t *testing.T) { 157 h, err := NewReportHandler("", &ReportHandlerOptions{ProjectDir: testDir, PrintJSON: true}) 158 require.NoError(t, err) 159 160 findingLogs := []string{"Oops", "The program crashed"} 161 findingReport := &report.Report{ 162 Status: report.RunStatusRunning, 163 Finding: &finding.Finding{ 164 Logs: findingLogs, 165 InputData: []byte("123"), 166 }, 167 } 168 err = h.Handle(findingReport) 169 require.NoError(t, err) 170 assert.Equal(t, "adoring_orangutan", findingReport.Finding.Name) 171 } 172 173 func checkOutput(t *testing.T, r io.Reader, s ...string) { 174 output, err := io.ReadAll(r) 175 require.NoError(t, err) 176 for _, str := range s { 177 require.Contains(t, string(output), str) 178 } 179 }