001/* 002 * Units of Measurement TCK 003 * Copyright © 2005-2019, 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.QuantityFormatTest; 066import tech.units.tck.tests.format.UnitFormatTest; 067import tech.units.tck.tests.quantity.QuantityInterfaceTest; 068import tech.units.tck.tests.quantity.QuantityTypesTest; 069import tech.units.tck.tests.spi.ObtainingQuantiesTest; 070import tech.units.tck.tests.spi.ObtainingUnitsTest; 071import tech.units.tck.tests.spi.QuantityFactoryTest; 072import tech.units.tck.tests.spi.ServiceProviderTest; 073import tech.units.tck.tests.spi.ServicesTest; 074import tech.units.tck.tests.spi.SystemOfUnitsTest; 075import tech.units.tck.tests.unit.UnitConversionTest; 076import tech.units.tck.tests.unit.UnitDimensionTest; 077import tech.units.tck.tests.unit.UnitInterfaceTest; 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:[email protected]">Werner Keil</a> 085 * @version 1.6, May 12, 2019 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-PRD"; 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 (String group : profile.getGroups()) { 105 test.addIncludedGroup(group); 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(QuantityInterfaceTest.class)); 115 classes.add(new XmlClass(QuantityTypesTest.class)); 116 classes.add(new XmlClass(UnitFormatTest.class)); 117 classes.add(new XmlClass(QuantityFormatTest.class)); 118 classes.add(new XmlClass(QuantityFactoryTest.class)); 119 classes.add(new XmlClass(SystemOfUnitsTest.class)); 120 classes.add(new XmlClass(ServiceProviderTest.class)); 121 classes.add(new XmlClass(ServicesTest.class)); 122 classes.add(new XmlClass(ObtainingUnitsTest.class)); 123 classes.add(new XmlClass(ObtainingQuantiesTest.class)); 124 test.setXmlClasses(classes); 125 } 126 127 /** 128 * Main method to start the TCK. Optional arguments are: 129 * <ul> 130 * <li>-Dtech.units.tck.profile for defining the profile for TestNG groups (default: full).</li> 131 * <li>-Dtech.units.tck.outputDir for defining the output directory TestNG uses (default: 132 * ./target/tck-output).</li> 133 * <li>-Dtech.units.tck.verbose=true to enable TestNG verbose mode.</li> 134 * <li>-Dtech.units.tck.reportFile=targetFile.txt for defining the TCK result summary report 135 * target file (default: ./target/tck-results.txt).</li> 136 * </ul> 137 * 138 * @param args Optional arguments to control TCK execution 139 */ 140 @SuppressWarnings("deprecation") 141 @Override 142 public int run(InputStream in, OutputStream out, OutputStream err, String... args) { 143 System.out.println("-- " + SPEC_ID + " TCK started --"); 144 System.out.println("Profile: " + profile.getDescription()); 145 final List<XmlSuite> suites = new ArrayList<>(); 146 suites.add(new TCKRunner()); 147 final TestNG tng = new TestNG(); 148 tng.setXmlSuites(suites); 149 String outDir = System.getProperty(SYS_PROPERTY_OUTPUT_DIR, "./target/tck-output"); 150 tng.setOutputDirectory(outDir); 151 String verbose = System.getProperty(SYS_PROPERTY_VERBOSE); 152 if ("true".equalsIgnoreCase(verbose)) { 153 tng.addListener(new VerboseReporter("[VerboseUoM] ")); 154 } 155 String reportFile = System.getProperty(SYS_PROPERTY_REPORT_FILE, "./target/tck-results.txt"); 156 final File file = new File(reportFile); 157 final Reporter rep = new Reporter(profile, file); 158 System.out.println("Writing to file " + file.getAbsolutePath() + " ..."); 159 tng.addListener(rep); 160 tng.run(); 161 rep.writeSummary(); 162 System.out.println("-- " + SPEC_ID + " TCK finished --"); 163 return 0; 164 } 165 166 @Override 167 public String getVersion() { 168 return TCK_VERSION; 169 } 170 171 @Override 172 public final Set<SourceVersion> getSourceVersions() { 173 return Collections.unmodifiableSet(new HashSet<>(Arrays.asList(new SourceVersion[] {SourceVersion.RELEASE_5, SourceVersion.RELEASE_6, SourceVersion.RELEASE_7}))); 174 } 175 176 public static final void main(String... args) { 177 if (args.length > 0 && "-version".equalsIgnoreCase(args[0])) { 178 showVersion(); 179 } else { // (args.length > 0 && "-help".equalsIgnoreCase(args[0])) { 180 showHelp(); 181 } /* 182 * else { final Tool runner = new TCKRunner(); runner.run(System.in, System.out, 183 * System.err, new String[]{TCKRunner.class.getName()}); } 184 */ 185 } 186 187 private static void showHelp() { 188 final StringWriter consoleWriter = new StringWriter(1000); 189 consoleWriter.write("*****************************************************************************************\n"); 190 consoleWriter.write("**** " + SPEC_ID + " - Units of Measurement, Technical Compatibility Kit, version " + TCK_VERSION + "\n"); 191 consoleWriter.write("*****************************************************************************************\n\n"); 192 consoleWriter.write("Usage:\n"); 193 consoleWriter.write("To run the TCK, execute TestNG with Maven or a similar build tool.\n\n"); 194 consoleWriter.write("E.g. by running \"mvn test\" with this POM.\n\n"); 195 consoleWriter.write("You may use the following system properties to override the default behavior:\n"); 196 consoleWriter.write("-D" + SYS_PROPERTY_PROFILE + "=<profile>" + " to select the desired profile from these available " + SPEC_ID + " profiles:\n"); 197 for (Profile p : Profile.values()) { 198 consoleWriter.write(" " + p.name() + " - " + p.getDescription() + (p.isDefault() ? " (the default profile)\n" : "\n")); 199 } 200 consoleWriter.write("-D" + SYS_PROPERTY_OUTPUT_DIR + "=<directory> to set the output directory of your choice.\n"); 201 consoleWriter.write("-D" + SYS_PROPERTY_REPORT_FILE + "=<file> to set the TCK result file directory of your choice.\n"); 202 consoleWriter.write("-D" + SYS_PROPERTY_VERBOSE + "=true/false to toggle the TCK verbose option for additional test output. The default is \"false\"\n"); 203 System.out.println(consoleWriter); 204 } 205 206 private static void showVersion() { 207 System.out.println(SPEC_ID + " - Units of Measurement, Technical Compatibility Kit, version \"" + TCK_VERSION + "\"\n"); 208 } 209 210 public static final class Reporter extends TestListenerAdapter { 211 private int count = 0; 212 private int skipped = 0; 213 private int failed = 0; 214 private int success = 0; 215 private final StringWriter consoleWriter = new StringWriter(3000); 216 private FileWriter fileWriter; 217 218 public Reporter(Profile profile, File file) { 219 try { 220 if (!file.exists()) { 221 file.createNewFile(); 222 } 223 fileWriter = new FileWriter(file); 224 fileWriter.write("*****************************************************************************************\n"); 225 fileWriter.write("**** " + SPEC_ID + " - Units of Measurement, Technical Compatibility Kit, version " + TCK_VERSION + "\n"); 226 fileWriter.write("*****************************************************************************************\n\n"); 227 fileWriter.write("Executed on " + new java.util.Date() + "\n"); 228 fileWriter.write("Using " + profile.getDescription() + " profile\n\n"); 229 // System.out: 230 consoleWriter.write("*****************************************************************************************\n"); 231 consoleWriter.write("**** " + SPEC_ID + " - Units of Measurement, Technical Compatibility Kit, version " + TCK_VERSION + "\n"); 232 consoleWriter.write("*****************************************************************************************\n\n"); 233 consoleWriter.write("Executed on " + new java.util.Date() + "\n"); 234 consoleWriter.write("Using " + profile.getDescription() + " profile\n\n"); 235 } catch (IOException e) { 236 e.printStackTrace(); 237 System.exit(-1); 238 } 239 } 240 241 @Override 242 public void onTestFailure(ITestResult tr) { 243 failed++; 244 count++; 245 String location = tr.getTestClass().getRealClass().getSimpleName() + '#' + tr.getMethod().getMethodName(); 246 try { 247 Method realTestMethod = tr.getMethod().getConstructorOrMethod().getMethod(); 248 Test testAnnot = realTestMethod.getAnnotation(Test.class); 249 if (testAnnot != null && testAnnot.description() != null && !testAnnot.description().isEmpty()) { 250 if (tr.getThrowable() != null) { 251 StringWriter sw = new StringWriter(); 252 PrintWriter w = new PrintWriter(sw); 253 tr.getThrowable().printStackTrace(w); 254 w.flush(); 255 log("[FAILED] " + testAnnot.description() + "(" + location + "):\n" + sw.toString()); 256 } else { 257 log("[FAILED] " + testAnnot.description() + "(" + location + ")"); 258 } 259 } else { 260 if (tr.getThrowable() != null) { 261 StringWriter sw = new StringWriter(); 262 PrintWriter w = new PrintWriter(sw); 263 tr.getThrowable().printStackTrace(w); 264 w.flush(); 265 log("[FAILED] " + location + ":\n" + sw.toString()); 266 } else { 267 log("[FAILED] " + location); 268 } 269 } 270 } catch (IOException e) { 271 throw new IllegalStateException("IO Error", e); 272 } 273 } 274 275 @Override 276 public void onTestSkipped(ITestResult tr) { 277 skipped++; 278 count++; 279 String location = tr.getTestClass().getRealClass().getSimpleName() + '#' + tr.getMethod().getMethodName(); 280 try { 281 Method realTestMethod = tr.getMethod().getConstructorOrMethod().getMethod(); 282 Test specAssert = realTestMethod.getAnnotation(Test.class); 283 if (specAssert != null && specAssert.description() != null && !specAssert.description().isEmpty()) { 284 log("[SKIPPED] " + specAssert.description() + "(" + location + ")"); 285 } else { 286 log("[SKIPPED] " + location); 287 } 288 } catch (IOException e) { 289 throw new IllegalStateException("IO Error", e); 290 } 291 } 292 293 @Override 294 public void onTestSuccess(ITestResult tr) { 295 success++; 296 count++; 297 String location = tr.getTestClass().getRealClass().getSimpleName() + '#' + tr.getMethod().getMethodName(); 298 try { 299 Method realTestMethod = tr.getMethod().getConstructorOrMethod().getMethod(); 300 Test specAssert = realTestMethod.getAnnotation(Test.class); 301 if (specAssert != null && specAssert.description() != null && !specAssert.description().isEmpty()) { 302 log("[SUCCESS] " + specAssert.description() + "(" + location + ")"); 303 } else { 304 log("[SUCCESS] " + location); 305 } 306 } catch (IOException e) { 307 throw new IllegalStateException("IO Error", e); 308 } 309 } 310 311 private void log(String text) throws IOException { 312 fileWriter.write(text); 313 fileWriter.write('\n'); 314 consoleWriter.write(text); 315 consoleWriter.write('\n'); 316 } 317 318 public void writeSummary() { 319 try { 320 log("\n" + SPEC_ID + " TCK version " + TCK_VERSION + " Summary"); 321 log("-------------------------------------------------------"); 322 log("\nTOTAL TESTS EXECUTED : " + count); 323 log("TOTAL TESTS SKIPPED : " + skipped); 324 log("TOTAL TESTS SUCCESS : " + success); 325 log("TOTAL TESTS FAILED : " + failed); 326 fileWriter.flush(); 327 fileWriter.close(); 328 consoleWriter.flush(); 329 System.out.println(); 330 System.out.println(consoleWriter); 331 } catch (IOException e) { 332 throw new IllegalStateException("IO Error", e); 333 } 334 } 335 } 336}