// 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.commands.usability; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import com.google.common.collect.Sets; import de.ugoe.cs.autoquest.CommandHelpers; import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence; import de.ugoe.cs.autoquest.tasktrees.treeifc.TaskTreeUtils; import de.ugoe.cs.autoquest.usability.UsabilityEvaluationResult; import de.ugoe.cs.autoquest.usability.UsabilitySmell; import de.ugoe.cs.autoquest.usability.UsabilitySmell.ManualLabel; import de.ugoe.cs.util.console.Command; import de.ugoe.cs.util.console.GlobalDataContainer; /** *

* TODO comment *

* * @author Patrick Harms * @version 1.0 */ public class CMDusabilityStatistics implements Command { private static int COUNT = 0; private static int DUPLICATES = 1; private static int INTENSITY_LVL = 2; private static int TRUE_POSITIVE = 3; private static int TRUE_POSITIVE_DUPLICATES = 4; private static int TRUE_POSITIVE_INTENSITY_LVL = 5; private static int UNASSESSED = 6; private static int MP_COUNT = 7; private static int MP_DUPLICATES = 8; private static int MP_INTENSITY_LVL = 9; private static int MP_TRUE_POSITIVE = 10; private static int MP_TRUE_POSITIVE_DUPLICATES = 11; private static int MP_TRUE_POSITIVE_INTENSITY_LVL = 12; private static int MP_UNASSESSED = 13; /* * (non-Javadoc) * * @see de.ugoe.cs.util.console.Command#run(java.util.List) */ @Override public void run(List parameters) { List usabilityResultNames = new ArrayList<>(parameters.size()); try { for (Object parameter : parameters) { usabilityResultNames.add((String) parameter); } } catch (Exception e) { throw new IllegalArgumentException(); } List usabilityResults = new ArrayList<>(usabilityResultNames.size()); for (String usabilityResultName : usabilityResultNames) { Object dataObject = GlobalDataContainer.getInstance().getData(usabilityResultName); if (dataObject == null) { CommandHelpers.objectNotFoundMessage(usabilityResultName); return; } if (!(dataObject instanceof UsabilityEvaluationResult)) { CommandHelpers.objectNotType(usabilityResultName, "UsabilityEvaluationResult"); return; } usabilityResults.add((UsabilityEvaluationResult) dataObject); } // analyse all smells Map> allSmells = new TreeMap<>(); Map> mostProminentSequences = new TreeMap<>(); Set smellTypes = new TreeSet<>(); for (int i = 0; i < usabilityResults.size(); i++) { String usabilityResultName = usabilityResultNames.get(i); allSmells.put(usabilityResultName, usabilityResults.get(i).getAllSmells()); for (UsabilitySmell smell : usabilityResults.get(i).getAllSmells()) { smellTypes.add(smell.getBriefDescription()); } if (!mostProminentSequences.containsKey(usabilityResultName)) { mostProminentSequences.put(usabilityResultName, TaskTreeUtils.getMostProminentTasks (usabilityResults.get(i).getTaskModel())); } } analyseAndDump("all smells", allSmells, mostProminentSequences); for (String smellType : smellTypes) { Map> relevantSmells = new TreeMap<>(); for (int i = 0; i < usabilityResults.size(); i++) { List smellList = new LinkedList<>(); for (UsabilitySmell smell : usabilityResults.get(i).getAllSmells()) { if (smellType.equals(smell.getBriefDescription())) { smellList.add(smell); } } relevantSmells.put(usabilityResultNames.get(i), smellList); } analyseAndDump(smellType, relevantSmells, mostProminentSequences); } } /** * */ private void analyseAndDump(String setName, Map> smells, Map> mostProminentSequences) { System.out.println("\n\n###################################################################"); System.out.println("usability statistics for " + setName + "\n"); // determine statistics int[][] basicResultData = new int[14][]; for (int i = 0; i < basicResultData.length; i++) { basicResultData[i] = new int[smells.size()]; } Map>> tagCounters = new TreeMap<>(); List columnNames = new LinkedList<>(); int index = 0; for (Map.Entry> smellGroup : smells.entrySet()) { String usabilityResultName = smellGroup.getKey(); columnNames.add(usabilityResultName); basicResultData[COUNT][index] = smellGroup.getValue().size(); basicResultData[DUPLICATES][index] = getDuplicates(smellGroup.getValue()); basicResultData[INTENSITY_LVL][index] = getIntensityLevel(smellGroup.getValue()); List truePositives = new LinkedList<>(); List unassessed = new LinkedList<>(); List mps = new LinkedList<>(); List mpTruePositives = new LinkedList<>(); List mpUnassessed = new LinkedList<>(); for (UsabilitySmell smell : smellGroup.getValue()) { if (smell.getManualLabel() == ManualLabel.TRUE_POSITIVE) { truePositives.add(smell); } else if (smell.getManualLabel() == ManualLabel.UNCHECKED) { unassessed.add(smell); } if (mostProminentSequences.get(smellGroup.getKey()).contains(smell.getSmellingTask())) { mps.add(smell); if (smell.getManualLabel() == ManualLabel.TRUE_POSITIVE) { mpTruePositives.add(smell); } else if (smell.getManualLabel() == ManualLabel.UNCHECKED) { mpUnassessed.add(smell); } } Set tagList = new HashSet<>(smell.getTags()); Set> powerSetTags = Sets.powerSet(tagList); for (Set tagSet : powerSetTags) { List tags = new LinkedList<>(tagSet); //{List tags = new LinkedList<>(tagList); Collections.sort(tags); String tagCombinationKey = tags.toString(); Map> counterMap = tagCounters.get(tagCombinationKey); if (counterMap == null) { counterMap = new HashMap<>(); tagCounters.put(tagCombinationKey, counterMap); } List smellWithSameTagCombination = counterMap.get(usabilityResultName); if (smellWithSameTagCombination == null) { smellWithSameTagCombination = new LinkedList<>(); counterMap.put(usabilityResultName, smellWithSameTagCombination); } smellWithSameTagCombination.add(smell); } } basicResultData[TRUE_POSITIVE][index] = truePositives.size(); basicResultData[TRUE_POSITIVE_DUPLICATES][index] = getDuplicates(truePositives); basicResultData[TRUE_POSITIVE_INTENSITY_LVL][index] = getIntensityLevel(truePositives); basicResultData[UNASSESSED][index] = unassessed.size(); basicResultData[MP_COUNT][index] = mps.size(); basicResultData[MP_DUPLICATES][index] = getDuplicates(mps); basicResultData[MP_INTENSITY_LVL][index] = getIntensityLevel(mps); basicResultData[MP_TRUE_POSITIVE][index] = mpTruePositives.size(); basicResultData[MP_TRUE_POSITIVE_DUPLICATES][index] = getDuplicates(mpTruePositives); basicResultData[MP_TRUE_POSITIVE_INTENSITY_LVL][index] = getIntensityLevel(mpTruePositives); basicResultData[MP_UNASSESSED][index] = mpUnassessed.size(); index++; } int maxTagNameLength = 0; for (String tagCombination : tagCounters.keySet()) { maxTagNameLength = Math.max(maxTagNameLength, tagCombination.length()); } maxTagNameLength = Math.max(maxTagNameLength, " intensity level".length()); List lines = new LinkedList<>(); lines.add(createBorderLine(maxTagNameLength, columnNames)); lines.add(new StringBuffer("overall")); lines.add(createDataLine(" count", maxTagNameLength, basicResultData[COUNT], columnNames)); lines.add(createDataLine(" duplicates", maxTagNameLength, basicResultData[DUPLICATES], columnNames)); lines.add(createDataLine(" intensity level", maxTagNameLength, basicResultData[INTENSITY_LVL], columnNames)); lines.add(createDataLine(" true positives", maxTagNameLength, basicResultData[TRUE_POSITIVE], columnNames)); lines.add(createDataLine(" duplicates", maxTagNameLength, basicResultData[TRUE_POSITIVE_DUPLICATES], columnNames)); lines.add(createDataLine(" intensity level", maxTagNameLength, basicResultData[TRUE_POSITIVE_INTENSITY_LVL], columnNames)); lines.add(createDataLine(" unassessed", maxTagNameLength, basicResultData[UNASSESSED], columnNames)); lines.add(createBorderLine(maxTagNameLength, columnNames)); lines.add(new StringBuffer("most prominent")); lines.add(createDataLine(" count", maxTagNameLength, basicResultData[MP_COUNT], columnNames)); lines.add(createDataLine(" duplicates", maxTagNameLength, basicResultData[MP_DUPLICATES], columnNames)); lines.add(createDataLine(" intensity level", maxTagNameLength, basicResultData[MP_INTENSITY_LVL], columnNames)); lines.add(createDataLine(" true positives", maxTagNameLength, basicResultData[MP_TRUE_POSITIVE], columnNames)); lines.add(createDataLine(" duplicates", maxTagNameLength, basicResultData[MP_TRUE_POSITIVE_DUPLICATES], columnNames)); lines.add(createDataLine(" intensity level", maxTagNameLength, basicResultData[MP_TRUE_POSITIVE_INTENSITY_LVL], columnNames)); lines.add(createDataLine(" unassessed", maxTagNameLength, basicResultData[MP_UNASSESSED], columnNames)); lines.add(createBorderLine(maxTagNameLength, columnNames)); for (Map.Entry>> tagStats : tagCounters.entrySet()) { StringBuffer line = new StringBuffer(); line.append(tagStats.getKey()); for (int i = tagStats.getKey().length(); i < maxTagNameLength; i++) { line.append(' '); } for (String columnName : columnNames) { String numberStr = ""; if (tagStats.getValue().get(columnName) != null) { numberStr += tagStats.getValue().get(columnName).size(); while (numberStr.length() < 5) { numberStr += ' '; } numberStr += "(" + getIntensityLevel(tagStats.getValue().get(columnName)) + ")"; } line.append(" | "); line.append(numberStr); for (int i = numberStr.length(); i < columnName.length(); i++) { line.append(' '); } } lines.add(line); } for (int i = 0; i < maxTagNameLength; i++) { System.out.print(' '); } for (String columnName : columnNames) { System.out.print(" | " + columnName); } System.out.println(); for (StringBuffer line : lines) { System.out.println(line); } } /** * */ private StringBuffer createBorderLine(int firstColumnWith, List columnNames) { StringBuffer line = new StringBuffer(); for (int i = 0; i < firstColumnWith; i++) { line.append('-'); } for (String columnName : columnNames) { line.append("-|-"); for (int j = 0; j < columnName.length(); j++) { line.append('-'); } } return line; } /** * */ private StringBuffer createDataLine(String lineName, int firstColumnWith, int[] values, List columnNames) { StringBuffer line = new StringBuffer(); line.append(lineName); for (int i = lineName.length(); i < firstColumnWith; i++) { line.append(' '); } for (int i = 0; i < values.length; i++) { String numberStr = "" + values[i]; line.append(" | "); line.append(numberStr); for (int j = numberStr.length(); j < columnNames.get(i).length(); j++) { line.append(' '); } } return line; } /** * */ private int getDuplicates(List allSmells) { int duplicateCount = 0; for (UsabilitySmell smell1 : allSmells) { if (smell1.getSmellingTask() != null) { for (UsabilitySmell smell2 : allSmells) { if ((smell2.getSmellingTask() != null) && (smell1.getSmellingTask() != smell2.getSmellingTask()) && (TaskTreeUtils.isChild(smell1.getSmellingTask(), smell2.getSmellingTask()))) { duplicateCount++; break; } } } } return duplicateCount; } /** * */ private int getIntensityLevel(List smellList) { if (smellList.size() <= 0) { return -1; } LinkedList smellsToConsider = new LinkedList<>(); // determine the smells with the highest intensity for (UsabilitySmell smell : smellList) { boolean added = false; ListIterator it = smellsToConsider.listIterator(); while (it.hasNext()) { if (it.next().getIntensity().getRatio() < smell.getIntensity().getRatio()) { it.previous(); it.add(smell); added = true; break; } } if (!added) { smellsToConsider.add(smell); } while (smellsToConsider.size() > 5) { smellsToConsider.removeLast(); } } // calculate the average intensity of the smells with the highest intensity int cummulativeIntensity = 0; for (UsabilitySmell smell : smellsToConsider) { cummulativeIntensity += smell.getIntensity().getRatio(); } return cummulativeIntensity / smellsToConsider.size(); } /* * (non-Javadoc) * * @see de.ugoe.cs.util.console.Command#help() */ @Override public String help() { return "usabilityStatistics []*"; } }