// 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.LinkedList; 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.DefaultTaskInstanceTraversingVisitor; import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask; import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance; import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration; import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptionalInstance; import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection; import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelectionInstance; 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; /** * This is a convenience class for testing to evaluate if a certain task or task instance structure * matches a given textual specification for the structure. * * @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 assertUserSession(String userSessionSpec, IUserSession session) { if (doTrace) { new TaskTreeEncoder().encode(session, System.err); } TaskSpec taskInstanceSpec = null; Matcher taskMatcher = taskPattern.matcher(userSessionSpec); Map tasks = new HashMap(); while (taskMatcher.find()) { taskInstanceSpec = parseTaskInstance(taskMatcher); if (taskInstanceSpec != null) { assertUserSession(taskInstanceSpec, session, tasks); } } } /** * */ public void assertTaskInstance(String userSessionSpec, ITaskInstance taskInstance) { if (doTrace) { new TaskTreeEncoder().encode(taskInstance, System.err); } TaskSpec taskInstanceSpec = null; Matcher taskMatcher = taskPattern.matcher(userSessionSpec); Map tasks = new HashMap(); while (taskMatcher.find()) { taskInstanceSpec = parseTaskInstance(taskMatcher); if (taskInstanceSpec != null) { assertTaskInstance(taskInstanceSpec, taskInstance, 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.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); } /** * */ public void assertEventTaskInstancesEqual(ITaskInstanceList expected, ITaskInstanceList checked) { final List expectedEventTaskInstances = new ArrayList(); final List checkedEventTaskInstances = new ArrayList(); for (ITaskInstance instance : expected) { instance.accept(new DefaultTaskInstanceTraversingVisitor() { @Override public void visit(IEventTaskInstance eventTaskInstance) { expectedEventTaskInstances.add(eventTaskInstance); } }); } for (ITaskInstance instance : checked) { instance.accept(new DefaultTaskInstanceTraversingVisitor() { @Override public void visit(IEventTaskInstance eventTaskInstance) { checkedEventTaskInstances.add(eventTaskInstance); } }); } assertEquals("task instance lists differ in the number of event task instances", expectedEventTaskInstances.size(), checkedEventTaskInstances.size()); for (int i = 0; i < expectedEventTaskInstances.size(); i++) { assertTaskInstancesEqual (expectedEventTaskInstances.get(i), checkedEventTaskInstances.get(i)); } } /** * */ 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 = getChildren(expected); List checkedChildren = getChildren(checked); 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; } /** * */ private void assertUserSession(TaskSpec taskSpec, IUserSession session, Map tasks) { if (doTrace) { System.err.println("\ncomparing " + taskSpec.type + " with " + session + "\n"); } if (!"UserSession".equals(taskSpec.type)) { fail("can not compare a task instance with a user session"); } List children = session.getExecutedTasks(); if (taskSpec.children.length != children.size()) { fail("number of task instances in task instance list does not match"); } for (int i = 0; i < children.size(); i++) { TaskSpec childSpec = taskSpec.children[i]; assertTrue(taskSpecEqualsTaskInstance(childSpec, children.get(i), tasks)); } } /** * */ private void assertTaskInstance(TaskSpec taskSpec, ITaskInstance taskInstance, Map tasks) { if (doTrace) { System.err.println("\ncomparing " + taskSpec.type + " with " + taskInstance + "\n"); } if (!"TaskInstances".equals(taskSpec.type)) { fail("can not compare a task instance with a task instance list"); } List children = getChildren(taskInstance); if (taskSpec.children.length != children.size()) { fail("number of task instances in task instance list does not match"); } for (int i = 0; i < children.size(); i++) { TaskSpec childSpec = taskSpec.children[i]; assertTrue(taskSpecEqualsTaskInstance(childSpec, children.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) && ((!(taskInstance instanceof IEventTaskInstance)) || (!(((IEventTaskInstance) taskInstance).getEvent().getType() 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) ((IEventTaskInstance) taskInstance).getEvent().getType(); 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) && (((IEventTaskInstance) taskInstance).getEvent().getType() != null) && (!taskSpec.name.equals(((IEventTaskInstance) taskInstance).getEvent().getType().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(((IEventTaskInstance) taskInstance).getEvent().getType().getName())) { if (doTrace) { System.err.println ("event names do not match: " + taskSpec.name + " != " + ((IEventTaskInstance) taskInstance).getEvent().getType().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); } List children = getChildren(taskInstance); if (((taskSpec.children == null) && (children.size() > 0)) || ((taskSpec.children != null) && (taskSpec.children.length != children.size()))) { if (doTrace) { System.err.println ("numbers of children do not match: " + (taskSpec.children == null ? "0" : taskSpec.children.length) + " != " + (children == null ? "0" : children.size()) + "\n"); } return false; } Iterator childrenIterator = children.iterator(); if (taskSpec.children != null) { for (TaskSpec child : taskSpec.children) { if (!taskSpecEqualsTaskInstance(child, childrenIterator.next(), tasks)) { if (doTrace) { System.err.println("one of the children does not match\n"); } return false; } } } if (!childrenIterator.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 List getChildren(ITaskInstance taskInstance) { List result = new LinkedList(); if (taskInstance instanceof ITaskInstanceList) { for (ITaskInstance child : (ITaskInstanceList) taskInstance) { result.add(child); } } else if (taskInstance instanceof ISelectionInstance) { result.add(((ISelectionInstance) taskInstance).getChild()); } else if (taskInstance instanceof IOptionalInstance) { result.add(((IOptionalInstance) taskInstance).getChild()); } return result; } /** * */ private class TaskSpec { public String type; public String name; public String additionalInfo; public TaskSpec[] children; } }