|
1
|
|
package org.egothor.methodatlas.ai; |
|
2
|
|
|
|
3
|
|
import java.util.HashMap; |
|
4
|
|
import java.util.Map; |
|
5
|
|
import java.util.Objects; |
|
6
|
|
import java.util.Optional; |
|
7
|
|
|
|
8
|
|
/** |
|
9
|
|
* Immutable lookup structure providing efficient access to AI-generated method |
|
10
|
|
* suggestions by method name. |
|
11
|
|
* |
|
12
|
|
* <p> |
|
13
|
|
* This class acts as an adapter between the class-level suggestion model |
|
14
|
|
* returned by the AI subsystem ({@link AiClassSuggestion}) and the per-method |
|
15
|
|
* processing logic used by {@code MethodAtlasApp}. It converts the list of |
|
16
|
|
* {@link AiMethodSuggestion} objects into a name-indexed lookup map so that |
|
17
|
|
* suggestions can be retrieved in constant time during traversal of parsed test |
|
18
|
|
* methods. |
|
19
|
|
* </p> |
|
20
|
|
* |
|
21
|
|
* <h2>Design Characteristics</h2> |
|
22
|
|
* |
|
23
|
|
* <ul> |
|
24
|
|
* <li>immutable after construction</li> |
|
25
|
|
* <li>null-safe for missing or malformed AI responses</li> |
|
26
|
|
* <li>optimized for repeated method-level lookups</li> |
|
27
|
|
* </ul> |
|
28
|
|
* |
|
29
|
|
* <p> |
|
30
|
|
* If the AI response contains duplicate suggestions for the same method, only |
|
31
|
|
* the first occurrence is retained. |
|
32
|
|
* </p> |
|
33
|
|
* |
|
34
|
|
* @see AiClassSuggestion |
|
35
|
|
* @see AiMethodSuggestion |
|
36
|
|
*/ |
|
37
|
|
public final class SuggestionLookup { |
|
38
|
|
|
|
39
|
|
private final Map<String, AiMethodSuggestion> byMethodName; |
|
40
|
|
|
|
41
|
|
/** |
|
42
|
|
* Creates a new immutable lookup instance backed by the supplied map. |
|
43
|
|
* |
|
44
|
|
* <p> |
|
45
|
|
* The internal map is defensively copied to guarantee immutability of the |
|
46
|
|
* lookup structure. |
|
47
|
|
* </p> |
|
48
|
|
* |
|
49
|
|
* @param byMethodName mapping from method names to AI suggestions |
|
50
|
|
*/ |
|
51
|
|
private SuggestionLookup(Map<String, AiMethodSuggestion> byMethodName) { |
|
52
|
|
this.byMethodName = Map.copyOf(byMethodName); |
|
53
|
|
} |
|
54
|
|
|
|
55
|
|
/** |
|
56
|
|
* Creates a lookup instance from a class-level AI suggestion result. |
|
57
|
|
* |
|
58
|
|
* <p> |
|
59
|
|
* The method extracts all method suggestions contained in the supplied |
|
60
|
|
* {@link AiClassSuggestion} and indexes them by method name. Entries with |
|
61
|
|
* {@code null} suggestions, missing method names, or blank method names are |
|
62
|
|
* ignored. |
|
63
|
|
* </p> |
|
64
|
|
* |
|
65
|
|
* <p> |
|
66
|
|
* If the suggestion contains no method entries, an empty lookup instance is |
|
67
|
|
* returned. |
|
68
|
|
* </p> |
|
69
|
|
* |
|
70
|
|
* @param suggestion AI classification result for a test class |
|
71
|
|
* @return lookup structure providing fast access to method suggestions |
|
72
|
|
*/ |
|
73
|
|
public static SuggestionLookup from(AiClassSuggestion suggestion) { |
|
74
|
6
1. from : removed conditional - replaced equality check with false → SURVIVED
2. from : removed conditional - replaced equality check with true → KILLED
3. from : removed conditional - replaced equality check with false → KILLED
4. from : removed conditional - replaced equality check with true → KILLED
5. from : removed conditional - replaced equality check with true → KILLED
6. from : removed conditional - replaced equality check with false → KILLED
|
if (suggestion == null || suggestion.methods() == null || suggestion.methods().isEmpty()) { |
|
75
|
1
1. from : replaced return value with null for org/egothor/methodatlas/ai/SuggestionLookup::from → KILLED
|
return new SuggestionLookup(Map.of()); |
|
76
|
|
} |
|
77
|
|
|
|
78
|
|
Map<String, AiMethodSuggestion> map = new HashMap<>(); |
|
79
|
|
for (AiMethodSuggestion methodSuggestion : suggestion.methods()) { |
|
80
|
2
1. from : removed conditional - replaced equality check with false → KILLED
2. from : removed conditional - replaced equality check with true → KILLED
|
if (methodSuggestion == null) { |
|
81
|
|
continue; |
|
82
|
|
} |
|
83
|
4
1. from : removed conditional - replaced equality check with false → SURVIVED
2. from : removed conditional - replaced equality check with true → KILLED
3. from : removed conditional - replaced equality check with false → KILLED
4. from : removed conditional - replaced equality check with true → KILLED
|
if (methodSuggestion.methodName() == null || methodSuggestion.methodName().isBlank()) { |
|
84
|
|
continue; |
|
85
|
|
} |
|
86
|
|
map.putIfAbsent(methodSuggestion.methodName(), methodSuggestion); |
|
87
|
|
} |
|
88
|
|
|
|
89
|
1
1. from : replaced return value with null for org/egothor/methodatlas/ai/SuggestionLookup::from → KILLED
|
return new SuggestionLookup(map); |
|
90
|
|
} |
|
91
|
|
|
|
92
|
|
/** |
|
93
|
|
* Retrieves the AI suggestion for the specified method name. |
|
94
|
|
* |
|
95
|
|
* <p> |
|
96
|
|
* If no suggestion exists for the method, an empty {@link Optional} is |
|
97
|
|
* returned. |
|
98
|
|
* </p> |
|
99
|
|
* |
|
100
|
|
* @param methodName name of the method being queried |
|
101
|
|
* @return optional containing the suggestion if present |
|
102
|
|
* |
|
103
|
|
* @throws NullPointerException if {@code methodName} is {@code null} |
|
104
|
|
*/ |
|
105
|
|
public Optional<AiMethodSuggestion> find(String methodName) { |
|
106
|
|
Objects.requireNonNull(methodName, "methodName"); |
|
107
|
1
1. find : replaced return value with Optional.empty for org/egothor/methodatlas/ai/SuggestionLookup::find → KILLED
|
return Optional.ofNullable(byMethodName.get(methodName)); |
|
108
|
|
} |
|
109
|
|
} |
| | Mutations |
| 74 |
|
1.1 Location : from Killed by : org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:from_nullSuggestion_returnsEmptyLookup()] removed conditional - replaced equality check with true → KILLED
2.2 Location : from Killed by : org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:find_existingMethod_returnsSuggestion()] removed conditional - replaced equality check with false → KILLED
3.3 Location : from Killed by : org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:from_nullMethods_returnsEmptyLookup()] removed conditional - replaced equality check with true → KILLED
4.4 Location : from Killed by : none removed conditional - replaced equality check with false → SURVIVED
Covering tests
Covered by tests:
- org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:from_emptyMethods_returnsEmptyLookup()]
- org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:find_nullMethodName_throwsNullPointerException()]
- org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:find_missingMethod_returnsEmptyOptional()]
- org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:find_existingMethod_returnsSuggestion()]
- org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:from_duplicateMethodNames_keepsFirstOccurrence()]
- org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:from_filtersNullBlankAndMissingMethodNames()]
- org.egothor.methodatlas.MethodAtlasAppApplyTagsTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsTest]/[method:applyTags_nonSecurityMethod_notAnnotated(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppApplyTagsTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsTest]/[method:applyTags_noImportsAddedWhenNothingAnnotated(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppManualTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppManualTest]/[method:manualConsume_emitsEmptyAiColumnsForClassesWithoutResponseFile(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppApplyTagsTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsTest]/[method:applyTags_existingAnnotationsNotDuplicated(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppApplyTagsTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsTest]/[method:applyTags_addsDisplayNameImport(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppManualTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppManualTest]/[method:manualConsume_emitsEnrichedCsvForClassesWithResponseFiles(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppApplyTagsTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsTest]/[method:applyTags_addsTagImport(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppApplyTagsTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsTest]/[method:applyTags_withAi_annotatesSecurityRelevantMethod(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppManualTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppManualTest]/[method:manualConsume_mixesEnrichedAndEmptyRowsForPartialResponses(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppApplyTagsTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsTest]/[method:applyTags_summaryCountsMatchAnnotationsAdded(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppAiTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppAiTest]/[method:aiCache_miss_engineCalledForUnknownHash(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppAiTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppAiTest]/[method:csvMode_aiEnabled_withRealisticFixtures_emitsMergedAiSuggestions(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppAiTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppAiTest]/[method:plainMode_aiFailureForOneClass_continuesScanningAndFallsBackForThatClass(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppAiTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppAiTest]/[method:aiCache_hit_engineNotCalledForUnchangedClass(java.nio.file.Path)]
5.5 Location : from Killed by : org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:find_existingMethod_returnsSuggestion()] removed conditional - replaced equality check with true → KILLED
6.6 Location : from Killed by : org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:find_existingMethod_returnsSuggestion()] removed conditional - replaced equality check with false → KILLED
|
| 75 |
|
1.1 Location : from Killed by : org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:from_nullSuggestion_returnsEmptyLookup()] replaced return value with null for org/egothor/methodatlas/ai/SuggestionLookup::from → KILLED
|
| 80 |
|
1.1 Location : from Killed by : org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:from_filtersNullBlankAndMissingMethodNames()] removed conditional - replaced equality check with false → KILLED
2.2 Location : from Killed by : org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:find_existingMethod_returnsSuggestion()] removed conditional - replaced equality check with true → KILLED
|
| 83 |
|
1.1 Location : from Killed by : org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:find_existingMethod_returnsSuggestion()] removed conditional - replaced equality check with true → KILLED
2.2 Location : from Killed by : org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:find_existingMethod_returnsSuggestion()] removed conditional - replaced equality check with false → KILLED
3.3 Location : from Killed by : none removed conditional - replaced equality check with false → SURVIVED
Covering tests
Covered by tests:
- org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:find_nullMethodName_throwsNullPointerException()]
- org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:find_missingMethod_returnsEmptyOptional()]
- org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:find_existingMethod_returnsSuggestion()]
- org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:from_duplicateMethodNames_keepsFirstOccurrence()]
- org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:from_filtersNullBlankAndMissingMethodNames()]
- org.egothor.methodatlas.MethodAtlasAppApplyTagsTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsTest]/[method:applyTags_nonSecurityMethod_notAnnotated(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppApplyTagsTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsTest]/[method:applyTags_noImportsAddedWhenNothingAnnotated(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppApplyTagsTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsTest]/[method:applyTags_existingAnnotationsNotDuplicated(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppApplyTagsTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsTest]/[method:applyTags_addsDisplayNameImport(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppManualTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppManualTest]/[method:manualConsume_emitsEnrichedCsvForClassesWithResponseFiles(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppApplyTagsTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsTest]/[method:applyTags_addsTagImport(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppApplyTagsTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsTest]/[method:applyTags_withAi_annotatesSecurityRelevantMethod(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppManualTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppManualTest]/[method:manualConsume_mixesEnrichedAndEmptyRowsForPartialResponses(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppApplyTagsTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsTest]/[method:applyTags_summaryCountsMatchAnnotationsAdded(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppAiTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppAiTest]/[method:aiCache_miss_engineCalledForUnknownHash(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppAiTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppAiTest]/[method:csvMode_aiEnabled_withRealisticFixtures_emitsMergedAiSuggestions(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppAiTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppAiTest]/[method:plainMode_aiFailureForOneClass_continuesScanningAndFallsBackForThatClass(java.nio.file.Path)]
- org.egothor.methodatlas.MethodAtlasAppAiTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppAiTest]/[method:aiCache_hit_engineNotCalledForUnchangedClass(java.nio.file.Path)]
4.4 Location : from Killed by : org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:from_filtersNullBlankAndMissingMethodNames()] removed conditional - replaced equality check with true → KILLED
|
| 89 |
|
1.1 Location : from Killed by : org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:find_missingMethod_returnsEmptyOptional()] replaced return value with null for org/egothor/methodatlas/ai/SuggestionLookup::from → KILLED
|
| 107 |
|
1.1 Location : find Killed by : org.egothor.methodatlas.ai.SuggestionLookupTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.SuggestionLookupTest]/[method:find_existingMethod_returnsSuggestion()] replaced return value with Optional.empty for org/egothor/methodatlas/ai/SuggestionLookup::find → KILLED
|