001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. 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: */
018:
019: package org.apache.tools.ant.taskdefs.optional.junit;
020:
021: import java.io.File;
022: import java.io.FileOutputStream;
023: import java.io.OutputStream;
024: import java.io.BufferedOutputStream;
025:
026: import org.apache.tools.ant.BuildException;
027: import org.apache.tools.ant.Task;
028: import org.apache.tools.ant.types.EnumeratedAttribute;
029:
030: /**
031: * <p> A wrapper for the implementations of <code>JUnitResultFormatter</code>.
032: * In particular, used as a nested <code><formatter></code> element in
033: * a <code><junit></code> task.
034: * <p> For example,
035: * <code><pre>
036: * <junit printsummary="no" haltonfailure="yes" fork="false">
037: * <formatter type="plain" usefile="false" />
038: * <test name="org.apache.ecs.InternationalCharTest" />
039: * </junit></pre></code>
040: * adds a <code>plain</code> type implementation
041: * (<code>PlainJUnitResultFormatter</code>) to display the results of the test.
042: *
043: * <p> Either the <code>type</code> or the <code>classname</code> attribute
044: * must be set.
045: *
046: * @see JUnitTask
047: * @see XMLJUnitResultFormatter
048: * @see BriefJUnitResultFormatter
049: * @see PlainJUnitResultFormatter
050: * @see JUnitResultFormatter
051: */
052: public class FormatterElement {
053:
054: private String classname;
055: private String extension;
056: private OutputStream out = System.out;
057: private File outFile;
058: private boolean useFile = true;
059: private String ifProperty;
060: private String unlessProperty;
061:
062: /** xml formatter class */
063: public static final String XML_FORMATTER_CLASS_NAME = "org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter";
064: /** brief formatter class */
065: public static final String BRIEF_FORMATTER_CLASS_NAME = "org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter";
066: /** plain formatter class */
067: public static final String PLAIN_FORMATTER_CLASS_NAME = "org.apache.tools.ant.taskdefs.optional.junit.PlainJUnitResultFormatter";
068:
069: /**
070: * <p> Quick way to use a standard formatter.
071: *
072: * <p> At the moment, there are three supported standard formatters.
073: * <ul>
074: * <li> The <code>xml</code> type uses a <code>XMLJUnitResultFormatter</code>.
075: * <li> The <code>brief</code> type uses a <code>BriefJUnitResultFormatter</code>.
076: * <li> The <code>plain</code> type (the default) uses a <code>PlainJUnitResultFormatter</code>.
077: * </ul>
078: *
079: * <p> Sets <code>classname</code> attribute - so you can't use that
080: * attribute if you use this one.
081: * @param type the enumerated value to use.
082: */
083: public void setType(TypeAttribute type) {
084: if ("xml".equals(type.getValue())) {
085: setClassname(XML_FORMATTER_CLASS_NAME);
086: } else {
087: if ("brief".equals(type.getValue())) {
088: setClassname(BRIEF_FORMATTER_CLASS_NAME);
089: } else { // must be plain, ensured by TypeAttribute
090: setClassname(PLAIN_FORMATTER_CLASS_NAME);
091: }
092: }
093: }
094:
095: /**
096: * <p> Set name of class to be used as the formatter.
097: *
098: * <p> This class must implement <code>JUnitResultFormatter</code>
099: * @param classname the name of the formatter class.
100: */
101: public void setClassname(String classname) {
102: this .classname = classname;
103: if (XML_FORMATTER_CLASS_NAME.equals(classname)) {
104: setExtension(".xml");
105: } else if (PLAIN_FORMATTER_CLASS_NAME.equals(classname)) {
106: setExtension(".txt");
107: } else if (BRIEF_FORMATTER_CLASS_NAME.equals(classname)) {
108: setExtension(".txt");
109: }
110: }
111:
112: /**
113: * Get name of class to be used as the formatter.
114: * @return the name of the class.
115: */
116: public String getClassname() {
117: return classname;
118: }
119:
120: /**
121: * Set the extension to use for the report file.
122: * @param ext the extension to use.
123: */
124: public void setExtension(String ext) {
125: this .extension = ext;
126: }
127:
128: /**
129: * Get the extension used for the report file.
130: * @return the extension.
131: */
132: public String getExtension() {
133: return extension;
134: }
135:
136: /**
137: * <p> Set the file which the formatte should log to.
138: *
139: * <p> Note that logging to file must be enabled .
140: */
141: void setOutfile(File out) {
142: this .outFile = out;
143: }
144:
145: /**
146: * <p> Set output stream for formatter to use.
147: *
148: * <p> Defaults to standard out.
149: * @param out the output stream to use.
150: */
151: public void setOutput(OutputStream out) {
152: this .out = out;
153: }
154:
155: /**
156: * Set whether the formatter should log to file.
157: * @param useFile if true use a file, if false send
158: * to standard out.
159: */
160: public void setUseFile(boolean useFile) {
161: this .useFile = useFile;
162: }
163:
164: /**
165: * Get whether the formatter should log to file.
166: */
167: boolean getUseFile() {
168: return useFile;
169: }
170:
171: /**
172: * Set whether this formatter should be used. It will be
173: * used if the property has been set, otherwise it won't.
174: * @param ifProperty name of property
175: */
176: public void setIf(String ifProperty) {
177: this .ifProperty = ifProperty;
178: }
179:
180: /**
181: * Set whether this formatter should NOT be used. It
182: * will not be used if the property has been set, orthwise it
183: * will be used.
184: * @param unlessProperty name of property
185: */
186: public void setUnless(String unlessProperty) {
187: this .unlessProperty = unlessProperty;
188: }
189:
190: /**
191: * Ensures that the selector passes the conditions placed
192: * on it with <code>if</code> and <code>unless</code> properties.
193: * @param t the task the this formatter is used in.
194: * @return true if the formatter should be used.
195: */
196: public boolean shouldUse(Task t) {
197: if (ifProperty != null
198: && t.getProject().getProperty(ifProperty) == null) {
199: return false;
200: } else if (unlessProperty != null
201: && t.getProject().getProperty(unlessProperty) != null) {
202: return false;
203: }
204:
205: return true;
206: }
207:
208: /**
209: * @since Ant 1.2
210: */
211: JUnitTaskMirror.JUnitResultFormatterMirror createFormatter()
212: throws BuildException {
213: return createFormatter(null);
214: }
215:
216: /**
217: * @since Ant 1.6
218: */
219: JUnitTaskMirror.JUnitResultFormatterMirror createFormatter(
220: ClassLoader loader) throws BuildException {
221:
222: if (classname == null) {
223: throw new BuildException(
224: "you must specify type or classname");
225: }
226: //although this code appears to duplicate that of ClasspathUtils.newInstance,
227: //we cannot use that because this formatter may run in a forked process,
228: //without that class.
229: Class f = null;
230: try {
231: if (loader == null) {
232: f = Class.forName(classname);
233: } else {
234: f = Class.forName(classname, true, loader);
235: }
236: } catch (ClassNotFoundException e) {
237: throw new BuildException("Using loader " + loader
238: + " on class " + classname + ": " + e, e);
239: } catch (NoClassDefFoundError e) {
240: throw new BuildException("Using loader " + loader
241: + " on class " + classname + ": " + e, e);
242: }
243:
244: Object o = null;
245: try {
246: o = f.newInstance();
247: } catch (InstantiationException e) {
248: throw new BuildException(e);
249: } catch (IllegalAccessException e) {
250: throw new BuildException(e);
251: }
252:
253: if (!(o instanceof JUnitTaskMirror.JUnitResultFormatterMirror)) {
254: throw new BuildException(classname
255: + " is not a JUnitResultFormatter");
256: }
257: JUnitTaskMirror.JUnitResultFormatterMirror r = (JUnitTaskMirror.JUnitResultFormatterMirror) o;
258: if (useFile && outFile != null) {
259: try {
260: out = new BufferedOutputStream(new FileOutputStream(
261: outFile));
262: } catch (java.io.IOException e) {
263: throw new BuildException("Unable to open file "
264: + outFile, e);
265: }
266: }
267: r.setOutput(out);
268: return r;
269: }
270:
271: /**
272: * <p> Enumerated attribute with the values "plain", "xml" and "brief".
273: *
274: * <p> Use to enumerate options for <code>type</code> attribute.
275: */
276: public static class TypeAttribute extends EnumeratedAttribute {
277: /** {@inheritDoc}. */
278: public String[] getValues() {
279: return new String[] { "plain", "xml", "brief" };
280: }
281: }
282: }
|