package caltool.model.schedule; import caltool.model.caldb.*; import mvp.*; import java.util.*; import org.testng.*; import org.testng.annotations.*; /**** * * Class ScheduleTest is the companion testing class for class Schedule . It implements the following module test plan: *
* Test
* Case Input Output Remarks
* ====================================================================
* 1 null Proper init done Only case
*
*/
@Test
protected void testSchedule() {
schedule = new Schedule(null, new CalendarDB()); // setup & invoke
Assert.assertTrue( // validate
validateSchedulePostcond(schedule));
}
/**
* Unit test getCategories by calling getCategories on a schedule with a
* null and non-null categories field. The Categories model is tested
* fully in its own class test.
*
* Test
* Case Input Output Remarks
* ====================================================================
* 1 schedule.categories null Null case
* == null
*
* 2 schedule.categories same non-null Non-null case
* =- non-null value
*
*/
@Test(dependsOnMethods = {"testSchedule"})
protected void testGetCategories() {
Categories result; // method return value
/*
* Do case 1 and validate the result.
*/
schedule.categories = null; // setup
result = schedule.getCategories(); // invoke
Assert.assertTrue( // validate
validateGetCategoriesPostcond(result));
/*
* Do case 2 and validate the result.
*/
schedule.categories = new Categories(); // setup
result = schedule.getCategories(); // invoke
Assert.assertTrue( // validate
validateGetCategoriesPostcond(result));
}
/**
* Unit test setTaskPriority by sending inputs in and out of range.
*
* Test
* Case Input Output Remarks
* ====================================================================
* 1 task, priority = 0 task.priority = 0 Bottom of range
* 2 task, priority = 5 task.priority = 5 Middle of range
* 3 task, priority = 5 task.priority = 10 Top of range
* 4 task, priority = -1 exception thrown Just below bottom
* 5 task, priority = -100 exception thrown Well below bottom
* 6 task, priority = 11 exception thrown Just above top
* 7 task, priority = 100 exception thrown Well above top
*/
@Test(dependsOnMethods = {"testSchedule"})
void testSetTaskPriority ()
throws ScheduleTaskPrecondViolation {
Task task = new Task();
schedule.setTaskPriority(task, 0);
Assert.assertTrue(validateSetTaskPriorityPostcond(task, 0));
schedule.setTaskPriority(task, 5);
Assert.assertTrue(validateSetTaskPriorityPostcond(task, 5));
schedule.setTaskPriority(task, 10);
Assert.assertTrue(validateSetTaskPriorityPostcond(task, 10));
try {
schedule.setTaskPriority(task, -1);
Assert.assertTrue(false);
}
catch (ScheduleTaskPrecondViolation e) {
Assert.assertTrue(true);
}
try {
schedule.setTaskPriority(task, -100);
Assert.assertTrue(false);
}
catch (ScheduleTaskPrecondViolation e) {
Assert.assertTrue(true);
}
try {
schedule.setTaskPriority(task, 11);
Assert.assertTrue(false);
}
catch (ScheduleTaskPrecondViolation e) {
Assert.assertTrue(true);
}
try {
schedule.setTaskPriority(task, 100);
Assert.assertTrue(false);
}
catch (ScheduleTaskPrecondViolation e) {
Assert.assertTrue(true);
}
}
/**
* Unit test scheduleEvent by supplying inputs that test the value range of
* each Event data field and exercise each precondition clause. The cases
* are as follows:
*
* Test
* Case Input Output Remarks
* ====================================================================
* 1 {"Event 0", Input event Lower end of possible
* {"Sunday",1, added to items event data range
* "January",1}, no junk, no
* null, confusion
* null,
* null}
*
* 2 {10000-char string, Input event Upper end of possible
* {"Sunday",1, added to items event data range
* "January",1}, no junk,
* {"Saturday",31, no confusion
* "December", 9999},
* 10000-char string
* reversed,
* 10000-char string}
*
* 3 events with start and Input event Events with all combos
* thru end date ranging thru added to items of days, dates, and
* 2564 each legal day, each no junk, no months
* legal date, and each confusion
* legal month, with
* rotating year,
* category, and security,
* where "rotating" means
* that test values for
* years are generated in
* multiples of 100,
* numeric-valued category
* strings are generated
* in multiples of 10,
* and the two possible
* values of security are
* toggled for each case
*
* 2565 32 cases to exercise Schedule Events that violate
* thru possible boolean Event precond logic.
* 2597 values for 5 precond Precond
* clauses Exception
* thrown
*
*/
@Test(dependsOnMethods = {"testSchedule"})
protected void testScheduleEvent() {
/*
* Do the cases.
*/
try {
testScheduleEventCase1();
testScheduleEventCase2();
testScheduleEventCases3Thru2564();
testScheduleEventCases2565Thru2597();
}
catch (ScheduleEventPrecondViolation e) {
/* This should not happen at this level, but in case it does ... */
System.out.println("scheduleEvent EXCEPTION:");
for (int i = 0; i < e.numberOfErrors(); i++) {
System.out.println(e.getErrors()[i]);
}
}
}
/**
* Run testScheduleEvent case 1.
*/
protected void testScheduleEventCase1()
throws ScheduleEventPrecondViolation {
Event e;
/*
* Get a shallow clone of the pre-scheduling items.
*/
ScheduledItem[] preItems =
schedule.calDB.getCurrentCalendar().getItemsCopy();
/*
* Call the method under test.
*/
schedule.scheduleEvent(e = new Event(
"Event 0", // title
new Date(DayName.Sunday, // start date
1,
MonthName.January,
1),
null, // end date
new Category("Category 1"), // category
SimpleSecurity.Public // security
));
/*
* Do the validation.
*/
validateScheduleEventPostcond(preItems, e);
}
/**
* Run testScheduleEvent case 2.
*/
protected void testScheduleEventCase2()
throws ScheduleEventPrecondViolation {
int i;
String longString = "";
String longStringReversed = "";
Event e;
ScheduledItem[] preItems =
schedule.calDB.getCurrentCalendar().getItemsCopy();
for (i = 0; i < 10000; i++) {
longString += (char) i % 256;
longStringReversed = (char) i + longStringReversed;
}
schedule.scheduleEvent(e = new Event(
longString, // title
new Date(DayName.Sunday, // start date
1,
MonthName.January,
1),
new Date(DayName.Saturday, // end date
2,
MonthName.December,
9999),
new Category(longStringReversed), // category
SimpleSecurity.Private // security
));
validateScheduleEventPostcond(preItems, e);
}
/**
* Run testScheduleEvent cases 3 through 2564 by looping through various
* combinations of days, weeks, and months.
*/
protected void testScheduleEventCases3Thru2564()
throws ScheduleEventPrecondViolation {
int day, number, month, year, i, n;
Date date;
Event e;
for (i = 3, day = 0; day < 7; day++) {
for (number = 1; number <= 31; number++) {
for (month = 0; month < 12; month++) {
date = new Date(
DayName.values()[day],
number,
MonthName.values()[month],
year = number * 100);
if (date.isValid()) {
ScheduledItem[] preItems =
schedule.calDB.getCurrentCalendar().getItemsCopy();
schedule.scheduleEvent(e = new Event(
"Event " + // title
String.valueOf(n = year + month + day),
date, // start
date, // end
new Category(String.valueOf(n*10)), // category
((number % 2) == 0) ? // security
SimpleSecurity.Public :
SimpleSecurity.Private
));
validateScheduleEventPostcond(preItems, e);
}
}
}
}
p("Done with Cases 3 thru 2564");
}
/**
* Run testScheduleEvent cases 2565 through 2597 to fully exercise the
* precond logic.
*/
protected void testScheduleEventCases2565Thru2597() {
/* Coming next milestone */
}
/*-*
* Postcondition validation methods.
*/
/**
* Evaluate the Schedule constructor postcond on the given calDB and
* cheduleEventPrecondViolation inputs, with this.schedule as the actual
* output.
*/
boolean validateSchedulePostcond(Schedule schedule) {
return
schedule.getView() == view &&
schedule.calDB != null &&
schedule.scheduleEventPrecondViolation != null &&
!schedule.scheduleEventPrecondViolation.anyErrors();
// 3 other precond checks omitted temporarily for simplicity
}
/**
* Evaluate the getCategories postcond with the given returnVal as the
* actual output.
*/
boolean validateGetCategoriesPostcond(Categories returnVal) {
return schedule.categories == returnVal;
}
/**
* Evaluate the setTaskPriority postcond on the given task and priority
* value.
*/
boolean validateSetTaskPriorityPostcond(Task task, int priority) {
return task.priority == priority;
}
/**
* Evaluate the scheduleEvet postcond on this.schedule. For quick
* reference, here's the postcond:
*
* (\forall ScheduledItem item;
* calDB.getCurrentCalendar().getItems().contains(item);
* item.equals(event) ||
* \old(calDB).getCurrentCalendar().getItems().contains(item))
*
* &&
*
* (calDB.getCurrentCalendar().getItems().size() ==
* \old(calDB).getCurrentCalendar().getItems().size() + 1)
*
* &&
*
* calDB.getCurrentCalendar().requiresSaving()
*
* &&
*
* calDB.getCurrentCalendar().hasChanged();
*/
boolean validateScheduleEventPostcond(ScheduledItem[] preItems, Event e) {
/*
* Evaluate the forall with a loop over the array return value of
* getItems. Note that this is a "short-circuit" evaluation loop,
* where we return false at the first occurrance of postcond violation.
* Note also that we are using the value of preItems as the value
* represented absractly as \old(...) in the abstract JML logic.
*/
p("items size = " + schedule.calDB.getCurrentCalendar().getItems().size());
for (ScheduledItem item :
schedule.calDB.getCurrentCalendar().getItems()) {
p("item = " + item.title);
if (! (item.equals(e) || Arrays.asList(preItems).contains(item))) {
return false;
}
p("item in postcond eval loop = " + item.title);
}
/*
ScheduledItem[] itemsArray = null;
itemsArray =
schedule.calDB.getCurrentCalendar().getItems().toArray(itemsArray);
for (int i = 0;
i < schedule.calDB.getCurrentCalendar().getItems().size();
i++) {
p(i + "th item = " + itemsArray[i]);
}
*/
/*
* The remaining clauses of the postcond are non-looping bool exprs
* that can be evaluated in the normal way.
*/
return
(schedule.calDB.getCurrentCalendar().getItems().size() ==
preItems.length + 46)
&&
schedule.calDB.getCurrentCalendar().requiresSaving()
&&
schedule.calDB.getCurrentCalendar().hasChanged();
}
/*-*
* Testing utility methods.
*/
/**
* Output a header message to stdout identifying the test phase.
*/
protected void dumpPhaseHeader(int phasenum) {
System.out.print("**** Schedule Testing Phase ");
System.out.print(phasenum);
System.out.println(" ****");
}
/**
* Output a header message to stdout for the unit test of the given
* testname.
*/
protected void dumpUnitTestHeader(String testname) {
System.out.print("** Unit Test " + testname + " **\n");
}
/**
* Output a header message to stdout for a unit test case.
*/
protected void dumpUnitTestCaseHeader(String testname, int caseNumber) {
System.out.print("* Unit Test Case " +
testname + String.valueOf(caseNumber) + " **\n");
}
/**
* Dump three blank lines following a test phase.
*/
protected void dumpPhaseEndSpacing() {
System.out.print("\n\n\n");
}
/**
* Dump a couple blank lines following a unit test.
*/
protected void dumpUnitTestEndSpacing() {
System.out.print("\n\n");
}
/**
* Dump just a string message.
*/
protected void dumpMessage(String message) {
System.out.println(message);
}
/**
* Dump the data values of schedule to stdout. For test validation
* purposes, include a print of the number of elements in the dumped items.
* Precede the dump with the given message, if the message is non-null.
*/
protected void dump(String message) {
int l; // Temp
if (message != null) {
System.out.print("* " + message + " *" + "\n");
}
System.out.print("Schedule contains\n" +
"Categories: " + schedule.categories + "\n" +
(l = schedule.calDB.getCurrentCalendar().numItems()) + " " +
(l == 1 ? " item" : " items") + "\n" +
schedule.toString() + "\n"
);
}
/**
* Schedule data object to support the tests.
*/
protected Schedule schedule;
/**
* Unit test scheduleAppointment using test cases 1-2564 of
* testScheduleEvent, with the addition of rotating values for the
* components of an Appointment that aren't in an Event. These rotating
* vales are: toggling value for recurring, toggling value for Priority,
* toggling value for remind, string value of details that starts with
* empty and increments by string length of 1, with the addition of of
* numerically increasing ASCII character values.
*
* 2565 32 cases to exercise Schedule Appointments that
* thru possible boolean Apppointment violate precond logic.
* 2629 values for 6 precond Precond
* clauses Exception
* thrown
*
*/
protected void testScheduleAppointment() {
}
/**
* Unit test scheduleTask using test cases 1-2564 of
* testScheduleAppointment, disregarding rotating values for the components
* of an Appointment that aren't in a Task, and adding rotating values for
* the Due Time and Priority components of a Task that are not in an
* Appointment. Values for Due Time rotate from 00:00 through 23:50 in
* increments of 10 minutes (i.e., modulo 24:00). Values for Priority
* rotate from 0 through 10 (i.e., modulo 11).
*/
protected void testScheduleTask() {
}
private void p(String s) { System.out.println(s); }
}