001 /**
002 * Copyright 2004-2014 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.student.mock.mojo;
017
018 import org.kuali.student.contract.model.MessageStructure;
019 import org.kuali.student.contract.model.Service;
020 import org.kuali.student.contract.model.ServiceContractModel;
021 import org.kuali.student.contract.model.ServiceMethod;
022 import org.kuali.student.contract.model.ServiceMethodError;
023 import org.kuali.student.contract.model.ServiceMethodParameter;
024 import org.kuali.student.contract.model.util.ServicesFilter;
025 import org.kuali.student.contract.writer.service.GetterSetterNameCalculator;
026 import org.slf4j.Logger;
027 import org.slf4j.LoggerFactory;
028
029 import javax.management.OperationsException;
030
031 import java.util.ArrayList;
032 import java.util.List;
033
034 /**
035 * This class will generate the base class that does CRUD tests as
036 * part of the Conformance Tests for services. The generated class will
037 * need to be extended (and abstract methods filled in) to be complete.
038 * This class is meant to be generated again and again, and developers
039 * should customize tests in the extended class by extending or overwriting
040 * methods of this class as needed.
041 *
042 * @author Mezba Mahtab (mezba.mahtab@utoronto.ca)
043 */
044 public class ConformanceTestBaseCrudClassServiceWriter extends MockImplServiceWriter {
045
046 private static final Logger log = LoggerFactory.getLogger(ConformanceTestExtendedCrudClassServiceWriter.class);
047
048 /////////////////////////
049 // CONSTANTS
050 /////////////////////////
051
052 public static final String ROOT_PACKAGE = "org.kuali.student";
053 protected static final String H1_COMMENT_CHAR = "=";
054 protected static final int H1_COMMENT_MARK_LENGTH = 20;
055
056 ////////////////////////////
057 // Data Variables
058 ////////////////////////////
059
060 private ServicesFilter filter;
061
062 List<String> dtoObjectNamesWithCrud = null; // a list of all the DTOs managed by this class that has CRUDs
063
064 protected List<String> getDtoObjectNamesWithCrud() {
065 return dtoObjectNamesWithCrud;
066 }
067
068 ////////////////////////////
069 // CONSTRUCTOR
070 ////////////////////////////
071
072 public ConformanceTestBaseCrudClassServiceWriter(ServiceContractModel model,
073 String directory,
074 String rootPackage,
075 String servKey,
076 List<ServiceMethod> methods,
077 boolean isR1) {
078 super(model, directory, rootPackage, servKey, methods, isR1, calcPackage(servKey, rootPackage), calcClassName(servKey));
079 dtoObjectNamesWithCrud = calcNamesOfDTOsWithCrudManagedByService();
080 }
081
082 public ConformanceTestBaseCrudClassServiceWriter(ServiceContractModel model,
083 String directory,
084 String rootPackage,
085 String servKey,
086 List<ServiceMethod> methods,
087 boolean isR1,
088 String packageName,
089 String className) {
090 super(model, directory, rootPackage, servKey, methods, isR1, packageName, className);
091 dtoObjectNamesWithCrud = calcNamesOfDTOsWithCrudManagedByService();
092 }
093
094 //////////////////////////
095 // FUNCTIONALS
096 //////////////////////////
097
098 public static String calcPackage(String servKey, String rootPackage) {
099 String pack = rootPackage + ".";
100 pack = pack + "service.test";
101 return pack;
102 }
103
104 /**
105 * Given the service key (name), returns a calculated class name for the conformance tester.
106 */
107 public static String calcClassName(String servKey) {
108 return "Test" + GetterSetterNameCalculator.calcInitUpper(fixServKey(servKey) + "ServiceImplConformanceBaseCrud");
109 }
110
111 public static List<Service> filterServices(ServiceContractModel model, ServicesFilter filter) {
112 if (filter == null) {
113 return model.getServices();
114 }
115 return filter.filter(model.getServices());
116 }
117
118
119 /**
120 * Write out the entire file
121 */
122 public void write() {
123 // begin file
124 indentPrintln("@RunWith(SpringJUnit4ClassRunner.class)");
125 indentPrintln("@ContextConfiguration(locations = {\"classpath:" + servKey + "-test-with-mock-context.xml\"})");
126 indentPrint("public abstract class " + calcClassName(servKey) + " ");
127 // println(" implements " + calcServiceInterfaceClassName(servKey));
128 Service serv = finder.findService(servKey);
129 setPackageName(serv.getImplProject() + ".impl"); // change the package name
130 importsAdd(serv.getImplProject() + "." + serv.getName()); // import for the service
131
132 doTestImportsAdd();
133
134 // begin main class
135 openBrace();
136
137 indentPrintln("");
138 indentPrintDecoratedComment("SETUP", H1_COMMENT_CHAR, H1_COMMENT_MARK_LENGTH);
139 indentPrintln("");
140
141 // test service setup
142 indentPrintln("@Resource");
143 indentPrintln("public " + calcServiceInterfaceClassName(servKey) + " testService;");
144 indentPrintln("public " + calcServiceInterfaceClassName(servKey) + " get" + calcServiceInterfaceClassName(servKey) + "() { return testService; }");
145 indentPrintln("public void set" + calcServiceInterfaceClassName(servKey) + "(" + calcServiceInterfaceClassName(servKey) + " service) { testService = service; }");
146 indentPrintln("");
147
148 // context info setup
149 indentPrintln("public ContextInfo contextInfo = null;");
150 indentPrintln("public static String principalId = \"123\";");
151 indentPrintln("");
152 indentPrintln("@Before");
153 indentPrintln("public void setUp()");
154 openBrace();
155 indentPrintln("principalId = \"123\";");
156 indentPrintln("contextInfo = new ContextInfo();");
157 indentPrintln("contextInfo.setPrincipalId(principalId);");
158 closeBrace();
159 indentPrintln("");
160
161 // testing starts
162 indentPrintDecoratedComment("TESTING", H1_COMMENT_CHAR, H1_COMMENT_MARK_LENGTH);
163 indentPrintln("");
164 /*
165 new ArrayList<String>();
166 for (ServiceMethod method: methods) {
167 // I am assuming all the DTOs will have a createXXX method.
168 if (MethodType.CREATE.equals (calcMethodType(method))) {
169 String objectName = calcObjectName(method);
170 dtoObjectNames.add(objectName);
171 }
172 }
173 */
174 // for each DTO, write the testCRUD
175 for (String dtoObjectName : dtoObjectNamesWithCrud) {
176 writeTestCrud(dtoObjectName);
177 indentPrintln("");
178 }
179
180 // print out list of service operations that were tested
181 indentPrintDecoratedComment("SERVICE OPS TESTED IN BASE TEST CLASS", H1_COMMENT_CHAR, H1_COMMENT_MARK_LENGTH*2);
182 indentPrintln("");
183
184 // separate out crud and non-crud methods
185 List<ServiceMethod> methodsTestedAsCrud = new ArrayList<ServiceMethod>();
186 List<ServiceMethod> methodsNotTested = new ArrayList<ServiceMethod>();
187
188 for (ServiceMethod method : methods) {
189 if (isServiceMethodTestedAsPartofCrudInBaseConformanceTest (method)) {
190 methodsTestedAsCrud.add(method);
191 } else {
192 methodsNotTested.add(method);
193 }
194 }
195
196 // print out crud methods
197 indentPrintln("/*");
198 incrementIndent();
199 indentPrintln("The following methods are tested as part of CRUD operations for this service's DTOs:");
200 incrementIndent();
201 for (ServiceMethod method: methodsTestedAsCrud) {
202 indentPrintln(method.getName());
203 }
204 decrementIndent();
205 decrementIndent();
206 indentPrintln("*/");
207 indentPrintln("");
208
209 // print out list of service operations that are not tested as abstract test methods
210 indentPrintDecoratedComment("SERVICE OPS NOT TESTED IN BASE TEST CLASS", H1_COMMENT_CHAR, H1_COMMENT_MARK_LENGTH*2);
211 indentPrintln("");
212
213 // for each method, create an abstract method to test that and print it out
214 for (ServiceMethod method: methodsNotTested) {
215 indentPrintln("/* Method Name: " + method.getName() + " */");
216 indentPrintln("@Test");
217 indentPrintln("public abstract void test_" + method.getName() + "() ");
218 if (method.getErrors().size()>0) {
219 indentPrint("throws ");
220 String comma = "";
221 for (ServiceMethodError error: method.getErrors()) {
222 indentPrint(comma + error.getClassName().trim());
223 comma = ",";
224 }
225 }
226 indentPrintln(";");
227 indentPrintln("");
228 }
229
230 // end file print out
231 closeBrace ();
232 println ("");
233
234 // close and print file
235 this.writeJavaClassAndImportsOutToFile();
236 this.getOut().close();
237 }
238
239 /**
240 * Write the CRUD test methods
241 */
242 public void writeTestCrud (String dtoObjectName) {
243
244 // get the message structures of the dto
245 List<MessageStructure> messageStructures = finder.findMessageStructures(dtoObjectName + "Info");
246
247 // start method open signature
248 indentPrintln("// ****************************************************");
249 indentPrintln("// " + dtoObjectName + "Info");
250 indentPrintln("// ****************************************************");
251 indentPrintln("@Test");
252 indentPrintln("public void testCrud" + dtoObjectName + "() ");
253 incrementIndent();
254 indentPrintln("throws DataValidationErrorException,");
255 incrementIndent();
256 indentPrintln("DoesNotExistException,");
257 indentPrintln("InvalidParameterException,");
258 indentPrintln("MissingParameterException,");
259 indentPrintln("OperationFailedException,");
260 indentPrintln("PermissionDeniedException,");
261 indentPrintln("ReadOnlyException,");
262 indentPrintln("VersionMismatchException,");
263 indentPrintln("DependentObjectsExistException");
264 decrementIndent();
265 decrementIndent();
266 openBrace();
267 // end method open signature
268
269 // write the test portions
270 incrementIndent();
271 writeTestCreate(dtoObjectName, messageStructures);
272 writeTestUpdate(dtoObjectName, messageStructures);
273 writeTestReadAfterUpdate(dtoObjectName, messageStructures);
274 writeTestDelete(dtoObjectName, messageStructures);
275 decrementIndent();
276
277 // end method
278 closeBrace();
279 indentPrintln("");
280
281 // methods that will be overwritten
282 writetestCrudXXX_setDTOFieldsForTestCreate(dtoObjectName, messageStructures);
283 writetestCrudXXX_testDTOFieldsForTestCreateUpdate(dtoObjectName, messageStructures);
284 writetestCrudXXX_setDTOFieldsForTestUpdate(dtoObjectName, messageStructures);
285 writetestCrudXXX_testDTOFieldsForTestReadAfterUpdate(dtoObjectName, messageStructures);
286 writetestCrudXXX_setDTOFieldsForTestReadAfterUpdate(dtoObjectName, messageStructures);
287 }
288
289 /**
290 * Write the 'test create' portion.
291 */
292 public void writeTestCreate (String dtoObjectName, List<MessageStructure> messageStructures) {
293 indentPrintDecoratedComment("test create");
294 indentPrintln(dtoObjectName + "Info expected = new " + dtoObjectName + "Info ();");
295 // indentPrintln("expected.setName(\"Name01\");");
296 // indentPrintln("expected.setDescr(new RichTextHelper().fromPlain(\"Description01\"));");
297 indentPrintln("");
298 indentPrintln("// METHOD TO SET DTO FIELDS HERE FOR TEST CREATE");
299 indentPrintln("testCrud" + dtoObjectName + "_setDTOFieldsForTestCreate (expected);");
300 indentPrintln("");
301
302 /*
303 indentPrintln("if (expected.getClass().isAssignableFrom(TypeStateEntityInfo.class))");
304 openBrace();
305 incrementIndent();
306 // indentPrintln("TypeStateEntityInfo expectedTS = (TypeStateEntityInfo) expected;");
307 indentPrintln("expected.setTypeKey(\"typeKey01\");");
308 indentPrintln("expected.setStateKey(\"stateKey01\");");
309 decrementIndent();
310 closeBrace();
311 */
312 indentPrintln("new AttributeTester().add2ForCreate(expected.getAttributes());");
313
314 indentPrintln("");
315 indentPrintln("// code to create actual");
316 indentPrintln(dtoObjectName + "Info actual = " + getMethodCallAsString ("create" + dtoObjectName, "= null; // TODO INSERT CODE TO CREATE actual HERE", MethodType.CREATE, dtoObjectName, "expected"));
317 indentPrintln("");
318
319 String testerName = null;
320 String keyOrId = null;
321 if (finder.findMessageStructure(dtoObjectName + "Info", "id") != null) {
322 keyOrId = "Id";
323 if (finder.findMessageStructure(dtoObjectName + "Info", "name") != null) {
324 testerName = "IdEntityTester";
325 } else if (finder.findMessageStructure(dtoObjectName + "Info", "effectiveDate") != null) {
326 testerName = "RelationshipTester";
327 } else {
328 testerName = "IdNamelessEntityTester";
329 // should also detect relationships
330 }
331 } else if (finder.findMessageStructure(dtoObjectName + "Info", "key") != null) {
332 keyOrId = "Key";
333 testerName = "KeyEntityTester";
334 }
335
336 // indentPrintln("if (actual.getClass().isAssignableFrom(IdEntityInfo.class))");
337 if (testerName !=null) {
338 // openBrace();
339 // incrementIndent();
340 indentPrintln("assertNotNull(actual.get" + keyOrId + "());");
341 indentPrintln("new " + testerName + "().check(expected, actual);");
342 // decrementIndent();
343 // closeBrace();
344 }
345
346 indentPrintln("");
347 indentPrintln("// METHOD TO TEST DTO FIELDS HERE FOR TEST CREATE");
348 indentPrintln("testCrud" + dtoObjectName + "_testDTOFieldsForTestCreateUpdate (expected, actual);");
349 indentPrintln("");
350
351 indentPrintln("new AttributeTester().check(expected.getAttributes(), actual.getAttributes());");
352 indentPrintln("new MetaTester().checkAfterCreate(actual.getMeta());");
353 indentPrintln("");
354
355 indentPrintDecoratedComment("test read");
356 indentPrintln("expected = actual;");
357 indentPrintln("actual = " + getMethodCallAsString ("get" + dtoObjectName, "null; // TODO INSERT CODE TO GET actual HERE BY CALLING SERVICE OP", MethodType.GET_BY_ID, dtoObjectName, "actual"));
358
359 if (testerName !=null) {
360 indentPrintln("assertEquals(expected.get" + keyOrId + "(), actual.get" + keyOrId + "());");
361 indentPrintln("new " + testerName + "().check(expected, actual);");
362 }
363
364 indentPrintln("");
365
366 indentPrintln("// INSERT CODE FOR TESTING MORE DTO FIELDS HERE");
367 indentPrintln("testCrud" + dtoObjectName + "_testDTOFieldsForTestCreateUpdate (expected, actual);");
368 indentPrintln("");
369
370 indentPrintln("new AttributeTester().check(expected.getAttributes(), actual.getAttributes());");
371 indentPrintln("new MetaTester().checkAfterGet(expected.getMeta(), actual.getMeta());");
372 indentPrintln("");
373 }
374
375 /**
376 * Write the 'test update' portion.
377 */
378 public void writeTestUpdate (String dtoObjectName, List<MessageStructure> messageStructures) {
379 indentPrintDecoratedComment("test update");
380 indentPrintln(dtoObjectName + "Info original = new " + dtoObjectName + "Info (actual);");
381 indentPrintln("expected = new " + dtoObjectName + "Info (actual);");
382
383 // indentPrintln("expected.setName(expected.getName() + \" updated\");");
384 // indentPrintln("expected.setDescr(new RichTextHelper().fromPlain(expected.getDescr().getPlain() + \"_Updated\"));");
385 indentPrintln("");
386 // indentPrintln("if (expected.getClass().isAssignableFrom(TypeStateEntityInfo.class))");
387 if (finder.findMessageStructure(dtoObjectName + "Info", "stateKey")!=null) {
388 // openBrace();
389 // incrementIndent();
390 // indentPrintln("TypeStateEntityInfo expectedTS = (TypeStateEntityInfo) expected;");
391 indentPrintln("expected.setStateKey(expected.getState() + \"_Updated\");");
392 // decrementIndent();
393 // closeBrace();
394 }
395 indentPrintln("");
396 indentPrintln("// METHOD TO INSERT CODE TO UPDATE DTO FIELDS HERE");
397 indentPrintln("testCrud" + dtoObjectName + "_setDTOFieldsForTestUpdate (expected);");
398 indentPrintln("");
399 indentPrintln("new AttributeTester().delete1Update1Add1ForUpdate(expected.getAttributes());");
400
401 indentPrintln("// code to update");
402 indentPrintln("actual = " + getMethodCallAsString ("update" + dtoObjectName, "= null; // TODO INSERT CODE TO CALL UPDATE SERVICE OP HERE", MethodType.UPDATE, dtoObjectName, "expected"));
403 indentPrintln("");
404
405 String testerName = null;
406 String keyOrId = null;
407 if (finder.findMessageStructure(dtoObjectName + "Info", "id") != null) {
408 keyOrId = "Id";
409 if (finder.findMessageStructure(dtoObjectName + "Info", "name") != null) {
410 testerName = "IdEntityTester";
411 } else if (finder.findMessageStructure(dtoObjectName + "Info", "effectiveDate") != null) {
412 testerName = "RelationshipTester";
413 } else {
414 testerName = "IdNamelessEntityTester";
415 }
416 } else if (finder.findMessageStructure(dtoObjectName + "Info", "key") != null) {
417 keyOrId = "Key";
418 testerName = "KeyEntityTester";
419 }
420 if (testerName !=null) {
421 indentPrintln("assertEquals(expected.get" + keyOrId + "(), actual.get" + keyOrId + "());");
422 indentPrintln("new " + testerName + "().check(expected, actual);");
423 }
424 indentPrintln("");
425 indentPrintln("// METHOD TO INSERT CODE FOR TESTING DTO FIELDS HERE");
426 indentPrintln("testCrud" + dtoObjectName + "_testDTOFieldsForTestCreateUpdate (expected, actual);");
427 indentPrintln("");
428 indentPrintln("new AttributeTester().check(expected.getAttributes(), actual.getAttributes());");
429 indentPrintln("new MetaTester().checkAfterUpdate(expected.getMeta(), actual.getMeta());");
430 indentPrintln("");
431
432 indentPrintln("// Test that VersionMissmatchException's are being detected");
433 indentPrintln("boolean exception = false;");
434 indentPrintln("try {");
435 indent(getOut(), ' ');
436
437 indentPrintln(getMethodCallAsString ("update" + dtoObjectName, "= null; // TODO INSERT CODE TO CALL UPDATE SERVICE OP HERE", MethodType.UPDATE, dtoObjectName, "original"));
438 indentPrintln("}");
439 indentPrintln("catch (VersionMismatchException e) { ");
440 indent(getOut(), ' ');
441 indentPrint("exception = true;");
442 indentPrintln("}");
443 indentPrintln("");
444
445 indentPrintln("Assert.assertTrue(\"VersionMissmatchException was not detected!\", exception);");
446 indentPrintln("");
447
448 }
449
450 /**
451 * Write the 'read after update' portion.
452 */
453 public void writeTestReadAfterUpdate (String dtoObjectName, List<MessageStructure> messageStructures) {
454 indentPrintDecoratedComment("test read after update");
455 indentPrintln("");
456 indentPrintln("expected = actual;");
457
458 String testerName = null;
459 String keyOrId = null;
460 if (finder.findMessageStructure(dtoObjectName + "Info", "id") != null) {
461 keyOrId = "Id";
462 if (finder.findMessageStructure(dtoObjectName + "Info", "name") != null) {
463 testerName = "IdEntityTester";
464 } else if (finder.findMessageStructure(dtoObjectName + "Info", "effectiveDate") != null) {
465 testerName = "RelationshipTester";
466 } else {
467 testerName = "IdNamelessEntityTester";
468 }
469 } else if (finder.findMessageStructure(dtoObjectName + "Info", "key") != null) {
470 keyOrId = "Key";
471 testerName = "KeyEntityTester";
472 }
473
474 indentPrintln("// code to get actual");
475 indentPrintln("actual = " + getMethodCallAsString ("get" + dtoObjectName, "null; // TODO INSERT CODE TO GET actual HERE BY CALLING SERVICE OP", MethodType.GET_BY_ID, dtoObjectName, "actual"));
476 indentPrintln("");
477
478
479 if (testerName !=null) {
480 indentPrintln("assertEquals(expected.get" + keyOrId + "(), actual.get" + keyOrId + "());");
481 indentPrintln("new " + testerName + "().check(expected, actual);");
482 }
483 indentPrintln("");
484 indentPrintln("// INSERT METHOD CODE FOR TESTING DTO FIELDS HERE");
485 indentPrintln("testCrud" + dtoObjectName + "_testDTOFieldsForTestReadAfterUpdate (expected, actual);");
486 indentPrintln("");
487 indentPrintln("new AttributeTester().check(expected.getAttributes(), actual.getAttributes());");
488 indentPrintln("new MetaTester().checkAfterGet(expected.getMeta(), actual.getMeta());");
489 indentPrintln("");
490 indentPrintln(dtoObjectName + "Info alphaDTO = actual;");
491 indentPrintln("");
492 indentPrintln("// create a 2nd DTO");
493 indentPrintln(dtoObjectName + "Info betaDTO = new " + dtoObjectName + "Info ();");
494 // indentPrintln("betaDTO.setName(\"Beta entity name\");");
495 // indentPrintln("betaDTO.setDescr(new RichTextHelper().fromPlain(\"Beta entity description\"));");
496 indentPrintln("");
497 indentPrintln("// METHOD TO INSERT CODE TO SET MORE DTO FIELDS HERE");
498 indentPrintln("testCrud" + dtoObjectName + "_setDTOFieldsForTestReadAfterUpdate (betaDTO);");
499 indentPrintln("");
500 // indentPrintln("if (betaDTO.getClass().isAssignableFrom(TypeStateEntityInfo.class))");
501 if (finder.findMessageStructure(dtoObjectName + "Info", "typeKey")!=null) {
502 // openBrace();
503 // incrementIndent();
504 //indentPrintln("TypeStateEntityInfo betaDTOTS = (TypeStateEntityInfo) betaDTO;");
505 indentPrintln("betaDTO.setTypeKey(\"typeKeyBeta\");");
506 // decrementIndent();
507 // closeBrace();
508 }
509 if (finder.findMessageStructure(dtoObjectName + "Info", "stateKey")!=null) {
510 indentPrintln("betaDTO.setStateKey(\"stateKeyBeta\");");
511 }
512 indentPrintln("betaDTO = " + getMethodCallAsString("create" + dtoObjectName, "null; // TODO INSERT CODE TO CREATE betaDTO", MethodType.CREATE, dtoObjectName, "betaDTO"));
513
514 indentPrintln("");
515 indentPrintDecoratedComment("test bulk get with no ids supplied");
516 indentPrintln("");
517 indentPrintln("List<String> " + initLower(dtoObjectName) + "Ids = new ArrayList<String>();");
518
519 indentPrintln("// code to get DTO by Ids");
520 indentPrintln("List<" + dtoObjectName + "Info> records = " + getMethodCallAsString ("get" + dtoObjectName + "sByIds", "null; // TODO INSERT CODE TO GET DTO BY IDS", MethodType.GET_BY_IDS, dtoObjectName));
521 indentPrintln("");
522
523 indentPrintln("assertEquals(" + initLower(dtoObjectName) + "Ids.size(), records.size());");
524 indentPrintln("assertEquals(0, " + initLower(dtoObjectName) + "Ids.size());");
525 indentPrintln("");
526 indentPrintDecoratedComment("test bulk get");
527 indentPrintln(initLower(dtoObjectName) + "Ids = new ArrayList<String>();");
528 indentPrintln(initLower(dtoObjectName) + "Ids.add(alphaDTO.getId());");
529 indentPrintln(initLower(dtoObjectName) + "Ids.add(betaDTO.getId());");
530
531 indentPrintln("// code to get DTO by Ids");
532 indentPrintln("records = " + getMethodCallAsString ("get" + dtoObjectName + "sByIds", "null; // TODO INSERT CODE TO GET DTO BY IDS", MethodType.GET_BY_IDS, dtoObjectName));
533 indentPrintln("");
534
535 indentPrintln("assertEquals(" + initLower(dtoObjectName) + "Ids.size(), records.size());");
536 indentPrintln("for (" + dtoObjectName + "Info record : records)");
537 openBrace();
538 incrementIndent();
539 indentPrintln("if (!" + initLower(dtoObjectName) + "Ids.remove(record.getId()))");
540 openBrace();
541 incrementIndent();
542 indentPrintln("fail(record.getId());");
543 decrementIndent();
544 closeBrace();
545 decrementIndent();
546 closeBrace();
547 indentPrintln("assertEquals(0, " + initLower(dtoObjectName) + "Ids.size());");
548 indentPrintln("");
549 indentPrintDecoratedComment("test get by type");
550
551 indentPrintln("// code to get by specific type \"typeKey01\" ");
552 indentPrintln(initLower(dtoObjectName) + "Ids = testService.get" + dtoObjectName + "IdsByType (\"typeKey_Updated\", contextInfo);");
553 // indentPrintln(initLower(dtoObjectName) + "Ids = " + getMethodCallAsString ("get" + dtoObjectName + "IdsByType", "// INSERT CODE TO GET BY SPECIFIC TYPE \"typeKey01\" HERE", MethodType.GET_IDS_BY_TYPE));
554 indentPrintln("");
555
556 indentPrintln("assertEquals(1, " + initLower(dtoObjectName) + "Ids.size());");
557 indentPrintln("assertEquals(alphaDTO.getId(), " + initLower(dtoObjectName) + "Ids.get(0));");
558 indentPrintln("");
559 indentPrintln("// test get by other type");
560
561 indentPrintln("// code to get by specific type \"typeKeyBeta\" ");
562 indentPrintln(initLower(dtoObjectName) + "Ids = testService.get" + dtoObjectName + "IdsByType (\"typeKeyBeta\", contextInfo);");
563 // indentPrintln(initLower(dtoObjectName) + "Ids = " + getMethodCallAsString ("get" + dtoObjectName + "IdsByType", "// INSERT CODE TO GET BY SPECIFIC TYPE \"typeKeyBeta\" HERE", MethodType.GET_IDS_BY_TYPE));
564 indentPrintln("");
565
566 indentPrintln("assertEquals(1, " + initLower(dtoObjectName) + "Ids.size());");
567 indentPrintln("assertEquals(betaDTO.getId(), " + initLower(dtoObjectName) + "Ids.get(0));");
568 indentPrintln("");
569 }
570
571 /**
572 * Write the 'delete' portion.
573 */
574 public void writeTestDelete (String dtoObjectName, List<MessageStructure> messageStructures) {
575 indentPrintDecoratedComment("test delete");
576 indentPrintln("");
577
578 indentPrintln("StatusInfo status = " + getMethodCallAsString ("delete" + dtoObjectName, "null; // TODO INSERT CODE TO DELETE RECORD", MethodType.DELETE, dtoObjectName, "actual"));
579 indentPrintln("");
580
581 indentPrintln("assertNotNull(status);");
582 indentPrintln("assertTrue(status.getIsSuccess());");
583 indentPrintln("try");
584 openBrace();
585 incrementIndent();
586 indentPrintln(dtoObjectName + "Info record = " + getMethodCallAsString ("get" + dtoObjectName, "null; // TODO INSERT CODE TO RETRIEVE RECENTLY DELETED RECORD", MethodType.GET_BY_ID, dtoObjectName, "actual"));
587 indentPrintln("fail(\"Did not receive DoesNotExistException when attempting to get already-deleted entity\");");
588 decrementIndent();
589 closeBrace();
590 indentPrintln("catch (DoesNotExistException dnee)");
591 openBrace();
592 incrementIndent();
593 indentPrintln("// expected");
594 decrementIndent();
595 closeBrace();
596 indentPrintln("");
597 }
598
599 /**
600 * Writes out a decorated comment.
601 */
602 public void indentPrintDecoratedComment (String label) {
603 indentPrintDecoratedComment(label, "-", 37);
604 /*
605 indentPrintln("// -------------------------------------");
606 indentPrintln("// " + label);
607 indentPrintln("// -------------------------------------");
608 */
609 }
610
611 /**
612 * Writes out a decorated comment, with the decoration string passed in.
613 */
614 public void indentPrintDecoratedComment (String label, String decorChar, int decorLength) {
615 String decorPattern = "";
616 for (int i=0; i<decorLength; i++) { decorPattern += decorChar; }
617 indentPrintln("// " + decorPattern);
618 indentPrintln("// " + label);
619 indentPrintln("// " + decorPattern);
620 }
621
622 /**
623 * Gets the method with the name.
624 */
625 private ServiceMethod getServiceMethod (String methodName) throws OperationsException {
626 for (ServiceMethod method : methods) {
627 if (method.getName().equals(methodName)) return method;
628 }
629 throw new OperationsException("Method " + methodName + " not found!");
630 }
631
632 /**
633 * Gets the string to print to call a method with the given name.
634 * @param dtoObjectName
635 */
636 private String getMethodCallAsString (String builtUpMethodName, String errorCode, MethodType methodType, String dtoObjectName) {
637 return getMethodCallAsString (builtUpMethodName, errorCode, methodType, dtoObjectName, null);
638 }
639
640 /**
641 * Gets the string to print to call a method with the given name.
642 */
643 private String getMethodCallAsString (String builtUpMethodName, String errorCode, MethodType methodType, String dtoName, String dtoNameReplacement) {
644 try {
645 ServiceMethod method = getServiceMethod(builtUpMethodName);
646 String methodCallStr = "";
647 methodCallStr += method.getName() + " (";
648 String comma = " ";
649 for (ServiceMethodParameter param : method.getParameters()) {
650 methodCallStr += comma;
651 if (dtoName!=null && dtoNameReplacement!=null) {
652 if ((dtoName + "Info").toLowerCase().equals(param.getName().toLowerCase())) {
653 methodCallStr += dtoNameReplacement;
654 }
655 else if (param.getName().endsWith("TypeKey")) {
656 methodCallStr += dtoNameReplacement + ".getTypeKey()";
657 }
658 else if (param.getName().endsWith("Id")) {
659 methodCallStr += dtoNameReplacement + ".getId()";
660 }
661 else {
662 methodCallStr += param.getName();
663 }
664 } else {
665 methodCallStr += param.getName();
666 }
667 comma = ", ";
668 }
669 methodCallStr += ");";
670 return "testService." + methodCallStr;
671 } catch (Exception e) {
672
673 if (dtoName != null)
674 log.error("dtoName = " + dtoName + ", methodName = " + builtUpMethodName + ", errorCode = " + errorCode);
675 else
676 log.error("dtoName = unknown, methodName = " + builtUpMethodName + ", errorCode = " + errorCode);
677
678 return errorCode;
679 }
680
681 }
682
683 /**
684 * Writes the section to set fields specific to this dto for testCreate section.
685 */
686 public void writetestCrudXXX_setDTOFieldsForTestCreate(String dtoObjectName, List<MessageStructure> messageStructures) {
687 indentPrintln("/*");
688 incrementIndent();
689 indentPrintln("A method to set the fields for a " + dtoObjectName + " in a 'test create' section prior to calling the 'create' operation.");
690 decrementIndent();
691 indentPrintln("*/");
692 indentPrintln("public abstract void testCrud" + dtoObjectName + "_setDTOFieldsForTestCreate(" + dtoObjectName + "Info expected);");
693 indentPrintln("");
694 }
695
696 /**
697 * Writes the section to test fields specific to this dto for testCreate and testUpdate sections.
698 */
699 public void writetestCrudXXX_testDTOFieldsForTestCreateUpdate(String dtoObjectName, List<MessageStructure> messageStructures) {
700 indentPrintln("/*");
701 incrementIndent();
702 indentPrintln("A method to test the fields for a " + dtoObjectName + ". This is called after:");
703 indentPrintln("- creating a DTO, where actual is the DTO returned by the create operation, and expected is the dto passed in to the create operation");
704 indentPrintln("- reading a DTO after creating it, and actual is the read DTO, and expected is the dto that was created");
705 indentPrintln("- updating a DTO, where actual is DTO returned by the update operation, and expected is the dto that was passed in to the update operation");
706 decrementIndent();
707 indentPrintln("*/");
708 indentPrintln("public abstract void testCrud" + dtoObjectName + "_testDTOFieldsForTestCreateUpdate(" + dtoObjectName + "Info expected, " + dtoObjectName + "Info actual);");
709 indentPrintln("");
710 }
711
712
713 /**
714 * Writes the section to set fields specific to this dto for testUpdate sections.
715 */
716 public void writetestCrudXXX_setDTOFieldsForTestUpdate(String dtoObjectName, List<MessageStructure> messageStructures) {
717 indentPrintln("/*");
718 incrementIndent();
719 indentPrintln("A method to set the fields for a " + dtoObjectName + " in a 'test update' section prior to calling the 'update' operation.");
720 decrementIndent();
721 indentPrintln("*/");
722 indentPrintln("public abstract void testCrud" + dtoObjectName + "_setDTOFieldsForTestUpdate(" + dtoObjectName + "Info expected);");
723 indentPrintln("");
724 }
725
726 /**
727 * Writes the section to test fields specific to this dto for testReadAfterUpdate sections.
728 */
729 public void writetestCrudXXX_testDTOFieldsForTestReadAfterUpdate(String dtoObjectName, List<MessageStructure> messageStructures) {
730 indentPrintln("/*");
731 incrementIndent();
732 indentPrintln("A method to test the fields for a " + dtoObjectName + " after an update operation, followed by a read operation,");
733 indentPrintln("where actual is the DTO returned by the read operation, and expected is the dto returned by the update operation.");
734 decrementIndent();
735 indentPrintln("*/");
736 indentPrintln("public abstract void testCrud" + dtoObjectName + "_testDTOFieldsForTestReadAfterUpdate(" + dtoObjectName + "Info expected, " + dtoObjectName + "Info actual);");
737 indentPrintln("");
738 }
739
740 /**
741 * Writes the section to set fields specific to this dto for testReadAfterUpdate sections.
742 */
743 public void writetestCrudXXX_setDTOFieldsForTestReadAfterUpdate(String dtoObjectName, List<MessageStructure> messageStructures) {
744 indentPrintln("/*");
745 incrementIndent();
746 indentPrintln("A method to set the fields for a " + dtoObjectName + " in the 'test read after update' section.");
747 indentPrintln("This dto is another (second) dto object being created for other tests.");
748 decrementIndent();
749 indentPrintln("*/");
750 indentPrintln("public abstract void testCrud" + dtoObjectName + "_setDTOFieldsForTestReadAfterUpdate(" + dtoObjectName + "Info expected);");
751 indentPrintln("");
752 }
753
754 /**
755 * Given a method type, returns true if this method is tested as part of CRUD operations
756 * tested by the base test conformance class.
757 */
758 protected boolean isServiceMethodTestedAsPartofCrudInBaseConformanceTest (ServiceMethod method) {
759 MethodType methodType = calcMethodType(method);
760 if ((MethodType.CREATE.equals(methodType))
761 || (MethodType.UPDATE.equals(methodType))
762 || (MethodType.DELETE.equals(methodType))
763 || (MethodType.GET_BY_ID.equals(methodType))
764 || (MethodType.GET_BY_IDS.equals(methodType))
765 || (MethodType.GET_IDS_BY_TYPE.equals(methodType))
766 || (MethodType.GET_TYPE.equals(methodType))
767 || (MethodType.GET_TYPES.equals(methodType))
768 || (MethodType.GET_IDS_BY_TYPE.equals(methodType))
769 ) {
770 return true;
771 } else {
772 return false;
773 }
774
775 }
776
777 /**
778 * Gets a list of all the DTO names that are part of this service.
779 */
780 protected List<String> calcNamesOfDTOsWithCrudManagedByService() {
781 List<String> dtoObjectNames = new ArrayList<String>();
782 for (ServiceMethod method: methods) {
783 // I am assuming all the DTOs will have a createXXX method.
784 if (MethodType.CREATE.equals (calcMethodType(method))) {
785 String objectName = calcObjectName(method);
786 // check if this is a valid info object
787 if (finder.findXmlType(objectName + "Info")!=null) {
788 dtoObjectNames.add(objectName);
789 }
790 /*
791 for (XmlType xmlType: model.getXmlTypes()) {
792 if (xmlType.getName().equals(objectName + "Info")) {
793 dtoObjectNames.add(objectName);
794 break;
795 }
796 }
797 */
798 }
799 }
800 return dtoObjectNames;
801 }
802
803 /**
804 * Does the importsAdd for all files required for testing
805 */
806 protected void doTestImportsAdd() {
807 // kuali imports
808 importsAdd("org.kuali.student.common.test.util.IdEntityTester");
809 importsAdd("org.kuali.student.common.test.util.KeyEntityTester");
810 importsAdd("org.kuali.student.r2.common.dto.ContextInfo");
811 importsAdd("org.kuali.student.r2.common.dto.IdEntityInfo");
812 importsAdd("org.kuali.student.r2.common.dto.StatusInfo");
813 importsAdd("org.kuali.student.r2.common.dto.TypeStateEntityInfo");
814 importsAdd("org.kuali.student.r2.common.util.RichTextHelper");
815 importsAdd("org.kuali.student.r2.core.organization.service.impl.lib.AttributeTester");
816 importsAdd("org.kuali.student.r2.core.organization.service.impl.lib.MetaTester");
817
818 // import all the dto
819 // for each DTO, write the testCRUD
820 for (String dtoObjectName : dtoObjectNamesWithCrud) {
821 try { importsAdd(finder.findXmlType(dtoObjectName + "Info").getJavaPackage() + "." + dtoObjectName + "Info"); }
822 catch (Exception ignored) {}
823 }
824
825 // exceptions
826 importsAdd("org.kuali.student.r2.common.exceptions.DataValidationErrorException");
827 importsAdd("org.kuali.student.r2.common.exceptions.DependentObjectsExistException");
828 importsAdd("org.kuali.student.r2.common.exceptions.DoesNotExistException");
829 importsAdd("org.kuali.student.r2.common.exceptions.InvalidParameterException");
830 importsAdd("org.kuali.student.r2.common.exceptions.MissingParameterException");
831 importsAdd("org.kuali.student.r2.common.exceptions.OperationFailedException");
832 importsAdd("org.kuali.student.r2.common.exceptions.PermissionDeniedException");
833 importsAdd("org.kuali.student.r2.common.exceptions.ReadOnlyException");
834 importsAdd("org.kuali.student.r2.common.exceptions.VersionMismatchException");
835
836 // java imports
837 importsAdd("org.springframework.test.context.ContextConfiguration");
838 importsAdd("org.springframework.test.context.junit4.SpringJUnit4ClassRunner");
839 importsAdd("org.junit.Assert");
840 importsAdd("org.junit.Before");
841 importsAdd("org.junit.Test");
842 importsAdd("org.junit.runner.RunWith");
843 importsAdd("static org.junit.Assert.assertEquals");
844 importsAdd("static org.junit.Assert.assertFalse");
845 importsAdd("static org.junit.Assert.assertNotNull");
846 importsAdd("static org.junit.Assert.assertNull");
847 importsAdd("static org.junit.Assert.assertTrue");
848 importsAdd("static org.junit.Assert.fail");
849 importsAdd("javax.annotation.Resource");
850 importsAdd("java.util.ArrayList");
851 importsAdd("java.util.List");
852 }
853 }