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 */ 016package org.kuali.student.mock.mojo; 017 018import org.kuali.student.contract.model.MessageStructure; 019import org.kuali.student.contract.model.Service; 020import org.kuali.student.contract.model.ServiceContractModel; 021import org.kuali.student.contract.model.ServiceMethod; 022import org.kuali.student.contract.model.ServiceMethodError; 023import org.kuali.student.contract.model.ServiceMethodParameter; 024import org.kuali.student.contract.model.util.ServicesFilter; 025import org.kuali.student.contract.writer.service.GetterSetterNameCalculator; 026import org.slf4j.Logger; 027import org.slf4j.LoggerFactory; 028 029import javax.management.OperationsException; 030 031import java.util.ArrayList; 032import 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 */ 044public 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}