// Copyright 2012 Georg-August-Universität Göttingen, Germany // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package de.ugoe.cs.autoquest.tasktrees; import static org.junit.Assert.*; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import de.ugoe.cs.autoquest.eventcore.gui.TextInput; import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask; import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration; import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection; import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstanceList; import de.ugoe.cs.autoquest.tasktrees.treeifc.IUserSession; /** * TODO comment * * @version $Revision: $ $Date: 01.04.2012$ * @author 2012, last modified by $Author: patrick$ */ public class TaskTreeChecker { /** */ private static Pattern taskPattern = Pattern.compile("([^{}]+)\\{|\\}"); /** */ private static Pattern taskDetailsPattern = Pattern.compile("\\s*(\\w*)\\s*([\\w\\(\\)\"]*)\\s*((\\w*)|(\".*\"))?"); /** */ private boolean doTrace; /** * */ public TaskTreeChecker() { this(false); } /** * */ public TaskTreeChecker(boolean doTrace) { this.doTrace = doTrace; } /** * */ public void assertTaskInstanceList(String userSessionSpec, ITaskInstanceList taskInstances) { if (doTrace) { new TaskTreeEncoder().encode(taskInstances, System.err); } TaskSpec taskInstanceSpec = null; Matcher taskMatcher = taskPattern.matcher(userSessionSpec); Map tasks = new HashMap(); while (taskMatcher.find()) { taskInstanceSpec = parseTaskInstance(taskMatcher); if (taskInstanceSpec != null) { assertTaskInstanceList(taskInstanceSpec, taskInstances, tasks); } } } /** * */ public void assertTaskInstanceListsEqual(ITaskInstanceList expected, ITaskInstanceList checked) { if (expected == null) { assertNull("null", checked); } else { assertNotNull(expected.toString(), checked); assertEquals(expected.toString() + ": types do not match", expected.getClass(), checked.getClass()); if ((expected != null) && (expected.size() > 0)) { assertNotNull(expected.toString() + ": children not there", checked); assertEquals(expected.toString() + ": different number of children", expected.size(), checked.size()); Map equalTasksMap = new HashMap(); for (int i = 0; i < expected.size(); i++) { assertTaskInstancesEqual(expected.get(i), checked.get(i), equalTasksMap); } } else { assertTrue(expected.toString() + ": unexpected children", (checked == null) || (checked.size() == 0)); } } } /** * */ public void assertTaskInstancesEqual(ITaskInstance expected, ITaskInstance checked) { Map equalTasksMap = new HashMap(); assertTaskInstancesEqual(expected, checked, equalTasksMap); } /** * */ private void assertTaskInstancesEqual(ITaskInstance expected, ITaskInstance checked, Map equalTasksMap) { if (expected == null) { assertNull("null", checked); } else { assertNotNull(expected.toString(), checked); assertEquals(expected.toString() + ": types do not match", expected.getClass(), checked.getClass()); if (equalTasksMap.containsKey(expected.getTask())) { assertEquals(expected.toString() + ": tasks do not match", checked.getTask(), equalTasksMap.get(expected.getTask())); } else { equalTasksMap.put(expected.getTask(), checked.getTask()); } List expectedChildren = expected.getChildren(); List checkedChildren = checked.getChildren(); if ((expectedChildren != null) && (expectedChildren.size() > 0)) { assertNotNull(expected.toString() + ": children not there", checkedChildren); assertEquals(expected.toString() + ": different number of children", expectedChildren.size(), checkedChildren.size()); if (expected instanceof ISequence) { for (int i = 0; i < expectedChildren.size(); i++) { assertTaskInstancesEqual(expectedChildren.get(i), checkedChildren.get(i)); } } else { for (int i = 0; i < expectedChildren.size(); i++) { boolean found = false; for (int j = 0; j < checkedChildren.size(); j++) { try { assertTaskInstancesEqual (expectedChildren.get(i), checkedChildren.get(j)); found = true; break; } catch (AssertionError e) { // try next } } assertTrue("one of the children not found", found); } } } else { assertTrue(expected.toString() + ": unexpected children", (checkedChildren == null) || (checkedChildren.size() == 0)); } } } /** * */ private TaskSpec parseTaskInstance(Matcher taskMatcher) { if ("}".equals(taskMatcher.group(1))) { throw new IllegalArgumentException("invalid task specification"); } String taskDetails = taskMatcher.group(1); Matcher matcher = taskDetailsPattern.matcher(taskDetails); if (!matcher.find()) { throw new IllegalArgumentException("could not parse task details"); } TaskSpec task = new TaskSpec(); task.type = matcher.group(1); task.name = matcher.group(2); if ((matcher.group(4) != null) && (!"".equals(matcher.group(4).trim()))) { task.name += " " + matcher.group(4).trim(); } if ((matcher.group(5) != null) && (!"".equals(matcher.group(5).trim()))) { task.additionalInfo = matcher.group(5).trim(); } if ("".equals(task.name)) { task.name = null; } List children = new ArrayList(); while (taskMatcher.find() && !"}".equals(taskMatcher.group(0))) { children.add(parseTaskInstance(taskMatcher)); } if (children.size() > 0) { task.children = children.toArray(new TaskSpec[children.size()]); } return task; } /** * @param task * @param taskMapCopy */ private void assertTaskInstanceList(TaskSpec taskSpec, ITaskInstanceList taskInstances, Map tasks) { if (doTrace) { System.err.println("\ncomparing " + taskSpec.type + " with " + taskInstances + "\n"); } if ((taskInstances instanceof IUserSession) && (!"UserSession".equals(taskSpec.type))) { fail("can not compare a task instance with a user session"); } else if ((!(taskInstances instanceof IUserSession)) && (!"TaskInstances".equals(taskSpec.type))) { fail("can not compare a task instance with a task instance list"); } if (taskSpec.children.length != taskInstances.size()) { fail("number of task instances in task instance list does not match"); } for (int i = 0; i < taskInstances.size(); i++) { TaskSpec childSpec = taskSpec.children[i]; assertTrue(taskSpecEqualsTaskInstance(childSpec, taskInstances.get(i), tasks)); } } /** * */ private boolean taskSpecEqualsTaskInstance(TaskSpec taskSpec, ITaskInstance taskInstance, Map tasks) { if (doTrace) { System.err.println("comparing " + taskSpec.name + " with"); new TaskTreeEncoder().encode(taskInstance, System.err); } ITask task = taskInstance.getTask(); if (("Event".equals(taskSpec.type) && (!(task instanceof IEventTask))) || ("TextInputEvent".equals(taskSpec.type) && ((!(task instanceof IEventTask)) || (!(((IEventTask) task).getEventType() instanceof TextInput)))) || ("Sequence".equals(taskSpec.type) && (!(task instanceof ISequence))) || ("Selection".equals(taskSpec.type) && (!(task instanceof ISelection))) || ("Iteration".equals(taskSpec.type) && (!(task instanceof IIteration)))) { if (doTrace) { System.err.println("task types do not match: " + taskSpec.type + " != " + task.getClass().getSimpleName() + "\n"); } return false; } else if (!"Event".equals(taskSpec.type) && !"TextInputEvent".equals(taskSpec.type) && !"Sequence".equals(taskSpec.type) && !"Selection".equals(taskSpec.type) && !"Iteration".equals(taskSpec.type)) { fail("unknown task type " + taskSpec.type + " --> please extend test case"); } if ("TextInputEvent".equals(taskSpec.type)) { TextInput eventType = (TextInput) ((IEventTask) task).getEventType(); if ((taskSpec.additionalInfo != null) && !"".equals(taskSpec.additionalInfo) && !(taskSpec.additionalInfo.equals(eventType.getEnteredText()))) { if (doTrace) { System.err.println("expected text \"" + taskSpec.additionalInfo + "\" is not equal to the text " + "provided by the task \"" + eventType.getEnteredText() + "\"\n"); } return false; } } else if ((task instanceof IEventTask) && (((IEventTask) task).getEventType() != null) && (!taskSpec.name.equals(((IEventTask) task).getEventType().getName()))) { // simple event names do not match. But what about the event name in // combination with the additional info String complexName = taskSpec.name + (!"".equals(taskSpec.additionalInfo) ? " " + taskSpec.additionalInfo : ""); if (!complexName.equals(((IEventTask) task).getEventType().getName())) { if (doTrace) { System.err.println("event names do not match: " + taskSpec.name + " != " + ((IEventTask) task).getEventType().getName() + "\n"); } return false; } } // check the task name against the map if (tasks.containsKey(taskSpec.name)) { if (!tasks.get(taskSpec.name).equals(task)) { if (doTrace) { System.err.println("the task instance is not of the expected task: " + taskSpec.name + " != " + task + "\n"); } return false; } } else if (tasks.containsValue(task)) { if (doTrace) { System.err.println("the task of the task instance " + taskSpec.name + " should be different to another one but it isn't\n"); } return false; } else { tasks.put(taskSpec.name, task); } if (((taskSpec.children == null) && (taskInstance.getChildren().size() > 0)) || ((taskSpec.children != null) && (taskSpec.children.length != taskInstance.getChildren().size()))) { if (doTrace) { System.err.println ("numbers of children do not match: " + (taskSpec.children == null ? "0" : taskSpec.children.length) + " != " + (taskInstance.getChildren() == null ? "0" : taskInstance.getChildren().size()) + "\n"); } return false; } Iterator children = taskInstance.getChildren().iterator(); if (taskSpec.children != null) { for (TaskSpec child : taskSpec.children) { if (!taskSpecEqualsTaskInstance(child, children.next(), tasks)) { if (doTrace) { System.err.println("one of the children does not match\n"); } return false; } } } if (!children.hasNext()) { if (doTrace) { System.err.println("nodes match\n"); } return true; } else { if (doTrace) { System.err.println("number of children does not match\n"); } return false; } } /** * */ private class TaskSpec { public String type; public String name; public String additionalInfo; public TaskSpec[] children; } }