| /** |
| * Copyright 2006-2017 the original author or authors. |
| * |
| * 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 org.objenesis.tck; |
| |
| import org.objenesis.Objenesis; |
| |
| import java.io.PrintStream; |
| import java.util.*; |
| |
| /** |
| * Reports results from TCK as tabulated text, suitable for dumping to the console or a file and |
| * being read by a human. It can be reused to provide a summary reports of different candidates as |
| * long as the same <code>objenesisDescription</code> is not used twice. |
| * |
| * @author Joe Walnes |
| * @author Henri Tremblay |
| * @see TCK |
| * @see Reporter |
| */ |
| public class TextReporter implements Reporter { |
| |
| private static class Result { |
| |
| String objenesisDescription; |
| |
| String candidateDescription; |
| |
| boolean result; |
| |
| Exception exception; |
| |
| /** |
| * @param objenesisDescription Description of the tested Objenesis instance |
| * @param candidateDescription Description of the tested candidate |
| * @param result If the test is successful or not |
| * @param exception Exception that might have occured during the test |
| */ |
| public Result(String objenesisDescription, String candidateDescription, boolean result, |
| Exception exception) { |
| this.objenesisDescription = objenesisDescription; |
| this.candidateDescription = candidateDescription; |
| this.result = result; |
| this.exception = exception; |
| } |
| } |
| |
| private final PrintStream summary; |
| |
| private final PrintStream log; |
| |
| private long startTime; |
| |
| private long totalTime = 0; |
| |
| private int errorCount = 0; |
| |
| private SortedMap<String, Object> allCandidates = new TreeMap<String, Object>(); |
| |
| private SortedMap<String, Object> allInstantiators = new TreeMap<String, Object>(); |
| |
| private String currentObjenesis; |
| |
| private String currentCandidate; |
| |
| private Map<Object, Map<String, Result>> objenesisResults = new HashMap<Object, Map<String, Result>>(); |
| |
| private String platformDescription; |
| |
| /** |
| * @param summary Output of main report. |
| * @param log Any additional information, useful for diagnostics. |
| */ |
| public TextReporter(PrintStream summary, PrintStream log) { |
| this.summary = summary; |
| this.log = log; |
| } |
| |
| public int getErrorCount() { |
| return errorCount; |
| } |
| |
| public void startTests(String platformDescription, Map<String, Object> allCandidates, |
| Map<String, Object> allInstantiators) { |
| |
| // HT: in case the same reporter is reused, I'm guessing that it will |
| // always be the same platform |
| this.platformDescription = platformDescription; |
| this.allCandidates.putAll(allCandidates); |
| this.allInstantiators.putAll(allInstantiators); |
| |
| for(String desc : allInstantiators.keySet()) { |
| objenesisResults.put(desc, new HashMap<String, Result>()); |
| } |
| |
| startTime = System.currentTimeMillis(); |
| } |
| |
| public void startTest(String candidateDescription, String objenesisDescription) { |
| currentCandidate = candidateDescription; |
| currentObjenesis = objenesisDescription; |
| } |
| |
| public void result(boolean instantiatedObject) { |
| if(!instantiatedObject) { |
| errorCount++; |
| } |
| objenesisResults.get(currentObjenesis).put(currentCandidate, |
| new Result( |
| currentObjenesis, currentCandidate, instantiatedObject, null)); |
| } |
| |
| public void exception(Exception exception) { |
| |
| errorCount++; |
| |
| objenesisResults.get(currentObjenesis).put(currentCandidate, |
| new Result( |
| currentObjenesis, currentCandidate, false, exception)); |
| } |
| |
| public void endTest() { |
| } |
| |
| public void endTests() { |
| totalTime += System.currentTimeMillis() - startTime; |
| } |
| |
| /** |
| * Print the final summary report |
| * |
| * @param parentConstructorTest If the test checking that the none serializable constructor was called was successful |
| */ |
| public void printResult(boolean parentConstructorTest) { |
| // Platform |
| summary.println("Running TCK on platform: " + platformDescription); |
| summary.println(); |
| |
| // Instantiator implementations |
| summary.println("Instantiators used: "); |
| for(Map.Entry<String, Object> o : allInstantiators.entrySet()) { |
| String inst = ((Objenesis) o.getValue()).getInstantiatorOf(String.class).getClass() |
| .getSimpleName(); |
| summary.println(" " + o.getKey() + ": " + inst); |
| } |
| summary.println(); |
| |
| // Parent constructor special test |
| summary.println("Not serializable parent constructor called as expected: " |
| + (parentConstructorTest ? 'Y' : 'N')); |
| summary.println(); |
| |
| if(!parentConstructorTest) { |
| errorCount++; |
| } |
| |
| Set<String> instantiators = this.allInstantiators.keySet(); |
| Set<String> candidates = this.allCandidates.keySet(); |
| |
| int maxObjenesisWidth = lengthOfLongestStringIn(instantiators); |
| int maxCandidateWidth = lengthOfLongestStringIn(candidates); |
| |
| // Strategy used |
| summary.print(pad("", maxCandidateWidth) + ' '); |
| for(String desc : instantiators) { |
| summary.print(pad(desc, maxObjenesisWidth) + ' '); |
| } |
| summary.println(); |
| |
| List<Result> exceptions = new ArrayList<Result>(); |
| |
| // Candidates (and keep the exceptions meanwhile) |
| for(String candidateDesc : candidates) { |
| summary.print(pad(candidateDesc, maxCandidateWidth) + ' '); |
| |
| for(String instDesc : instantiators) { |
| Result result = objenesisResults.get(instDesc).get(candidateDesc); |
| if(result == null) { |
| summary.print(pad("N/A", maxObjenesisWidth) + " "); |
| } |
| else { |
| summary.print(pad(result.result ? "Y" : "n", maxObjenesisWidth) + " "); |
| |
| if(result.exception != null) { |
| exceptions.add(result); |
| } |
| } |
| } |
| summary.println(); |
| } |
| |
| summary.println(); |
| |
| // Final |
| if(errorCount != 0) { |
| |
| for(Result element : exceptions) { |
| log.println("--- Candidate '" + element.candidateDescription + "', Instantiator '" |
| + element.objenesisDescription + "' ---"); |
| element.exception.printStackTrace(log); |
| log.println(); |
| } |
| |
| log.println(); |
| |
| summary.println("--- FAILED: " + errorCount + " error(s) occured ---"); |
| } |
| else { |
| summary.println("--- SUCCESSFUL: TCK tests passed without errors in " + totalTime + " ms"); |
| } |
| |
| summary.println(); |
| } |
| |
| /** |
| * Return true if the reporter has registered some errors |
| * |
| * @return if there was errors during execution |
| */ |
| public boolean hasErrors() { |
| return errorCount != 0; |
| } |
| |
| private String pad(String text, int width) { |
| if(text.length() == width) { |
| return text; |
| } |
| else if(text.length() > width) { |
| return text.substring(0, width); |
| } |
| else { |
| StringBuilder padded = new StringBuilder(text); |
| while(padded.length() < width) { |
| padded.append(' '); |
| } |
| return padded.toString(); |
| } |
| } |
| |
| private int lengthOfLongestStringIn(Collection<String> descriptions) { |
| int result = 0; |
| for(Iterator<String> it = descriptions.iterator(); it.hasNext();) { |
| result = Math.max(result, it.next().length()); |
| } |
| return result; |
| } |
| } |