001 // Copyright 2005-2006 Ferdinand Prantl <prantl@users.sourceforge.net> 002 // Copyright 2001-2004 The Apache Software Foundation 003 // All rights reserved. 004 // 005 // Licensed under the Apache License, Version 2.0 (the "License"); 006 // you may not use this file except in compliance with the License. 007 // You may obtain a copy of the License at 008 // 009 // http://www.apache.org/licenses/LICENSE-2.0 010 // 011 // Unless required by applicable law or agreed to in writing, software 012 // distributed under the License is distributed on an "AS IS" BASIS, 013 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 // See the License for the specific language governing permissions and 015 // limitations under the License. 016 // 017 // See http://ant-eclipse.sourceforge.net for the most recent version 018 // and more information. 019 020 package prantl.ant.eclipse; 021 022 import java.io.ByteArrayInputStream; 023 import java.io.ByteArrayOutputStream; 024 import java.io.IOException; 025 import java.io.InputStream; 026 import java.io.InputStreamReader; 027 import java.io.OutputStream; 028 import java.io.PrintStream; 029 import java.util.Arrays; 030 import java.util.HashSet; 031 import java.util.Hashtable; 032 import java.util.StringTokenizer; 033 034 import junit.framework.TestCase; 035 036 import org.apache.tools.ant.BuildEvent; 037 import org.apache.tools.ant.BuildListener; 038 import org.apache.tools.ant.Project; 039 040 /** 041 * Test fixture with unit test cases for the class <tt>EclipseTask</tt>. 042 * 043 * @see EclipseTask 044 * @since Ant-Eclipse 1.0 045 * @author Ferdinand Prantl <prantl@users.sourceforge.net> 046 */ 047 public class EclipseTaskTest extends TestCase { 048 049 /** 050 * Creates a new instance of the test fixture. Default constructor. 051 * 052 * @since Ant-Eclipse 1.0 053 */ 054 public EclipseTaskTest() { 055 } 056 057 /** 058 * Helper class constructing the task object for the class <tt>EclipseTask</tt> with 059 * the minimum environment simulating an ant-build file with a single target with a 060 * single task. 061 * 062 * @see EclipseTask 063 * @since Ant-Eclipse 1.0 064 * @author Ferdinand Prantl <prantl@users.sourceforge.net> 065 */ 066 static final class EclipseTaskTester extends EclipseTask { 067 068 /** 069 * Creates a new instance of the task with the minimum ant-like environment. 070 * 071 * @param object 072 * An object that the output is delegated into. 073 * @throws NullPointerException 074 * If the parameter <tt>object</tt> is null. 075 * @since Ant-Eclipse 1.0 076 */ 077 EclipseTaskTester(EclipseOutput object) { 078 super(object); 079 setProject(new Project()); 080 getProject().init(); 081 getProject().setUserProperty("ant.project.name", "eclipse"); 082 // setTaskType("eclipse"); 083 // setTaskName("eclipse"); 084 // setOwningTarget(new Target()); 085 } 086 087 } 088 089 /** 090 * Testing output class performing output into in-memory streams. 091 * 092 * @see EclipseOutput 093 * @since Ant-Eclipse 1.0 094 * @author Ferdinand Prantl <prantl@users.sourceforge.net> 095 */ 096 static final class MemoryEclipseOutput extends EclipseOutput { 097 098 private Hashtable settings = new Hashtable(); 099 100 private ByteArrayOutputStream project = null; 101 102 private ByteArrayOutputStream classPath = null; 103 104 /** 105 * Creates a new instance of the output object. 106 * 107 * @param element 108 * An object containing the configuration. 109 * @see EclipseOutput#EclipseOutput(EclipseElement) 110 * @since Ant-Eclipse 1.0 111 */ 112 MemoryEclipseOutput(EclipseElement element) { 113 super(element); 114 } 115 116 /** 117 * @see EclipseOutput#isPreferencesUpToDate(String) 118 * @since Ant-Eclipse 1.0 119 */ 120 boolean isPreferencesUpToDate(String name) { 121 return false; 122 } 123 124 /** 125 * @see EclipseOutput#isProjectUpToDate() 126 * @since Ant-Eclipse 1.0 127 */ 128 boolean isProjectUpToDate() { 129 return false; 130 } 131 132 /** 133 * @see EclipseOutput#isClassPathUpToDate() 134 * @since Ant-Eclipse 1.0 135 */ 136 boolean isClassPathUpToDate() { 137 return false; 138 } 139 140 /** 141 * @see EclipseOutput#openPreferences(String) 142 * @since Ant-Eclipse 1.0 143 */ 144 InputStream openPreferences(String name) { 145 ByteArrayOutputStream preferences = (ByteArrayOutputStream) settings 146 .get(name); 147 return preferences == null ? null : new ByteArrayInputStream(preferences 148 .toByteArray()); 149 } 150 151 /** 152 * @see EclipseOutput#openProject() 153 * @since Ant-Eclipse 1.0 154 */ 155 InputStream openProject() { 156 return project == null ? null : new ByteArrayInputStream(project 157 .toByteArray()); 158 } 159 160 /** 161 * @see EclipseOutput#openClassPath() 162 * @since Ant-Eclipse 1.0 163 */ 164 InputStream openClassPath() { 165 return classPath == null ? null : new ByteArrayInputStream(classPath 166 .toByteArray()); 167 } 168 169 /** 170 * @see EclipseOutput#createPreferences(String) 171 * @since Ant-Eclipse 1.0 172 */ 173 OutputStream createPreferences(String name) { 174 ByteArrayOutputStream preferences = new ByteArrayOutputStream(); 175 settings.put(name, preferences); 176 return preferences; 177 } 178 179 /** 180 * @see EclipseOutput#createProject() 181 * @since Ant-Eclipse 1.0 182 */ 183 OutputStream createProject() { 184 return project = new ByteArrayOutputStream(); 185 } 186 187 /** 188 * @see EclipseOutput#createClassPath() 189 * @since Ant-Eclipse 1.0 190 */ 191 OutputStream createClassPath() { 192 return classPath = new ByteArrayOutputStream(); 193 } 194 195 } 196 197 /** 198 * Testing build listener collecting the log messages up to the specified level. 199 * 200 * @since Ant-Eclipse 1.0 201 * @author Ferdinand Prantl <prantl@users.sourceforge.net> 202 */ 203 static final class MemoryLogListener implements BuildListener { 204 205 private StringBuffer log = new StringBuffer(); 206 207 private int logLevel; 208 209 /** 210 * Constructs a test listener which will store the log events below or equal the 211 * given level. 212 * 213 * @param logLevel 214 * Maximum logLevel to watch. 215 */ 216 public MemoryLogListener(int logLevel) { 217 this.logLevel = logLevel; 218 } 219 220 /** 221 * @return Collected log messages. 222 */ 223 String getLog() { 224 return log.toString(); 225 } 226 227 /** 228 * Fired before any targets are started. 229 * 230 * @param event 231 * Context information about the event. 232 */ 233 public void buildStarted(BuildEvent event) { 234 } 235 236 /** 237 * Fired after the last target has finished. This event will still be thrown if an 238 * error occured during the build. 239 * 240 * @param event 241 * Context information about the event. 242 */ 243 public void buildFinished(BuildEvent event) { 244 } 245 246 /** 247 * Fired when a target is started. 248 * 249 * @param event 250 * Context information about the event. 251 */ 252 public void targetStarted(BuildEvent event) { 253 } 254 255 /** 256 * Fired when a target has finished. This event will still be thrown if an error 257 * occured during the build. 258 * 259 * @param event 260 * Context information about the event. 261 */ 262 public void targetFinished(BuildEvent event) { 263 } 264 265 /** 266 * Fired when a task is started. 267 * 268 * @param event 269 * Context information about the event. 270 */ 271 public void taskStarted(BuildEvent event) { 272 } 273 274 /** 275 * Fired when a task has finished. This event will still be thrown if an error 276 * occured during the build. 277 * 278 * @param event 279 * Context information about the event. 280 */ 281 public void taskFinished(BuildEvent event) { 282 } 283 284 /** 285 * Fired whenever a message is logged. 286 * 287 * @param event 288 * Context information about the event. 289 */ 290 public void messageLogged(BuildEvent event) { 291 if (event.getPriority() <= logLevel) { 292 log.append(levels[event.getPriority()]); 293 log.append(' '); 294 log.append(event.getMessage()); 295 log.append('\n'); 296 } 297 } 298 299 private static final String[] levels = new String[] { "ERROR ", "WARNING", 300 "INFO ", "VERBOSE", "DEBUG " }; 301 302 } 303 304 /** 305 * Tests executing the task with the following configuration: 306 * 307 * <pre> 308 * <eclipse /> 309 * </pre> 310 * 311 * @throws Exception 312 * If the task execution fails. 313 */ 314 public void testExecuteWithEmptyEclipseElement() throws Exception { 315 MemoryEclipseOutput output = new MemoryEclipseOutput(new EclipseElement()); 316 EclipseTaskTester task = new EclipseTaskTester(output); 317 MemoryLogListener logListener = new MemoryLogListener(Project.MSG_VERBOSE); 318 task.getProject().addBuildListener(logListener); 319 320 ByteArrayOutputStream out = new ByteArrayOutputStream(); 321 ByteArrayOutputStream err = new ByteArrayOutputStream(); 322 PrintStream systemOut = System.out; 323 PrintStream systemErr = System.err; 324 try { 325 systemOut.flush(); 326 systemErr.flush(); 327 System.setOut(new PrintStream(out)); 328 System.setErr(new PrintStream(err)); 329 task.execute(); 330 } finally { 331 System.setOut(systemOut); 332 System.setErr(systemErr); 333 } 334 335 assertEquals(0, out.size()); 336 assertEquals(0, err.size()); 337 assertNull(output.openPreferences(OrgEclipseCoreResourcesPreferencesElement 338 .getPackageName())); 339 assertNull(output.openPreferences(OrgEclipseCoreRuntimePreferencesElement 340 .getPackageName())); 341 assertNull(output.openPreferences(OrgEclipseJdtCorePreferencesElement 342 .getPackageName())); 343 assertNull(output.openPreferences(OrgEclipseJdtUiPreferencesElement 344 .getPackageName())); 345 assertNull(output.openProject()); 346 assertNull(output.openClassPath()); 347 assertEquals("WARNING There were no settings found.\n" 348 + "WARNING There was no description of a project found.\n" 349 + "WARNING There was no description of a classpath found.\n", logListener 350 .getLog()); 351 } 352 353 /** 354 * Tests executing the task with the following configuration: 355 * 356 * <pre> 357 * <eclipse> 358 * <settings> 359 * <resources version="2" encoding="UTF-8" /> 360 * </settings> 361 * </eclipse> 362 * </pre> 363 * 364 * @throws Exception 365 * If the task execution fails. 366 */ 367 public void testExecuteWithSettingsElementWithVersionAndEncoding() throws Exception { 368 EclipseElement eclipse = new EclipseElement(); 369 SettingsElement settings = new SettingsElement(); 370 OrgEclipseCoreResourcesPreferencesElement resources = settings.createResources(); 371 resources.setVersion("2"); 372 resources.setEncoding("UTF-8"); 373 eclipse.setSettings(settings); 374 375 MemoryEclipseOutput output = new MemoryEclipseOutput(eclipse); 376 EclipseTaskTester task = new EclipseTaskTester(output); 377 MemoryLogListener logListener = new MemoryLogListener(Project.MSG_VERBOSE); 378 task.getProject().addBuildListener(logListener); 379 task.execute(); 380 381 String settingsOutput = streamToString(output 382 .openPreferences(OrgEclipseCoreResourcesPreferencesElement 383 .getPackageName())); 384 // "#Fri Aug 19 07:58:50 CEST 2005\n" 385 assertTrue(settingsOutput.startsWith("#")); 386 assertTrue(settingsOutput.endsWith("\n")); 387 assertEqualAllLines("encoding/<project>=UTF-8\n" 388 + "eclipse.preferences.version=2\n", skipLine(settingsOutput)); 389 assertNull(output.openPreferences(OrgEclipseCoreRuntimePreferencesElement 390 .getPackageName())); 391 assertNull(output.openPreferences(OrgEclipseJdtCorePreferencesElement 392 .getPackageName())); 393 assertNull(output.openPreferences(OrgEclipseJdtUiPreferencesElement 394 .getPackageName())); 395 assertNull(output.openProject()); 396 assertNull(output.openClassPath()); 397 assertEquals( 398 "INFO Writing the preferences for \"org.eclipse.core.resources\".\n" 399 + "WARNING There was no description of a project found.\n" 400 + "WARNING There was no description of a classpath found.\n", 401 logListener.getLog()); 402 } 403 404 /** 405 * Tests executing the task with the following configuration: 406 * 407 * <pre> 408 * <eclipse> 409 * <project /> 410 * </eclipse> 411 * </pre> 412 * 413 * @throws Exception 414 * If the task execution fails. 415 */ 416 public void testExecuteWithEmptyProjectElement() throws Exception { 417 EclipseElement eclipse = new EclipseElement(); 418 eclipse.setProject(new ProjectElement()); 419 420 MemoryEclipseOutput output = new MemoryEclipseOutput(eclipse); 421 EclipseTaskTester task = new EclipseTaskTester(output); 422 MemoryLogListener logListener = new MemoryLogListener(Project.MSG_VERBOSE); 423 task.getProject().addBuildListener(logListener); 424 task.execute(); 425 426 assertNull(output.openPreferences(OrgEclipseCoreResourcesPreferencesElement 427 .getPackageName())); 428 assertNull(output.openPreferences(OrgEclipseCoreRuntimePreferencesElement 429 .getPackageName())); 430 assertNull(output.openPreferences(OrgEclipseJdtCorePreferencesElement 431 .getPackageName())); 432 assertNull(output.openPreferences(OrgEclipseJdtUiPreferencesElement 433 .getPackageName())); 434 String projectOutput = streamToString(output.openProject()); 435 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 436 + "<projectDescription>\n" + " <name>eclipse</name>\n" + " <comment>\n" 437 + " </comment>\n" + " <projects>\n" + " </projects>\n" 438 + " <buildSpec>\n" + " <buildCommand>\n" 439 + " <name>org.eclipse.jdt.core.javabuilder</name>\n" 440 + " <arguments>\n" + " </arguments>\n" 441 + " </buildCommand>\n" + " </buildSpec>\n" + " <natures>\n" 442 + " <nature>org.eclipse.jdt.core.javanature</nature>\n" 443 + " </natures>\n" + "</projectDescription>", projectOutput); 444 assertNull(output.openClassPath()); 445 assertEquals("WARNING There were no settings found.\n" 446 + "INFO Writing the project definition in the mode \"java\".\n" 447 + "VERBOSE Project name is \"eclipse\".\n" 448 + "WARNING There was no description of a classpath found.\n", logListener 449 .getLog()); 450 } 451 452 /** 453 * Tests executing the task with the following configuration: 454 * 455 * <pre> 456 * <eclipse> 457 * <project /> 458 * </eclipse> 459 * </pre> 460 * 461 * @throws Exception 462 * If the task execution fails. 463 */ 464 public void testExecuteWithProjectElementWithName() throws Exception { 465 EclipseElement eclipse = new EclipseElement(); 466 ProjectElement project = new ProjectElement(); 467 project.setName("test"); 468 eclipse.setProject(project); 469 470 MemoryEclipseOutput output = new MemoryEclipseOutput(eclipse); 471 EclipseTaskTester task = new EclipseTaskTester(output); 472 MemoryLogListener logListener = new MemoryLogListener(Project.MSG_VERBOSE); 473 task.getProject().addBuildListener(logListener); 474 task.execute(); 475 476 assertNull(output.openPreferences(OrgEclipseCoreResourcesPreferencesElement 477 .getPackageName())); 478 assertNull(output.openPreferences(OrgEclipseCoreRuntimePreferencesElement 479 .getPackageName())); 480 assertNull(output.openPreferences(OrgEclipseJdtCorePreferencesElement 481 .getPackageName())); 482 assertNull(output.openPreferences(OrgEclipseJdtUiPreferencesElement 483 .getPackageName())); 484 String projectOutput = streamToString(output.openProject()); 485 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 486 + "<projectDescription>\n" + " <name>test</name>\n" + " <comment>\n" 487 + " </comment>\n" + " <projects>\n" + " </projects>\n" 488 + " <buildSpec>\n" + " <buildCommand>\n" 489 + " <name>org.eclipse.jdt.core.javabuilder</name>\n" 490 + " <arguments>\n" + " </arguments>\n" 491 + " </buildCommand>\n" + " </buildSpec>\n" + " <natures>\n" 492 + " <nature>org.eclipse.jdt.core.javanature</nature>\n" 493 + " </natures>\n" + "</projectDescription>", projectOutput); 494 assertNull(output.openClassPath()); 495 assertEquals("WARNING There were no settings found.\n" 496 + "INFO Writing the project definition in the mode \"java\".\n" 497 + "VERBOSE Project name is \"test\".\n" 498 + "WARNING There was no description of a classpath found.\n", logListener 499 .getLog()); 500 } 501 502 private String streamToString(InputStream input) throws IOException { 503 InputStreamReader reader = new InputStreamReader(input, "UTF-8"); 504 StringBuffer content = new StringBuffer(); 505 for (int ch; (ch = reader.read()) != -1;) 506 content.append((char) ch); 507 return content.toString(); 508 } 509 510 private String skipLine(String input) { 511 int next = input.indexOf('\n'); 512 return next >= 0 ? input.substring(next + 1) : ""; 513 } 514 515 private void assertEqualAllLines(String expected, String actual) { 516 HashSet expectedLines = new HashSet(Arrays.asList(split(expected, "\n"))); 517 String[] actualLines = split(actual, "\n"); 518 for (int i = 0; i != actualLines.length; ++i) 519 if (!expectedLines.remove(actualLines[i])) 520 fail("The line " + (i + 1) + " (\"" + actualLines[i] 521 + ") from the actual content \"" + actual 522 + "\" does not match any in the expected content \"" + expected 523 + "\"."); 524 int size = expectedLines.size(); 525 if (size != 0) 526 fail(size + " line(s) (" 527 + join((String[]) expectedLines.toArray(new String[] {}), "\n") 528 + ") from the expected content \"" + expected 529 + "\" were missing in the actual content \"" + actual + "\"."); 530 } 531 532 /** 533 * Splits the input string into an array of strings using the specified delimiter. 534 * 535 * @param input 536 * The input string to be splitted. 537 * @param delimiter 538 * The delimiting token. 539 * @throws NullPointerException 540 * If some of the input parameters are null. 541 * @return An array with strings as delimited parts of the input. 542 */ 543 public static String[] split(String input, String delimiter) { 544 StringTokenizer tokenizer = new StringTokenizer(input, delimiter); 545 String[] result = new String[tokenizer.countTokens()]; 546 for (int i = 0; tokenizer.hasMoreTokens(); ++i) 547 result[i] = tokenizer.nextToken(); 548 return result; 549 } 550 551 /** 552 * Splits the input array into a string using the specified delimiter. 553 * 554 * @param input 555 * The input array to be joined. 556 * @param delimiter 557 * The delimiting token. 558 * @throws NullPointerException 559 * If some of the input parameters are null. 560 * @return An string joined with the specified delimiter from he input array. 561 */ 562 public static String join(String[] input, String delimiter) { 563 StringBuffer result = new StringBuffer(); 564 for (int i = 0; i != input.length; ++i) { 565 if (i != 0) 566 result.append(delimiter); 567 result.append(input[i]); 568 } 569 return result.toString(); 570 } 571 572 }