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