1 | // Copyright 2012 Georg-August-Universität Göttingen, Germany
|
---|
2 | //
|
---|
3 | // Licensed under the Apache License, Version 2.0 (the "License");
|
---|
4 | // you may not use this file except in compliance with the License.
|
---|
5 | // You may obtain a copy of the License at
|
---|
6 | //
|
---|
7 | // http://www.apache.org/licenses/LICENSE-2.0
|
---|
8 | //
|
---|
9 | // Unless required by applicable law or agreed to in writing, software
|
---|
10 | // distributed under the License is distributed on an "AS IS" BASIS,
|
---|
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
---|
12 | // See the License for the specific language governing permissions and
|
---|
13 | // limitations under the License.
|
---|
14 |
|
---|
15 | package de.ugoe.cs.autoquest.commands.usability;
|
---|
16 |
|
---|
17 | import java.util.ArrayList;
|
---|
18 | import java.util.Collections;
|
---|
19 | import java.util.HashMap;
|
---|
20 | import java.util.HashSet;
|
---|
21 | import java.util.LinkedList;
|
---|
22 | import java.util.List;
|
---|
23 | import java.util.ListIterator;
|
---|
24 | import java.util.Map;
|
---|
25 | import java.util.Set;
|
---|
26 | import java.util.TreeMap;
|
---|
27 | import java.util.TreeSet;
|
---|
28 |
|
---|
29 | import com.google.common.collect.Sets;
|
---|
30 |
|
---|
31 | import de.ugoe.cs.autoquest.CommandHelpers;
|
---|
32 | import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
|
---|
33 | import de.ugoe.cs.autoquest.tasktrees.treeifc.TaskTreeUtils;
|
---|
34 | import de.ugoe.cs.autoquest.usability.UsabilityEvaluationResult;
|
---|
35 | import de.ugoe.cs.autoquest.usability.UsabilitySmell;
|
---|
36 | import de.ugoe.cs.autoquest.usability.UsabilitySmell.ManualLabel;
|
---|
37 | import de.ugoe.cs.util.console.Command;
|
---|
38 | import de.ugoe.cs.util.console.GlobalDataContainer;
|
---|
39 |
|
---|
40 | /**
|
---|
41 | * <p>
|
---|
42 | * TODO comment
|
---|
43 | * </p>
|
---|
44 | *
|
---|
45 | * @author Patrick Harms
|
---|
46 | * @version 1.0
|
---|
47 | */
|
---|
48 | public class CMDusabilityStatistics implements Command {
|
---|
49 |
|
---|
50 | private static int COUNT = 0;
|
---|
51 | private static int DUPLICATES = 1;
|
---|
52 | private static int INTENSITY_LVL = 2;
|
---|
53 | private static int TRUE_POSITIVE = 3;
|
---|
54 | private static int TRUE_POSITIVE_DUPLICATES = 4;
|
---|
55 | private static int TRUE_POSITIVE_INTENSITY_LVL = 5;
|
---|
56 | private static int UNASSESSED = 6;
|
---|
57 | private static int MP_COUNT = 7;
|
---|
58 | private static int MP_DUPLICATES = 8;
|
---|
59 | private static int MP_INTENSITY_LVL = 9;
|
---|
60 | private static int MP_TRUE_POSITIVE = 10;
|
---|
61 | private static int MP_TRUE_POSITIVE_DUPLICATES = 11;
|
---|
62 | private static int MP_TRUE_POSITIVE_INTENSITY_LVL = 12;
|
---|
63 | private static int MP_UNASSESSED = 13;
|
---|
64 |
|
---|
65 | /*
|
---|
66 | * (non-Javadoc)
|
---|
67 | *
|
---|
68 | * @see de.ugoe.cs.util.console.Command#run(java.util.List)
|
---|
69 | */
|
---|
70 | @Override
|
---|
71 | public void run(List<Object> parameters) {
|
---|
72 | List<String> usabilityResultNames = new ArrayList<>(parameters.size());
|
---|
73 | try {
|
---|
74 | for (Object parameter : parameters) {
|
---|
75 | usabilityResultNames.add((String) parameter);
|
---|
76 | }
|
---|
77 | }
|
---|
78 | catch (Exception e) {
|
---|
79 | throw new IllegalArgumentException();
|
---|
80 | }
|
---|
81 |
|
---|
82 | List<UsabilityEvaluationResult> usabilityResults = new ArrayList<>(usabilityResultNames.size());
|
---|
83 |
|
---|
84 | for (String usabilityResultName : usabilityResultNames) {
|
---|
85 | Object dataObject = GlobalDataContainer.getInstance().getData(usabilityResultName);
|
---|
86 | if (dataObject == null) {
|
---|
87 | CommandHelpers.objectNotFoundMessage(usabilityResultName);
|
---|
88 | return;
|
---|
89 | }
|
---|
90 | if (!(dataObject instanceof UsabilityEvaluationResult)) {
|
---|
91 | CommandHelpers.objectNotType(usabilityResultName, "UsabilityEvaluationResult");
|
---|
92 | return;
|
---|
93 | }
|
---|
94 |
|
---|
95 | usabilityResults.add((UsabilityEvaluationResult) dataObject);
|
---|
96 | }
|
---|
97 |
|
---|
98 | // analyse all smells
|
---|
99 | Map<String, List<UsabilitySmell>> allSmells = new TreeMap<>();
|
---|
100 | Map<String, Set<ISequence>> mostProminentSequences = new TreeMap<>();
|
---|
101 | Set<String> smellTypes = new TreeSet<>();
|
---|
102 |
|
---|
103 | for (int i = 0; i < usabilityResults.size(); i++) {
|
---|
104 | String usabilityResultName = usabilityResultNames.get(i);
|
---|
105 | allSmells.put(usabilityResultName, usabilityResults.get(i).getAllSmells());
|
---|
106 |
|
---|
107 | for (UsabilitySmell smell : usabilityResults.get(i).getAllSmells()) {
|
---|
108 | smellTypes.add(smell.getBriefDescription());
|
---|
109 | }
|
---|
110 |
|
---|
111 | if (!mostProminentSequences.containsKey(usabilityResultName)) {
|
---|
112 | mostProminentSequences.put(usabilityResultName,
|
---|
113 | TaskTreeUtils.getMostProminentTasks
|
---|
114 | (usabilityResults.get(i).getTaskModel()));
|
---|
115 | }
|
---|
116 | }
|
---|
117 |
|
---|
118 | analyseAndDump("all smells", allSmells, mostProminentSequences);
|
---|
119 |
|
---|
120 | for (String smellType : smellTypes) {
|
---|
121 | Map<String, List<UsabilitySmell>> relevantSmells = new TreeMap<>();
|
---|
122 | for (int i = 0; i < usabilityResults.size(); i++) {
|
---|
123 | List<UsabilitySmell> smellList = new LinkedList<>();
|
---|
124 |
|
---|
125 | for (UsabilitySmell smell : usabilityResults.get(i).getAllSmells()) {
|
---|
126 | if (smellType.equals(smell.getBriefDescription())) {
|
---|
127 | smellList.add(smell);
|
---|
128 | }
|
---|
129 | }
|
---|
130 |
|
---|
131 | relevantSmells.put(usabilityResultNames.get(i), smellList);
|
---|
132 | }
|
---|
133 |
|
---|
134 | analyseAndDump(smellType, relevantSmells, mostProminentSequences);
|
---|
135 | }
|
---|
136 | }
|
---|
137 |
|
---|
138 | /**
|
---|
139 | *
|
---|
140 | */
|
---|
141 | private void analyseAndDump(String setName,
|
---|
142 | Map<String, List<UsabilitySmell>> smells,
|
---|
143 | Map<String, Set<ISequence>> mostProminentSequences)
|
---|
144 | {
|
---|
145 | System.out.println("\n\n###################################################################");
|
---|
146 | System.out.println("usability statistics for " + setName + "\n");
|
---|
147 |
|
---|
148 | // determine statistics
|
---|
149 | int[][] basicResultData = new int[14][];
|
---|
150 |
|
---|
151 | for (int i = 0; i < basicResultData.length; i++) {
|
---|
152 | basicResultData[i] = new int[smells.size()];
|
---|
153 | }
|
---|
154 |
|
---|
155 | Map<String, Map<String, List<UsabilitySmell>>> tagCounters = new TreeMap<>();
|
---|
156 | List<String> columnNames = new LinkedList<>();
|
---|
157 |
|
---|
158 |
|
---|
159 | int index = 0;
|
---|
160 | for (Map.Entry<String, List<UsabilitySmell>> smellGroup : smells.entrySet()) {
|
---|
161 | String usabilityResultName = smellGroup.getKey();
|
---|
162 | columnNames.add(usabilityResultName);
|
---|
163 |
|
---|
164 | basicResultData[COUNT][index] = smellGroup.getValue().size();
|
---|
165 | basicResultData[DUPLICATES][index] = getDuplicates(smellGroup.getValue());
|
---|
166 | basicResultData[INTENSITY_LVL][index] = getIntensityLevel(smellGroup.getValue());
|
---|
167 |
|
---|
168 | List<UsabilitySmell> truePositives = new LinkedList<>();
|
---|
169 | List<UsabilitySmell> unassessed = new LinkedList<>();
|
---|
170 |
|
---|
171 | List<UsabilitySmell> mps = new LinkedList<>();
|
---|
172 | List<UsabilitySmell> mpTruePositives = new LinkedList<>();
|
---|
173 | List<UsabilitySmell> mpUnassessed = new LinkedList<>();
|
---|
174 |
|
---|
175 | for (UsabilitySmell smell : smellGroup.getValue()) {
|
---|
176 | if (smell.getManualLabel() == ManualLabel.TRUE_POSITIVE) {
|
---|
177 | truePositives.add(smell);
|
---|
178 | }
|
---|
179 | else if (smell.getManualLabel() == ManualLabel.UNCHECKED) {
|
---|
180 | unassessed.add(smell);
|
---|
181 | }
|
---|
182 |
|
---|
183 | if (mostProminentSequences.get(smellGroup.getKey()).contains(smell.getSmellingTask())) {
|
---|
184 | mps.add(smell);
|
---|
185 |
|
---|
186 | if (smell.getManualLabel() == ManualLabel.TRUE_POSITIVE) {
|
---|
187 | mpTruePositives.add(smell);
|
---|
188 | }
|
---|
189 | else if (smell.getManualLabel() == ManualLabel.UNCHECKED) {
|
---|
190 | mpUnassessed.add(smell);
|
---|
191 | }
|
---|
192 | }
|
---|
193 |
|
---|
194 | Set<String> tagList = new HashSet<>(smell.getTags());
|
---|
195 |
|
---|
196 | Set<Set<String>> powerSetTags = Sets.powerSet(tagList);
|
---|
197 |
|
---|
198 | for (Set<String> tagSet : powerSetTags) {
|
---|
199 | List<String> tags = new LinkedList<>(tagSet);
|
---|
200 | //{List<String> tags = new LinkedList<>(tagList);
|
---|
201 | Collections.sort(tags);
|
---|
202 | String tagCombinationKey = tags.toString();
|
---|
203 |
|
---|
204 | Map<String, List<UsabilitySmell>> counterMap = tagCounters.get(tagCombinationKey);
|
---|
205 |
|
---|
206 | if (counterMap == null) {
|
---|
207 | counterMap = new HashMap<>();
|
---|
208 | tagCounters.put(tagCombinationKey, counterMap);
|
---|
209 | }
|
---|
210 |
|
---|
211 | List<UsabilitySmell> smellWithSameTagCombination =
|
---|
212 | counterMap.get(usabilityResultName);
|
---|
213 |
|
---|
214 | if (smellWithSameTagCombination == null) {
|
---|
215 | smellWithSameTagCombination = new LinkedList<>();
|
---|
216 | counterMap.put(usabilityResultName, smellWithSameTagCombination);
|
---|
217 | }
|
---|
218 |
|
---|
219 | smellWithSameTagCombination.add(smell);
|
---|
220 | }
|
---|
221 | }
|
---|
222 |
|
---|
223 | basicResultData[TRUE_POSITIVE][index] = truePositives.size();
|
---|
224 | basicResultData[TRUE_POSITIVE_DUPLICATES][index] = getDuplicates(truePositives);
|
---|
225 | basicResultData[TRUE_POSITIVE_INTENSITY_LVL][index] = getIntensityLevel(truePositives);
|
---|
226 | basicResultData[UNASSESSED][index] = unassessed.size();
|
---|
227 |
|
---|
228 | basicResultData[MP_COUNT][index] = mps.size();
|
---|
229 | basicResultData[MP_DUPLICATES][index] = getDuplicates(mps);
|
---|
230 | basicResultData[MP_INTENSITY_LVL][index] = getIntensityLevel(mps);
|
---|
231 | basicResultData[MP_TRUE_POSITIVE][index] = mpTruePositives.size();
|
---|
232 | basicResultData[MP_TRUE_POSITIVE_DUPLICATES][index] = getDuplicates(mpTruePositives);
|
---|
233 | basicResultData[MP_TRUE_POSITIVE_INTENSITY_LVL][index] = getIntensityLevel(mpTruePositives);
|
---|
234 | basicResultData[MP_UNASSESSED][index] = mpUnassessed.size();
|
---|
235 |
|
---|
236 | index++;
|
---|
237 | }
|
---|
238 |
|
---|
239 | int maxTagNameLength = 0;
|
---|
240 | for (String tagCombination : tagCounters.keySet()) {
|
---|
241 | maxTagNameLength = Math.max(maxTagNameLength, tagCombination.length());
|
---|
242 | }
|
---|
243 |
|
---|
244 | maxTagNameLength = Math.max(maxTagNameLength, " intensity level".length());
|
---|
245 |
|
---|
246 | List<StringBuffer> lines = new LinkedList<>();
|
---|
247 |
|
---|
248 | lines.add(createBorderLine(maxTagNameLength, columnNames));
|
---|
249 | lines.add(new StringBuffer("overall"));
|
---|
250 | lines.add(createDataLine(" count", maxTagNameLength, basicResultData[COUNT], columnNames));
|
---|
251 | lines.add(createDataLine(" duplicates", maxTagNameLength, basicResultData[DUPLICATES], columnNames));
|
---|
252 | lines.add(createDataLine(" intensity level", maxTagNameLength, basicResultData[INTENSITY_LVL], columnNames));
|
---|
253 | lines.add(createDataLine(" true positives", maxTagNameLength, basicResultData[TRUE_POSITIVE], columnNames));
|
---|
254 | lines.add(createDataLine(" duplicates", maxTagNameLength, basicResultData[TRUE_POSITIVE_DUPLICATES], columnNames));
|
---|
255 | lines.add(createDataLine(" intensity level", maxTagNameLength, basicResultData[TRUE_POSITIVE_INTENSITY_LVL], columnNames));
|
---|
256 | lines.add(createDataLine(" unassessed", maxTagNameLength, basicResultData[UNASSESSED], columnNames));
|
---|
257 | lines.add(createBorderLine(maxTagNameLength, columnNames));
|
---|
258 | lines.add(new StringBuffer("most prominent"));
|
---|
259 | lines.add(createDataLine(" count", maxTagNameLength, basicResultData[MP_COUNT], columnNames));
|
---|
260 | lines.add(createDataLine(" duplicates", maxTagNameLength, basicResultData[MP_DUPLICATES], columnNames));
|
---|
261 | lines.add(createDataLine(" intensity level", maxTagNameLength, basicResultData[MP_INTENSITY_LVL], columnNames));
|
---|
262 | lines.add(createDataLine(" true positives", maxTagNameLength, basicResultData[MP_TRUE_POSITIVE], columnNames));
|
---|
263 | lines.add(createDataLine(" duplicates", maxTagNameLength, basicResultData[MP_TRUE_POSITIVE_DUPLICATES], columnNames));
|
---|
264 | lines.add(createDataLine(" intensity level", maxTagNameLength, basicResultData[MP_TRUE_POSITIVE_INTENSITY_LVL], columnNames));
|
---|
265 | lines.add(createDataLine(" unassessed", maxTagNameLength, basicResultData[MP_UNASSESSED], columnNames));
|
---|
266 | lines.add(createBorderLine(maxTagNameLength, columnNames));
|
---|
267 |
|
---|
268 | for (Map.Entry<String, Map<String, List<UsabilitySmell>>> tagStats : tagCounters.entrySet()) {
|
---|
269 | StringBuffer line = new StringBuffer();
|
---|
270 | line.append(tagStats.getKey());
|
---|
271 |
|
---|
272 | for (int i = tagStats.getKey().length(); i < maxTagNameLength; i++) {
|
---|
273 | line.append(' ');
|
---|
274 | }
|
---|
275 |
|
---|
276 | for (String columnName : columnNames) {
|
---|
277 | String numberStr = "";
|
---|
278 |
|
---|
279 | if (tagStats.getValue().get(columnName) != null) {
|
---|
280 | numberStr += tagStats.getValue().get(columnName).size();
|
---|
281 |
|
---|
282 | while (numberStr.length() < 5) {
|
---|
283 | numberStr += ' ';
|
---|
284 | }
|
---|
285 |
|
---|
286 | numberStr += "(" + getIntensityLevel(tagStats.getValue().get(columnName)) + ")";
|
---|
287 | }
|
---|
288 |
|
---|
289 | line.append(" | ");
|
---|
290 | line.append(numberStr);
|
---|
291 |
|
---|
292 | for (int i = numberStr.length(); i < columnName.length(); i++) {
|
---|
293 | line.append(' ');
|
---|
294 | }
|
---|
295 | }
|
---|
296 |
|
---|
297 | lines.add(line);
|
---|
298 | }
|
---|
299 |
|
---|
300 | for (int i = 0; i < maxTagNameLength; i++) {
|
---|
301 | System.out.print(' ');
|
---|
302 | }
|
---|
303 |
|
---|
304 | for (String columnName : columnNames) {
|
---|
305 | System.out.print(" | " + columnName);
|
---|
306 | }
|
---|
307 |
|
---|
308 | System.out.println();
|
---|
309 |
|
---|
310 | for (StringBuffer line : lines) {
|
---|
311 | System.out.println(line);
|
---|
312 | }
|
---|
313 | }
|
---|
314 |
|
---|
315 | /**
|
---|
316 | *
|
---|
317 | */
|
---|
318 | private StringBuffer createBorderLine(int firstColumnWith, List<String> columnNames) {
|
---|
319 | StringBuffer line = new StringBuffer();
|
---|
320 |
|
---|
321 | for (int i = 0; i < firstColumnWith; i++) {
|
---|
322 | line.append('-');
|
---|
323 | }
|
---|
324 |
|
---|
325 | for (String columnName : columnNames) {
|
---|
326 | line.append("-|-");
|
---|
327 | for (int j = 0; j < columnName.length(); j++) {
|
---|
328 | line.append('-');
|
---|
329 | }
|
---|
330 | }
|
---|
331 |
|
---|
332 | return line;
|
---|
333 | }
|
---|
334 |
|
---|
335 | /**
|
---|
336 | *
|
---|
337 | */
|
---|
338 | private StringBuffer createDataLine(String lineName,
|
---|
339 | int firstColumnWith,
|
---|
340 | int[] values,
|
---|
341 | List<String> columnNames)
|
---|
342 | {
|
---|
343 | StringBuffer line = new StringBuffer();
|
---|
344 |
|
---|
345 | line.append(lineName);
|
---|
346 |
|
---|
347 | for (int i = lineName.length(); i < firstColumnWith; i++) {
|
---|
348 | line.append(' ');
|
---|
349 | }
|
---|
350 |
|
---|
351 | for (int i = 0; i < values.length; i++) {
|
---|
352 | String numberStr = "" + values[i];
|
---|
353 |
|
---|
354 | line.append(" | ");
|
---|
355 | line.append(numberStr);
|
---|
356 |
|
---|
357 | for (int j = numberStr.length(); j < columnNames.get(i).length(); j++) {
|
---|
358 | line.append(' ');
|
---|
359 | }
|
---|
360 | }
|
---|
361 |
|
---|
362 | return line;
|
---|
363 | }
|
---|
364 |
|
---|
365 | /**
|
---|
366 | *
|
---|
367 | */
|
---|
368 | private int getDuplicates(List<UsabilitySmell> allSmells) {
|
---|
369 | int duplicateCount = 0;
|
---|
370 |
|
---|
371 | for (UsabilitySmell smell1 : allSmells) {
|
---|
372 | if (smell1.getSmellingTask() != null) {
|
---|
373 | for (UsabilitySmell smell2 : allSmells) {
|
---|
374 | if ((smell2.getSmellingTask() != null) &&
|
---|
375 | (smell1.getSmellingTask() != smell2.getSmellingTask()) &&
|
---|
376 | (TaskTreeUtils.isChild(smell1.getSmellingTask(), smell2.getSmellingTask())))
|
---|
377 | {
|
---|
378 | duplicateCount++;
|
---|
379 | break;
|
---|
380 | }
|
---|
381 | }
|
---|
382 | }
|
---|
383 | }
|
---|
384 |
|
---|
385 | return duplicateCount;
|
---|
386 | }
|
---|
387 |
|
---|
388 | /**
|
---|
389 | *
|
---|
390 | */
|
---|
391 | private int getIntensityLevel(List<UsabilitySmell> smellList) {
|
---|
392 | if (smellList.size() <= 0) {
|
---|
393 | return -1;
|
---|
394 | }
|
---|
395 |
|
---|
396 | LinkedList<UsabilitySmell> smellsToConsider = new LinkedList<>();
|
---|
397 |
|
---|
398 | // determine the smells with the highest intensity
|
---|
399 | for (UsabilitySmell smell : smellList) {
|
---|
400 | boolean added = false;
|
---|
401 | ListIterator<UsabilitySmell> it = smellsToConsider.listIterator();
|
---|
402 |
|
---|
403 | while (it.hasNext()) {
|
---|
404 | if (it.next().getIntensity().getRatio() < smell.getIntensity().getRatio()) {
|
---|
405 | it.previous();
|
---|
406 | it.add(smell);
|
---|
407 | added = true;
|
---|
408 | break;
|
---|
409 | }
|
---|
410 | }
|
---|
411 |
|
---|
412 | if (!added) {
|
---|
413 | smellsToConsider.add(smell);
|
---|
414 | }
|
---|
415 |
|
---|
416 | while (smellsToConsider.size() > 5) {
|
---|
417 | smellsToConsider.removeLast();
|
---|
418 | }
|
---|
419 | }
|
---|
420 |
|
---|
421 | // calculate the average intensity of the smells with the highest intensity
|
---|
422 | int cummulativeIntensity = 0;
|
---|
423 | for (UsabilitySmell smell : smellsToConsider) {
|
---|
424 | cummulativeIntensity += smell.getIntensity().getRatio();
|
---|
425 | }
|
---|
426 |
|
---|
427 | return cummulativeIntensity / smellsToConsider.size();
|
---|
428 | }
|
---|
429 | /*
|
---|
430 | * (non-Javadoc)
|
---|
431 | *
|
---|
432 | * @see de.ugoe.cs.util.console.Command#help()
|
---|
433 | */
|
---|
434 | @Override
|
---|
435 | public String help() {
|
---|
436 | return "usabilityStatistics [<usabilityEvaluationResultName>]*";
|
---|
437 | }
|
---|
438 |
|
---|
439 | }
|
---|