@@ -93,71 +93,77 @@ void generateSolutionPlan_withValidInput_returnsCodeGenerationResponse() throws
93
93
String renderedPrompt = "Rendered prompt for template plan" ;
94
94
String jsonResponse = "{\" solutionPlan\" :\" " + expectedPlan + "\" ,\" files\" :[]}" ;
95
95
96
- when (templates .render (eq ("/prompts/hyperion/template/1_plan.st" ), any (Map .class ))).thenReturn (renderedPrompt );
96
+ when (contextRenderer .getExistingSolutionCode (any (ProgrammingExercise .class ), any (GitService .class ))).thenReturn ("public class Solution {}" );
97
+ when (templates .renderObject (eq ("/prompts/hyperion/template/1_plan.st" ), any (Map .class ))).thenReturn (renderedPrompt );
97
98
when (chatModel .call (any (Prompt .class ))).thenReturn (createChatResponse (jsonResponse ));
98
99
99
100
CodeGenerationResponseDTO result = templateRepository .generateSolutionPlan (user , exercise , "build logs" , "repo structure" );
100
101
101
102
assertThat (result ).isNotNull ();
102
103
assertThat (result .getSolutionPlan ()).isEqualTo (expectedPlan );
103
- verify (templates ).render (eq ("/prompts/hyperion/template/1_plan.st" ), any (Map .class ));
104
+ verify (templates ).renderObject (eq ("/prompts/hyperion/template/1_plan.st" ), any (Map .class ));
104
105
verify (chatModel ).call (any (Prompt .class ));
105
106
}
106
107
107
108
@ Test
108
109
void generateSolutionPlan_includesSolutionCodeInTemplateVariables () throws Exception {
109
110
String jsonResponse = "{\" solutionPlan\" :\" test plan\" ,\" files\" :[]}" ;
110
111
111
- when (templates .render (any (String .class ), any (Map .class ))).thenReturn ("rendered" );
112
+ when (contextRenderer .getExistingSolutionCode (any (ProgrammingExercise .class ), any (GitService .class ))).thenReturn ("public class Solution {}" );
113
+ when (templates .renderObject (any (String .class ), any (Map .class ))).thenReturn ("rendered" );
112
114
when (chatModel .call (any (Prompt .class ))).thenReturn (createChatResponse (jsonResponse ));
113
115
114
116
templateRepository .generateSolutionPlan (user , exercise , "logs" , "structure" );
115
117
116
- verify (templates ).render (eq ("/prompts/hyperion/template/1_plan.st" ), any (Map .class ));
118
+ verify (templates ).renderObject (eq ("/prompts/hyperion/template/1_plan.st" ), any (Map .class ));
117
119
verify (chatModel ).call (any (Prompt .class ));
118
120
}
119
121
120
122
@ Test
121
123
void generateSolutionPlan_withFailedRepositoryCheckout_usesWarningMessage () throws Exception {
122
124
String jsonResponse = "{\" solutionPlan\" :\" test plan\" ,\" files\" :[]}" ;
123
- when (templates .render (any (String .class ), any (Map .class ))).thenReturn ("rendered" );
125
+ when (contextRenderer .getExistingSolutionCode (any (ProgrammingExercise .class ), any (GitService .class ))).thenReturn ("public class Solution {}" );
126
+ when (templates .renderObject (any (String .class ), any (Map .class ))).thenReturn ("rendered" );
124
127
when (chatModel .call (any (Prompt .class ))).thenReturn (createChatResponse (jsonResponse ));
125
128
126
129
templateRepository .generateSolutionPlan (user , exercise , "logs" , "structure" );
127
130
128
- verify (templates ).render (eq ("/prompts/hyperion/template/1_plan.st" ), any (Map .class ));
131
+ verify (templates ).renderObject (eq ("/prompts/hyperion/template/1_plan.st" ), any (Map .class ));
129
132
verify (chatModel ).call (any (Prompt .class ));
130
133
}
131
134
132
135
@ Test
133
136
void generateSolutionPlan_withMultipleJavaFiles_concatenatesContent () throws Exception {
134
137
String jsonResponse = "{\" solutionPlan\" :\" test plan\" ,\" files\" :[]}" ;
135
138
136
- when (templates .render (any (String .class ), any (Map .class ))).thenReturn ("rendered" );
139
+ when (contextRenderer .getExistingSolutionCode (any (ProgrammingExercise .class ), any (GitService .class ))).thenReturn ("public class Solution {}" );
140
+ when (templates .renderObject (any (String .class ), any (Map .class ))).thenReturn ("rendered" );
137
141
when (chatModel .call (any (Prompt .class ))).thenReturn (createChatResponse (jsonResponse ));
138
142
139
143
templateRepository .generateSolutionPlan (user , exercise , "logs" , "structure" );
140
144
141
- verify (templates ).render (eq ("/prompts/hyperion/template/1_plan.st" ), any (Map .class ));
145
+ verify (templates ).renderObject (eq ("/prompts/hyperion/template/1_plan.st" ), any (Map .class ));
142
146
verify (chatModel ).call (any (Prompt .class ));
143
147
}
144
148
145
149
@ Test
146
150
void generateSolutionPlan_withIOExceptionDuringWalk_returnsErrorMessage () throws Exception {
147
151
String jsonResponse = "{\" solutionPlan\" :\" test plan\" ,\" files\" :[]}" ;
148
152
149
- when (templates .render (any (String .class ), any (Map .class ))).thenReturn ("rendered" );
153
+ when (contextRenderer .getExistingSolutionCode (any (ProgrammingExercise .class ), any (GitService .class ))).thenReturn ("public class Solution {}" );
154
+ when (templates .renderObject (any (String .class ), any (Map .class ))).thenReturn ("rendered" );
150
155
when (chatModel .call (any (Prompt .class ))).thenReturn (createChatResponse (jsonResponse ));
151
156
152
157
templateRepository .generateSolutionPlan (user , exercise , "logs" , "structure" );
153
158
154
- verify (templates ).render (eq ("/prompts/hyperion/template/1_plan.st" ), any (Map .class ));
159
+ verify (templates ).renderObject (eq ("/prompts/hyperion/template/1_plan.st" ), any (Map .class ));
155
160
verify (chatModel ).call (any (Prompt .class ));
156
161
}
157
162
158
163
@ Test
159
164
void generateSolutionPlan_withRepositoryAccessException_throwsNetworkingException () throws Exception {
160
- when (templates .render (any (String .class ), any (Map .class ))).thenReturn ("rendered" );
165
+ when (contextRenderer .getExistingSolutionCode (any (ProgrammingExercise .class ), any (GitService .class ))).thenReturn ("public class Solution {}" );
166
+ when (templates .renderObject (any (String .class ), any (Map .class ))).thenReturn ("rendered" );
161
167
when (chatModel .call (any (Prompt .class ))).thenThrow (new RuntimeException ("Repository access failed" ));
162
168
163
169
assertThatThrownBy (() -> templateRepository .generateSolutionPlan (user , exercise , "logs" , "structure" )).isInstanceOf (RuntimeException .class )
@@ -168,12 +174,13 @@ void generateSolutionPlan_withRepositoryAccessException_throwsNetworkingExceptio
168
174
void generateSolutionPlan_withNoJavaFiles_returnsNoFilesMessage () throws Exception {
169
175
String jsonResponse = "{\" solutionPlan\" :\" test plan\" ,\" files\" :[]}" ;
170
176
171
- when (templates .render (any (String .class ), any (Map .class ))).thenReturn ("rendered" );
177
+ when (contextRenderer .getExistingSolutionCode (any (ProgrammingExercise .class ), any (GitService .class ))).thenReturn ("public class Solution {}" );
178
+ when (templates .renderObject (any (String .class ), any (Map .class ))).thenReturn ("rendered" );
172
179
when (chatModel .call (any (Prompt .class ))).thenReturn (createChatResponse (jsonResponse ));
173
180
174
181
templateRepository .generateSolutionPlan (user , exercise , "logs" , "structure" );
175
182
176
- verify (templates ).render (eq ("/prompts/hyperion/template/1_plan.st" ), any (Map .class ));
183
+ verify (templates ).renderObject (eq ("/prompts/hyperion/template/1_plan.st" ), any (Map .class ));
177
184
verify (chatModel ).call (any (Prompt .class ));
178
185
}
179
186
@@ -182,7 +189,7 @@ void defineFileStructure_withValidInput_returnsFileStructure() throws Exception
182
189
List <GeneratedFileDTO > expectedFiles = List .of (new GeneratedFileDTO ("Template.java" , "class Template {}" ));
183
190
String jsonResponse = "{\" solutionPlan\" :\" plan\" ,\" files\" :[{\" path\" :\" Template.java\" ,\" content\" :\" class Template {}\" }]}" ;
184
191
185
- when (templates .render (eq ("/prompts/hyperion/template/2_file_structure.st" ), any (Map .class ))).thenReturn ("rendered" );
192
+ when (templates .renderObject (eq ("/prompts/hyperion/template/2_file_structure.st" ), any (Map .class ))).thenReturn ("rendered" );
186
193
when (chatModel .call (any (Prompt .class ))).thenReturn (createChatResponse (jsonResponse ));
187
194
188
195
CodeGenerationResponseDTO result = templateRepository .defineFileStructure (user , exercise , "solution plan" , "repo structure" );
@@ -198,8 +205,8 @@ void generateClassAndMethodHeaders_callsDefineFileStructureAndUsesResult() throw
198
205
String fileStructureJson = "{\" solutionPlan\" :\" plan\" ,\" files\" :[{\" path\" :\" Template.java\" ,\" content\" :\" stub\" }]}" ;
199
206
String headersJson = "{\" solutionPlan\" :\" plan\" ,\" files\" :[{\" path\" :\" Template.java\" ,\" content\" :\" class Template { void method(); }\" }]}" ;
200
207
201
- when (templates .render (eq ("/prompts/hyperion/template/2_file_structure.st" ), any (Map .class ))).thenReturn ("rendered" );
202
- when (templates .render (eq ("/prompts/hyperion/template/3_headers.st" ), any (Map .class ))).thenReturn ("rendered" );
208
+ when (templates .renderObject (eq ("/prompts/hyperion/template/2_file_structure.st" ), any (Map .class ))).thenReturn ("rendered" );
209
+ when (templates .renderObject (eq ("/prompts/hyperion/template/3_headers.st" ), any (Map .class ))).thenReturn ("rendered" );
203
210
when (chatModel .call (any (Prompt .class ))).thenReturn (createChatResponse (fileStructureJson )).thenReturn (createChatResponse (headersJson ));
204
211
205
212
CodeGenerationResponseDTO result = templateRepository .generateClassAndMethodHeaders (user , exercise , "solution plan" , "repo structure" );
@@ -215,7 +222,7 @@ void generateCoreLogic_callsHeadersAndUsesResult() throws Exception {
215
222
String headersJson = "{\" solutionPlan\" :\" plan\" ,\" files\" :[{\" path\" :\" Template.java\" ,\" content\" :\" class Template { void method(); }\" }]}" ;
216
223
String coreLogicJson = "{\" solutionPlan\" :\" plan\" ,\" files\" :[{\" path\" :\" Template.java\" ,\" content\" :\" class Template { void method() { /* TODO */ } }\" }]}" ;
217
224
218
- when (templates .render (any (String .class ), any (Map .class ))).thenReturn ("rendered" );
225
+ when (templates .renderObject (any (String .class ), any (Map .class ))).thenReturn ("rendered" );
219
226
when (chatModel .call (any (Prompt .class ))).thenReturn (createChatResponse (fileStructureJson )).thenReturn (createChatResponse (headersJson ))
220
227
.thenReturn (createChatResponse (coreLogicJson ));
221
228
@@ -224,7 +231,7 @@ void generateCoreLogic_callsHeadersAndUsesResult() throws Exception {
224
231
assertThat (result ).isNotNull ();
225
232
assertThat (result .getFiles ().get (0 ).content ()).contains ("TODO" );
226
233
verify (chatModel , org .mockito .Mockito .times (3 )).call (any (Prompt .class ));
227
- verify (templates ).render (eq ("/prompts/hyperion/template/4_logic.st" ), any (Map .class ));
234
+ verify (templates ).renderObject (eq ("/prompts/hyperion/template/4_logic.st" ), any (Map .class ));
228
235
}
229
236
230
237
@ Test
@@ -236,7 +243,8 @@ void getRepositoryType_returnsTemplate() {
236
243
237
244
@ Test
238
245
void generateSolutionPlan_withNonTransientAiException_throwsNetworkingException () throws Exception {
239
- when (templates .render (any (String .class ), any (Map .class ))).thenReturn ("rendered" );
246
+ when (contextRenderer .getExistingSolutionCode (any (ProgrammingExercise .class ), any (GitService .class ))).thenReturn ("public class Solution {}" );
247
+ when (templates .renderObject (any (String .class ), any (Map .class ))).thenReturn ("rendered" );
240
248
when (chatModel .call (any (Prompt .class ))).thenThrow (new NonTransientAiException ("AI service error" ));
241
249
242
250
assertThatThrownBy (() -> templateRepository .generateSolutionPlan (user , exercise , "logs" , "structure" )).isInstanceOf (NetworkingException .class )
@@ -247,25 +255,27 @@ void generateSolutionPlan_withNonTransientAiException_throwsNetworkingException(
247
255
void generateSolutionPlan_withNullBuildLogs_usesEmptyString () throws Exception {
248
256
String jsonResponse = "{\" solutionPlan\" :\" test plan\" ,\" files\" :[]}" ;
249
257
250
- when (templates .render (any (String .class ), any (Map .class ))).thenReturn ("rendered" );
258
+ when (contextRenderer .getExistingSolutionCode (any (ProgrammingExercise .class ), any (GitService .class ))).thenReturn ("public class Solution {}" );
259
+ when (templates .renderObject (any (String .class ), any (Map .class ))).thenReturn ("rendered" );
251
260
when (chatModel .call (any (Prompt .class ))).thenReturn (createChatResponse (jsonResponse ));
252
261
253
262
templateRepository .generateSolutionPlan (user , exercise , null , "repo structure" );
254
263
255
- verify (templates ).render (eq ("/prompts/hyperion/template/1_plan.st" ), any (Map .class ));
264
+ verify (templates ).renderObject (eq ("/prompts/hyperion/template/1_plan.st" ), any (Map .class ));
256
265
verify (chatModel ).call (any (Prompt .class ));
257
266
}
258
267
259
268
@ Test
260
269
void generateSolutionPlan_withNullRepositoryStructure_usesEmptyString () throws Exception {
261
270
String jsonResponse = "{\" solutionPlan\" :\" test plan\" ,\" files\" :[]}" ;
262
271
263
- when (templates .render (any (String .class ), any (Map .class ))).thenReturn ("rendered" );
272
+ when (contextRenderer .getExistingSolutionCode (any (ProgrammingExercise .class ), any (GitService .class ))).thenReturn ("public class Solution {}" );
273
+ when (templates .renderObject (any (String .class ), any (Map .class ))).thenReturn ("rendered" );
264
274
when (chatModel .call (any (Prompt .class ))).thenReturn (createChatResponse (jsonResponse ));
265
275
266
276
templateRepository .generateSolutionPlan (user , exercise , "logs" , null );
267
277
268
- verify (templates ).render (eq ("/prompts/hyperion/template/1_plan.st" ), any (Map .class ));
278
+ verify (templates ).renderObject (eq ("/prompts/hyperion/template/1_plan.st" ), any (Map .class ));
269
279
verify (chatModel ).call (any (Prompt .class ));
270
280
}
271
281
0 commit comments