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