@@ -186,6 +186,116 @@ class SarifReportTest {
186186 assert (codeFlowPhysicalLocations[0 ].region.startColumn == 5 )
187187 }
188188
189+ @Test
190+ fun testMinimizationRemovesDuplicates () {
191+ mockUtMethodNames()
192+
193+ val mockUtExecution = Mockito .mock(UtExecution ::class .java, Mockito .RETURNS_DEEP_STUBS )
194+ Mockito .`when `(mockUtExecution.result).thenReturn(UtImplicitlyThrownException (NullPointerException (), false ))
195+
196+ val testCases = listOf (
197+ UtTestCase (mockUtMethod, listOf (mockUtExecution)),
198+ UtTestCase (mockUtMethod, listOf (mockUtExecution)) // duplicate
199+ )
200+
201+ val report = SarifReport (
202+ testCases = testCases,
203+ generatedTestsCode = " " ,
204+ sourceFindingMain
205+ ).createReport().toSarif()
206+
207+ assert (report.runs.first().results.size == 1 ) // no duplicates
208+ }
209+
210+ @Test
211+ fun testMinimizationDoesNotRemoveResultsWithDifferentRuleId () {
212+ mockUtMethodNames()
213+
214+ val mockUtExecution1 = Mockito .mock(UtExecution ::class .java, Mockito .RETURNS_DEEP_STUBS )
215+ val mockUtExecution2 = Mockito .mock(UtExecution ::class .java, Mockito .RETURNS_DEEP_STUBS )
216+
217+ // different ruleId's
218+ Mockito .`when `(mockUtExecution1.result).thenReturn(UtImplicitlyThrownException (NullPointerException (), false ))
219+ Mockito .`when `(mockUtExecution2.result).thenReturn(UtImplicitlyThrownException (ArithmeticException (), false ))
220+
221+ val testCases = listOf (
222+ UtTestCase (mockUtMethod, listOf (mockUtExecution1)),
223+ UtTestCase (mockUtMethod, listOf (mockUtExecution2)) // not a duplicate
224+ )
225+
226+ val report = SarifReport (
227+ testCases = testCases,
228+ generatedTestsCode = " " ,
229+ sourceFindingMain
230+ ).createReport().toSarif()
231+
232+ assert (report.runs.first().results.size == 2 ) // no results have been removed
233+ }
234+
235+ @Test
236+ fun testMinimizationDoesNotRemoveResultsWithDifferentLocations () {
237+ mockUtMethodNames()
238+
239+ val mockUtExecution1 = Mockito .mock(UtExecution ::class .java, Mockito .RETURNS_DEEP_STUBS )
240+ val mockUtExecution2 = Mockito .mock(UtExecution ::class .java, Mockito .RETURNS_DEEP_STUBS )
241+
242+ // the same ruleId's
243+ Mockito .`when `(mockUtExecution1.result).thenReturn(UtImplicitlyThrownException (NullPointerException (), false ))
244+ Mockito .`when `(mockUtExecution2.result).thenReturn(UtImplicitlyThrownException (NullPointerException (), false ))
245+
246+ // different locations
247+ Mockito .`when `(mockUtExecution1.path.lastOrNull()?.stmt?.javaSourceStartLineNumber).thenReturn(11 )
248+ Mockito .`when `(mockUtExecution2.path.lastOrNull()?.stmt?.javaSourceStartLineNumber).thenReturn(22 )
249+
250+ val testCases = listOf (
251+ UtTestCase (mockUtMethod, listOf (mockUtExecution1)),
252+ UtTestCase (mockUtMethod, listOf (mockUtExecution2)) // not a duplicate
253+ )
254+
255+ val report = SarifReport (
256+ testCases = testCases,
257+ generatedTestsCode = " " ,
258+ sourceFindingMain
259+ ).createReport().toSarif()
260+
261+ assert (report.runs.first().results.size == 2 ) // no results have been removed
262+ }
263+
264+ @Test
265+ fun testMinimizationChoosesShortestCodeFlow () {
266+ mockUtMethodNames()
267+
268+ val mockNPE1 = Mockito .mock(NullPointerException ::class .java)
269+ val mockNPE2 = Mockito .mock(NullPointerException ::class .java)
270+
271+ val mockUtExecution1 = Mockito .mock(UtExecution ::class .java, Mockito .RETURNS_DEEP_STUBS )
272+ val mockUtExecution2 = Mockito .mock(UtExecution ::class .java, Mockito .RETURNS_DEEP_STUBS )
273+
274+ // the same ruleId's
275+ Mockito .`when `(mockUtExecution1.result).thenReturn(UtImplicitlyThrownException (mockNPE1, false ))
276+ Mockito .`when `(mockUtExecution2.result).thenReturn(UtImplicitlyThrownException (mockNPE2, false ))
277+
278+ // but different stack traces
279+ val stackTraceElement1 = StackTraceElement (" Main" , " main" , " Main.java" , 3 )
280+ val stackTraceElement2 = StackTraceElement (" Main" , " main" , " Main.java" , 7 )
281+ Mockito .`when `(mockNPE1.stackTrace).thenReturn(arrayOf(stackTraceElement1))
282+ Mockito .`when `(mockNPE2.stackTrace).thenReturn(arrayOf(stackTraceElement1, stackTraceElement2))
283+
284+ val testCases = listOf (
285+ UtTestCase (mockUtMethod, listOf (mockUtExecution1)),
286+ UtTestCase (mockUtMethod, listOf (mockUtExecution2)) // duplicate with a longer stack trace
287+ )
288+
289+ val report = SarifReport (
290+ testCases = testCases,
291+ generatedTestsCode = " " ,
292+ sourceFindingMain
293+ ).createReport().toSarif()
294+
295+ assert (report.runs.first().results.size == 1 ) // no duplicates
296+ assert (report.runs.first().results.first().totalCodeFlowLocations() == 1 ) // with a shorter stack trace
297+ }
298+
189299 // internal
190300
191301 private val mockUtMethod = Mockito .mock(UtMethod ::class .java, Mockito .RETURNS_DEEP_STUBS )
0 commit comments