blob: 100d9f71afb5fbae6c74b4404d7e4dff621eb3fe [file] [log] [blame]
banksean07b74002025-06-26 16:05:25 +00001package codereview
2
3import (
4 "testing"
5 "time"
6)
7
8// TestCompareTestResults_NilPointerPanic tests the fix for the nil pointer panic
9// that occurred when comparing test results between commits where a package
10// exists in the after state but not in the before state.
11func TestCompareTestResults_NilPointerPanic(t *testing.T) {
12 // Create a CodeReviewer instance (minimal setup)
13 reviewer := &CodeReviewer{
14 sketchBaseRef: "main",
15 }
16
17 // Create test results where:
18 // - before: empty (no packages)
19 // - after: has a package with tests
20 beforeResults := []testJSON{} // Empty - no packages existed before
21
22 afterResults := []testJSON{
23 {
24 Time: time.Now(),
25 Package: "sketch.dev/newpkg",
26 Action: "run",
27 Test: "TestNewFunction",
28 },
29 {
30 Time: time.Now(),
31 Package: "sketch.dev/newpkg",
32 Action: "pass",
33 Test: "TestNewFunction",
34 Elapsed: 0.001,
35 },
36 {
37 Time: time.Now(),
38 Package: "sketch.dev/newpkg",
39 Action: "pass",
40 Test: "", // package-level pass
41 Elapsed: 0.001,
42 },
43 }
44
45 // This should not panic - before the fix, this would cause a nil pointer dereference
46 // when trying to access beforeResult.TestStatus[test] where beforeResult is nil
47 regressions, err := reviewer.compareTestResults(beforeResults, afterResults)
48 if err != nil {
49 t.Fatalf("compareTestResults failed: %v", err)
50 }
51
52 // We expect no regressions since the new test is passing
53 if len(regressions) != 0 {
54 t.Errorf("Expected no regressions for passing new test, got %d", len(regressions))
55 }
56}
57
58// TestCompareTestResults_NilPointerPanic_FailingTest tests the same scenario
59// but with a failing test to ensure we properly detect regressions
60func TestCompareTestResults_NilPointerPanic_FailingTest(t *testing.T) {
61 reviewer := &CodeReviewer{
62 sketchBaseRef: "main",
63 }
64
65 beforeResults := []testJSON{} // Empty - no packages existed before
66
67 afterResults := []testJSON{
68 {
69 Time: time.Now(),
70 Package: "sketch.dev/newpkg",
71 Action: "run",
72 Test: "TestNewFunction",
73 },
74 {
75 Time: time.Now(),
76 Package: "sketch.dev/newpkg",
77 Action: "fail",
78 Test: "TestNewFunction",
79 Elapsed: 0.001,
80 },
81 {
82 Time: time.Now(),
83 Package: "sketch.dev/newpkg",
84 Action: "fail",
85 Test: "", // package-level fail
86 Elapsed: 0.001,
87 },
88 }
89
90 // This should not panic and should detect the regression
91 regressions, err := reviewer.compareTestResults(beforeResults, afterResults)
92 if err != nil {
93 t.Fatalf("compareTestResults failed: %v", err)
94 }
95
96 // We expect 1 regression for the failing new test
97 if len(regressions) != 1 {
98 t.Errorf("Expected 1 regression for failing new test, got %d", len(regressions))
99 }
100
101 if len(regressions) > 0 {
102 regression := regressions[0]
103 if regression.Package != "sketch.dev/newpkg" {
104 t.Errorf("Expected package 'sketch.dev/newpkg', got %q", regression.Package)
105 }
106 if regression.Test != "TestNewFunction" {
107 t.Errorf("Expected test 'TestNewFunction', got %q", regression.Test)
108 }
109 if regression.BeforeStatus != testStatusUnknown {
110 t.Errorf("Expected before status testStatusUnknown, got %v", regression.BeforeStatus)
111 }
112 if regression.AfterStatus != testStatusFail {
113 t.Errorf("Expected after status testStatusFail, got %v", regression.AfterStatus)
114 }
115 }
116}
117
118// TestCompareTestResults_ExistingPackage tests the normal case where
119// a package exists in both before and after states
120func TestCompareTestResults_ExistingPackage(t *testing.T) {
121 reviewer := &CodeReviewer{
122 sketchBaseRef: "main",
123 }
124
125 // Package exists in both before and after
126 beforeResults := []testJSON{
127 {
128 Time: time.Now(),
129 Package: "sketch.dev/existing",
130 Action: "pass",
131 Test: "TestExisting",
132 Elapsed: 0.001,
133 },
134 {
135 Time: time.Now(),
136 Package: "sketch.dev/existing",
137 Action: "pass",
138 Test: "",
139 Elapsed: 0.001,
140 },
141 }
142
143 afterResults := []testJSON{
144 {
145 Time: time.Now(),
146 Package: "sketch.dev/existing",
147 Action: "fail",
148 Test: "TestExisting",
149 Elapsed: 0.001,
150 },
151 {
152 Time: time.Now(),
153 Package: "sketch.dev/existing",
154 Action: "fail",
155 Test: "",
156 Elapsed: 0.001,
157 },
158 }
159
160 // This should detect the regression from pass to fail
161 regressions, err := reviewer.compareTestResults(beforeResults, afterResults)
162 if err != nil {
163 t.Fatalf("compareTestResults failed: %v", err)
164 }
165
166 // We expect 1 regression
167 if len(regressions) != 1 {
168 t.Errorf("Expected 1 regression, got %d", len(regressions))
169 }
170
171 if len(regressions) > 0 {
172 regression := regressions[0]
173 if regression.BeforeStatus != testStatusPass {
174 t.Errorf("Expected before status testStatusPass, got %v", regression.BeforeStatus)
175 }
176 if regression.AfterStatus != testStatusFail {
177 t.Errorf("Expected after status testStatusFail, got %v", regression.AfterStatus)
178 }
179 }
180}
Josh Bleecher Snyder26b6f9b2025-07-01 01:41:11 +0000181
182// TestHashChangedFiles tests the hash function for changed files
183func TestHashChangedFiles(t *testing.T) {
184 reviewer := &CodeReviewer{
185 repoRoot: "/app",
186 processedChangedFileSets: make(map[string]bool),
187 reportedRelatedFiles: make(map[string]bool),
188 }
189
190 // Test that same files in different order produce same hash
191 files1 := []string{"/app/a.go", "/app/b.go"}
192 files2 := []string{"/app/b.go", "/app/a.go"}
193
194 hash1 := reviewer.hashChangedFiles(files1)
195 hash2 := reviewer.hashChangedFiles(files2)
196
197 if hash1 != hash2 {
198 t.Errorf("Expected same hash for same files in different order, got %q vs %q", hash1, hash2)
199 }
200
201 // Test that different files produce different hash
202 files3 := []string{"/app/a.go", "/app/c.go"}
203 hash3 := reviewer.hashChangedFiles(files3)
204
205 if hash1 == hash3 {
206 t.Errorf("Expected different hash for different files, got same hash %q", hash1)
207 }
208
209 // Test single file
210 files4 := []string{"/app/a.go"}
211 hash4 := reviewer.hashChangedFiles(files4)
212
213 if hash1 == hash4 {
214 t.Errorf("Expected different hash for different number of files, got same hash %q", hash1)
215 }
216}