001/* 002 * Units of Measurement TCK 003 * Copyright (c) 2005-2018, Jean-Marie Dautelle, Werner Keil, Otavio Santana. 004 * 005 * All rights reserved. 006 * 007 * Redistribution and use in source and binary forms, with or without modification, 008 * are permitted provided that the following conditions are met: 009 * 010 * 1. Redistributions of source code must retain the above copyright notice, 011 * this list of conditions and the following disclaimer. 012 * 013 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions 014 * and the following disclaimer in the documentation and/or other materials provided with the distribution. 015 * 016 * 3. Neither the name of JSR-385 nor the names of its contributors may be used to endorse or promote products 017 * derived from this software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 021 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 023 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 026 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package tech.units.tck; 031 032import static tech.units.tck.util.TestUtils.SYS_PROPERTY_OUTPUT_DIR; 033import static tech.units.tck.util.TestUtils.SYS_PROPERTY_PROFILE; 034import static tech.units.tck.util.TestUtils.SYS_PROPERTY_REPORT_FILE; 035import static tech.units.tck.util.TestUtils.SYS_PROPERTY_VERBOSE; 036 037import java.io.File; 038import java.io.FileWriter; 039import java.io.IOException; 040import java.io.InputStream; 041import java.io.OutputStream; 042import java.io.PrintWriter; 043import java.io.StringWriter; 044import java.lang.reflect.Method; 045import java.util.ArrayList; 046import java.util.Arrays; 047import java.util.Collections; 048import java.util.HashSet; 049import java.util.List; 050import java.util.Set; 051 052import javax.lang.model.SourceVersion; 053import javax.tools.Tool; 054 055import org.testng.ITestResult; 056import org.testng.TestListenerAdapter; 057import org.testng.TestNG; 058import org.testng.annotations.Test; 059import org.testng.reporters.VerboseReporter; 060import org.testng.xml.XmlClass; 061import org.testng.xml.XmlSuite; 062import org.testng.xml.XmlTest; 063 064import tech.units.tck.tests.FundamentalTypesTest; 065import tech.units.tck.tests.format.UnitFormatTest; 066import tech.units.tck.tests.quantity.QuantityInterfaceTest; 067import tech.units.tck.tests.quantity.QuantityTypesTest; 068import tech.units.tck.tests.spi.ObtainingQuantiesTest; 069import tech.units.tck.tests.spi.ObtainingUnitsTest; 070import tech.units.tck.tests.spi.QuantityFactoryTest; 071import tech.units.tck.tests.spi.ServiceProviderTest; 072import tech.units.tck.tests.spi.ServicesTest; 073import tech.units.tck.tests.spi.SystemOfUnitsTest; 074import tech.units.tck.tests.unit.UnitConversionTest; 075import tech.units.tck.tests.unit.UnitDimensionTest; 076import tech.units.tck.tests.unit.UnitInterfaceTest; 077import tech.units.tck.util.TestGroups.Group; 078import tech.units.tck.util.TestGroups.Profile; 079import tech.uom.lib.common.function.Versioned; 080 081/** 082 * Main class for executing the JSR 385 TCK. 083 * 084 * @author <a href="mailto:units@catmedia.us">Werner Keil</a> 085 * @version 1.2, July 11, 2018 086 * @since 1.0 087 */ 088public class TCKRunner extends XmlSuite implements Tool, Versioned<String> { 089 090 /** 091 * 092 */ 093 private static final long serialVersionUID = 3189431432291353154L; 094 private static final String TCK_VERSION = "2.0.0-EDR"; 095 public static final String SPEC_ID = "JSR 385"; 096 public static final String SPEC_VERSION = "2.0.0"; 097 private final Profile profile; 098 099 public TCKRunner() { 100 setName(SPEC_ID + " - TCK " + TCK_VERSION); 101 final XmlTest test = new XmlTest(this); 102 profile = Profile.valueOf((System.getProperty(SYS_PROPERTY_PROFILE, 103 Profile.FULL.name()).toUpperCase())); 104 for (Group group : profile.getGroups()) { 105 test.addIncludedGroup(group.name()); 106 } 107 test.setName("TCK/Test Setup"); 108 final List<XmlClass> classes = new ArrayList<>(); 109 classes.add(new XmlClass(TCKSetup.class)); 110 classes.add(new XmlClass(FundamentalTypesTest.class)); 111 classes.add(new XmlClass(UnitInterfaceTest.class)); 112 classes.add(new XmlClass(UnitConversionTest.class)); 113 classes.add(new XmlClass(UnitDimensionTest.class)); 114 classes.add(new XmlClass(UnitFormatTest.class)); 115 classes.add(new XmlClass(QuantityInterfaceTest.class)); 116 classes.add(new XmlClass(QuantityTypesTest.class)); 117 classes.add(new XmlClass(QuantityFactoryTest.class)); 118 classes.add(new XmlClass(SystemOfUnitsTest.class)); 119 classes.add(new XmlClass(ServiceProviderTest.class)); 120 classes.add(new XmlClass(ServicesTest.class)); 121 classes.add(new XmlClass(ObtainingUnitsTest.class)); 122 classes.add(new XmlClass(ObtainingQuantiesTest.class)); 123 test.setXmlClasses(classes); 124 } 125 126 /** 127 * Main method to start the TCK. Optional arguments are: 128 * <ul> 129 * <li>-Dtech.units.tck.profile for defining the profile for TestNG groups (default: full).</li> 130 * <li>-Dtech.units.tck.outputDir for defining the output directory TestNG uses (default: 131 * ./target/tck-output).</li> 132 * <li>-Dtech.units.tck.verbose=true to enable TestNG verbose mode.</li> 133 * <li>-Dtech.units.tck.reportFile=targetFile.txt for defining the TCK result summary report 134 * target file (default: ./target/tck-results.txt).</li> 135 * </ul> 136 * 137 * @param args Optional arguments to control TCK execution 138 */ 139 @Override 140 public int run(InputStream in, OutputStream out, OutputStream err, String... args) { 141 System.out.println("-- " + SPEC_ID + " TCK started --"); 142 System.out.println("Profile: " + profile.getDescription()); 143 final List<XmlSuite> suites = new ArrayList<>(); 144 suites.add(new TCKRunner()); 145 final TestNG tng = new TestNG(); 146 tng.setXmlSuites(suites); 147 String outDir = System.getProperty(SYS_PROPERTY_OUTPUT_DIR, "./target/tck-output"); 148 tng.setOutputDirectory(outDir); 149 String verbose = System.getProperty(SYS_PROPERTY_VERBOSE); 150 if ("true".equalsIgnoreCase(verbose)) { 151 tng.addListener(new VerboseReporter()); 152 } 153 String reportFile = System.getProperty(SYS_PROPERTY_REPORT_FILE, "./target/tck-results.txt"); 154 final File file = new File(reportFile); 155 final Reporter rep = new Reporter(profile, file); 156 System.out.println("Writing to file " + file.getAbsolutePath() + " ..."); 157 tng.addListener(rep); 158 tng.run(); 159 rep.writeSummary(); 160 System.out.println("-- " + SPEC_ID + " TCK finished --"); 161 return 0; 162 } 163 164 @Override 165 public String getVersion() { 166 return TCK_VERSION; 167 } 168 169 @Override 170 public final Set<SourceVersion> getSourceVersions() { 171 return Collections.unmodifiableSet(new HashSet<>(Arrays.asList(new SourceVersion[] {SourceVersion.RELEASE_5, SourceVersion.RELEASE_6, SourceVersion.RELEASE_7}))); 172 } 173 174 public static final void main(String... args) { 175 if (args.length > 0 && "-version".equalsIgnoreCase(args[0])) { 176 showVersion(); 177 } else { // (args.length > 0 && "-help".equalsIgnoreCase(args[0])) { 178 showHelp(); 179 } /* 180 * else { final Tool runner = new TCKRunner(); runner.run(System.in, System.out, 181 * System.err, new String[]{TCKRunner.class.getName()}); } 182 */ 183 } 184 185 private static void showHelp() { 186 final StringWriter consoleWriter = new StringWriter(1000); 187 consoleWriter.write("*****************************************************************************************\n"); 188 consoleWriter.write("**** " + SPEC_ID + " - Units of Measurement, Technical Compatibility Kit, version " + TCK_VERSION + "\n"); 189 consoleWriter.write("*****************************************************************************************\n\n"); 190 consoleWriter.write("Usage:\n"); 191 consoleWriter.write("To run the TCK, execute TestNG with Maven or a similar build tool.\n\n"); 192 consoleWriter.write("E.g. by running \"mvn test\" with this POM.\n\n"); 193 consoleWriter.write("You may use the following system properties to override the default behavior:\n"); 194 consoleWriter.write("-D" + SYS_PROPERTY_PROFILE + "=<profile>" + " to select the desired profile from these available " + SPEC_ID + " profiles:\n"); 195 for (Profile p : Profile.values()) { 196 consoleWriter.write(" " + p.name() + " - " + p.getDescription() + (p.isDefault() ? " (the default profile)\n" : "\n")); 197 } 198 consoleWriter.write("-D" + SYS_PROPERTY_OUTPUT_DIR + "=<directory> to set the output directory of your choice.\n"); 199 consoleWriter.write("-D" + SYS_PROPERTY_REPORT_FILE + "=<file> to set the TCK result file directory of your choice.\n"); 200 consoleWriter.write("-D" + SYS_PROPERTY_VERBOSE + "=true/false to toggle the TCK verbose option for additional test output. The default is \"false\"\n"); 201 System.out.println(consoleWriter); 202 } 203 204 private static void showVersion() { 205 System.out.println(SPEC_ID + " - Units of Measurement, Technical Compatibility Kit, version \"" + TCK_VERSION + "\"\n"); 206 } 207 208 public static final class Reporter extends TestListenerAdapter { 209 private int count = 0; 210 private int skipped = 0; 211 private int failed = 0; 212 private int success = 0; 213 private final StringWriter consoleWriter = new StringWriter(3000); 214 private FileWriter fileWriter; 215 216 public Reporter(Profile profile, File file) { 217 try { 218 if (!file.exists()) { 219 file.createNewFile(); 220 } 221 fileWriter = new FileWriter(file); 222 fileWriter.write("*****************************************************************************************\n"); 223 fileWriter.write("**** " + SPEC_ID + " - Units of Measurement, Technical Compatibility Kit, version " + TCK_VERSION + "\n"); 224 fileWriter.write("*****************************************************************************************\n\n"); 225 fileWriter.write("Executed on " + new java.util.Date() + "\n"); 226 fileWriter.write("Using " + profile.getDescription() + " profile\n\n"); 227 // System.out: 228 consoleWriter.write("*****************************************************************************************\n"); 229 consoleWriter.write("**** " + SPEC_ID + " - Units of Measurement, Technical Compatibility Kit, version " + TCK_VERSION + "\n"); 230 consoleWriter.write("*****************************************************************************************\n\n"); 231 consoleWriter.write("Executed on " + new java.util.Date() + "\n"); 232 consoleWriter.write("Using " + profile.getDescription() + " profile\n\n"); 233 } catch (IOException e) { 234 e.printStackTrace(); 235 System.exit(-1); 236 } 237 } 238 239 @Override 240 public void onTestFailure(ITestResult tr) { 241 failed++; 242 count++; 243 String location = tr.getTestClass().getRealClass().getSimpleName() + '#' + tr.getMethod().getMethodName(); 244 try { 245 Method realTestMethod = tr.getMethod().getConstructorOrMethod().getMethod(); 246 Test testAnnot = realTestMethod.getAnnotation(Test.class); 247 if (testAnnot != null && testAnnot.description() != null && !testAnnot.description().isEmpty()) { 248 if (tr.getThrowable() != null) { 249 StringWriter sw = new StringWriter(); 250 PrintWriter w = new PrintWriter(sw); 251 tr.getThrowable().printStackTrace(w); 252 w.flush(); 253 log("[FAILED] " + testAnnot.description() + "(" + location + "):\n" + sw.toString()); 254 } else { 255 log("[FAILED] " + testAnnot.description() + "(" + location + ")"); 256 } 257 } else { 258 if (tr.getThrowable() != null) { 259 StringWriter sw = new StringWriter(); 260 PrintWriter w = new PrintWriter(sw); 261 tr.getThrowable().printStackTrace(w); 262 w.flush(); 263 log("[FAILED] " + location + ":\n" + sw.toString()); 264 } else { 265 log("[FAILED] " + location); 266 } 267 } 268 } catch (IOException e) { 269 throw new IllegalStateException("IO Error", e); 270 } 271 } 272 273 @Override 274 public void onTestSkipped(ITestResult tr) { 275 skipped++; 276 count++; 277 String location = tr.getTestClass().getRealClass().getSimpleName() + '#' + tr.getMethod().getMethodName(); 278 try { 279 Method realTestMethod = tr.getMethod().getConstructorOrMethod().getMethod(); 280 Test specAssert = realTestMethod.getAnnotation(Test.class); 281 if (specAssert != null && specAssert.description() != null && !specAssert.description().isEmpty()) { 282 log("[SKIPPED] " + specAssert.description() + "(" + location + ")"); 283 } else { 284 log("[SKIPPED] " + location); 285 } 286 } catch (IOException e) { 287 throw new IllegalStateException("IO Error", e); 288 } 289 } 290 291 @Override 292 public void onTestSuccess(ITestResult tr) { 293 success++; 294 count++; 295 String location = tr.getTestClass().getRealClass().getSimpleName() + '#' + tr.getMethod().getMethodName(); 296 try { 297 Method realTestMethod = tr.getMethod().getConstructorOrMethod().getMethod(); 298 Test specAssert = realTestMethod.getAnnotation(Test.class); 299 if (specAssert != null && specAssert.description() != null && !specAssert.description().isEmpty()) { 300 log("[SUCCESS] " + specAssert.description() + "(" + location + ")"); 301 } else { 302 log("[SUCCESS] " + location); 303 } 304 } catch (IOException e) { 305 throw new IllegalStateException("IO Error", e); 306 } 307 } 308 309 private void log(String text) throws IOException { 310 fileWriter.write(text); 311 fileWriter.write('\n'); 312 consoleWriter.write(text); 313 consoleWriter.write('\n'); 314 } 315 316 public void writeSummary() { 317 try { 318 log("\n" + SPEC_ID + " TCK version " + TCK_VERSION + " Summary"); 319 log("-------------------------------------------------------"); 320 log("\nTOTAL TESTS EXECUTED : " + count); 321 log("TOTAL TESTS SKIPPED : " + skipped); 322 log("TOTAL TESTS SUCCESS : " + success); 323 log("TOTAL TESTS FAILED : " + failed); 324 fileWriter.flush(); 325 fileWriter.close(); 326 consoleWriter.flush(); 327 System.out.println(); 328 System.out.println(consoleWriter); 329 } catch (IOException e) { 330 throw new IllegalStateException("IO Error", e); 331 } 332 } 333 } 334}