/*
* @(#)BaseTestCase.java 1.13 06/10/10
*
* Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package gunit.framework ;
import java.awt.* ;
import java.awt.image.* ;
import java.io.* ;
import java.net.* ;
import java.util.* ;
import java.lang.reflect.* ;
import junit.framework.AssertionFailedError ;
import gunit.image.RefImageNotFoundException ;
/**
* <code>BaseTestCase</code> is an abstract class that extends JUnit's
* <code>TestCase</code> and contains methods that should run on PBP/PP.
* All profile and optional package specific functionality are defined
* as abstract methods.
* <p>
* <code>BaseTestCase</code> overrides setUp(), tearDown() and runTest()
* methods from the base class to provide gunit's Testcase behavioir.
*/
public abstract class BaseTestCase extends junit.framework.TestCase {
private Container container ;
private String[] args ;
// Graphics object for the testcase.
private Graphics gc ;
// created only for Graphics testcases
private BufferedImage backBuffer ;
/**
* Indicates if the testcase asserted using any of the assert
* functions provided by gunit.
*/
protected boolean isAsserted = false ;
private boolean isGraphicsTestcase = false ;
// A non-null value indicates that the testcase attempted to assert
// and the reference image was not found.
private String referenceImageFile = null ;
static TestContainer defaultTestContainer = null ;
static String[] refImageDirs = null ;
static TestArguments testArgs = null ;
static TestFilter testFilter = null ;
static TestResultVerifier resultVerifier = null ;
static {
TestContext context = TestContext.getInstance() ;
defaultTestContainer = (TestContainer)
context.getObjectValue(TestContext.TEST_CONTAINER_CLASS);
refImageDirs = getRefImageDirs(
context.getStringValue(TestContext.REF_IMAGE_PATH)) ;
resultVerifier = (TestResultVerifier)
context.getObjectValue(TestContext.TEST_RESULT_VERIFIER_CLASS);
testArgs = new TestArguments();
testFilter = (TestFilter)context.getValue(TestContext.TEST_FILTER) ;
if ( testFilter == null ) {
testFilter = new TestFilter() {
public boolean allowExecution(Class c, String method) {
return true ;
}
};
}
}
static String[] getRefImageDirs(String path) {
StringTokenizer st = new StringTokenizer(path, ":") ;
String[] dirs = new String[st.countTokens()] ;
for ( int i = 0 ; st.hasMoreTokens() ; i ++ ) {
dirs[i] = st.nextToken() ;
}
return dirs ;
}
// junit.framework.TestCase
protected void setUp() {
if ( !testFilter.allowExecution(getClass(), getName()) )
return ;
this.isAsserted = false ;
this.isGraphicsTestcase = false ;
this.referenceImageFile = null ;
this.args = testArgs.getArgs(getClass(), getName()) ;
this.container = createContainer() ;
this.container.removeAll() ;
this.gc = createGraphics() ;
}
// junit.framework.TestCase
protected void tearDown() {
if ( !testFilter.allowExecution(getClass(), getName()) )
return ;
disposeGraphics() ;
if ( this.referenceImageFile != null ) {
System.out.println(this.referenceImageFile+
" does not exist, in the following directories");
for ( int i = 0 ; i < this.refImageDirs.length ; i ++ ) {
System.out.println(" "+this.refImageDirs[i]) ;
}
System.out.print("Create image[(y)es/(n)o][default=y]:") ;
BufferedReader br
= new BufferedReader(new InputStreamReader(System.in));
try {
String result_code = br.readLine().trim() ;
if ( result_code.length() <= 0 ||
"y".equals(result_code) ) {
File f = new File(this.referenceImageFile) ;
String dir = f.getParent() ;
if ( dir == null )
dir = this.refImageDirs[this.refImageDirs.length-1];
String file = f.getName() ;
System.out.print("Enter directory [default="+dir+"]:");
result_code = br.readLine().trim() ;
if ( result_code.length() > 0 ) {
dir = result_code ;
}
file = dir+File.separator+file ;
encodeImage(this.backBuffer,file);
}
}
catch (Exception ex) {
}
}
this.container = null ;
this.backBuffer = null ;
}
// junit.framework.TestCase
protected void runTest() throws Throwable {
Class cls = getClass();
String method = getName() ;
//System.out.println(cls.getName()+"."+method);
try {
if ( testFilter.allowExecution(cls, method) ) {
super.runTest() ;
}
else {
return ;
}
if ( !this.isGraphicsTestcase && this.container != null ) {
this.container.validate() ;
}
// if ( testcase has not asserted using image compare ) {
// chances are it had used Assert.assert() methods or
// it did not do anything w.r.t the verification
//
// if there is a description information for the testcase
// then we display the description and ask the user to
// manually verify the result
// }
if ( this.isAsserted ) {
return ;
}
TestResultDescription desc =
TestResultDescription.getInstance(cls, method);
resultVerifier.verify(cls, method, desc) ;
}
catch (RefImageNotFoundException refimg_nf_ex) {
this.referenceImageFile = refimg_nf_ex.getImage() ;
throw refimg_nf_ex ;
}
catch ( Throwable t ) {
throw t ;
}
}
/**
* Returns the container for the testcase to create GUI artifacts
*/
protected final Container getContainer() {
return this.container ;
}
/**
* Returns the arguments for the testcase. It returns a zero length
* string if there are no arguments for the testcase
*/
protected final String[] getArguments() {
return this.args ;
}
/**
* Returns a <code>Graphics</code> for the graphics testcase to
* render.
*/
protected final Graphics getGraphics() {
this.isGraphicsTestcase = true ;
return this.gc ;
}
protected Container createContainer() {
return defaultTestContainer.getContainer() ;
}
/**
* Returns the image that contains the testcase rendition
*/
protected final Object getTestImage() {
return this.backBuffer ;
}
/**
* Returns the reference image for the testcase.
*/
protected final Object getReferenceImage() {
return getReferenceImage(getReferenceImageFilename());
}
/**
* Returns the image file name for the testcase
*/
protected final String getReferenceImageFilename() {
if ( !this.isGraphicsTestcase )
throw new IllegalArgumentException("Not a graphics testcase");
return getClass().getName().replace('.', '_')+
"_"+
getName()+
"_"+
this.backBuffer.getWidth()+"x"+this.backBuffer.getHeight()+
".png";
}
/**
* Returns the expected image for the fileName relative to the
* image directory
*
* @param fileName file name relative to the image directory
*/
protected final Object getReferenceImage(String fileName) {
for ( int i = 0 ; i < this.refImageDirs.length ; i ++ ) {
// make the relative fileName absolute with the ref image
// directory
String file = this.refImageDirs[i] + File.separator + fileName ;
if ( new File(file).exists() )
return file ;
}
throw new RefImageNotFoundException("", fileName);
}
/**
* A convenience method that does
* <code>assertImageEquals(getReferenceImage(),getTestImage())</code>
*/
protected final void assertImageEquals() {
assertImageEquals(getReferenceImage(), getTestImage());
}
/**
* Assertion method for image equal operation.
*
* @param expected the value returned from getReferenceImage()
* @param actual the value returned from getTestImage()
*/
protected final void assertImageEquals(Object expected,
Object actual) {
assertImageEquals("", expected, actual) ;
}
/**
* An utility method that loads an image from a file
*/
protected final Image loadImage(String imageFile) {
Image img = Toolkit.getDefaultToolkit().getImage(imageFile);
return trackImage(img, this.container) ;
}
/**
* An utility method that loads an image from a URL
*/
protected final Image loadImage(URL url) {
Image img = Toolkit.getDefaultToolkit().getImage(url);
return trackImage(img, this.container) ;
}
/**
* Indicates if a back buffer should be used to render the testcase
* graphics operations. The default value is <code>true</code>, but
* the testcase can override to return <code>false</code>,so that
* screen graphics is used instead of the image buffer
*/
protected boolean useBackBuffer() {
return true ;
}
/**
* Creates a <Code>BufferedImage</code> for the specified width
* and height with INT_ARGB format
*/
protected abstract BufferedImage createBufferedImage(int width,
int height) ;
/**
* Encode the contents of the <code>BufferedImage</code> with an
* image compression format (preferably PNG) onto the file specified
*/
protected abstract void encodeImage(BufferedImage image,
String filename);
/**
* Ensures that the assertion is valid
*
* @param message message for the failure case.
* @param expected the value returned from getReferenceImage()
* @param actual the value returned from getTestImage()
*/
protected abstract void assertImageEquals(String message,
Object expected,
Object actual) ;
/**
* Set the background color for the graphics
*/
protected abstract void clearToBackgroundColor(Graphics g, Color c,
int x, int y, int w, int h) ;
private Graphics createGraphics() {
if ( useBackBuffer() ) {
return createImageGraphics() ;
}
else {
return createScreenGraphics() ;
}
}
private void disposeGraphics() {
if ( this.backBuffer != null ) {
disposeImageGraphics() ;
}
else {
disposeScreenGraphics() ;
}
}
private BufferedImage createBackBuffer() {
Dimension size = this.container.getSize() ;
return createBufferedImage(size.width, size.height) ;
}
private Graphics createScreenGraphics() {
Dimension size = this.container.getSize() ;
Graphics g = container.getGraphics() ;
g.clearRect(0,0,size.width, size.height);
Insets insets = this.container.getInsets() ;
if ( (insets.top|insets.left) != 0 )
g.translate(insets.left, insets.top) ;
return g ;
}
private void disposeScreenGraphics() {
this.gc.dispose() ;
this.gc = null ;
}
private Graphics createImageGraphics() {
this.backBuffer = createBackBuffer() ;
Graphics2D g = (Graphics2D)this.backBuffer.getGraphics() ;
Color bg = this.container.getBackground() ;
clearToBackgroundColor(g, bg, 0, 0, this.backBuffer.getWidth(null),
this.backBuffer.getHeight(null)) ;
/*
g.setBackground(bg) ;
g.clearRect(0,
0,
this.backBuffer.getWidth(null),
this.backBuffer.getHeight(null)) ;
*/
return g ;
}
private void disposeImageGraphics() {
this.gc.dispose() ;
this.gc = null ;
if ( this.isGraphicsTestcase ) {
Graphics g = createScreenGraphics() ;
try {
g.drawImage(this.backBuffer,0,0,null) ;
}
finally {
g.dispose() ;
}
}
}
private BufferedImage toBufferedImage(Image image) {
if ( image instanceof BufferedImage )
return ((BufferedImage)image) ;
BufferedImage bi = createBufferedImage(image.getWidth(null),
image.getHeight(null)) ;
Graphics big = bi.getGraphics() ;
big.drawImage(image, 0,0, null) ;
big.dispose() ;
return bi ;
}
static Image trackImage(Image img) {
return trackImage(img, new Container());
}
static Image trackImage(Image img, Component comp) {
MediaTracker tracker = new MediaTracker(comp);
if(img != null) {
// Track an image to make sure it loads completely.
tracker.addImage(img, 0);
try {
tracker.waitForID(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return img ;
}
}
/**
* <code>TestArguments</code> abstracts the arguments for all the testcases
*/
class TestArguments {
static final String DEFAULT_TAG = "default" ;
static final String[] STRING_ARRAY = new String[0] ;
String[] defaultArgs = STRING_ARRAY ;
// Map<String, String[]>
// Map<classname.methodname, args>
Map argsMap = new HashMap() ;
TestArguments() {
this(TestContext.getInstance().getStringValue(
TestContext.TEST_ARGS_FILENAME));
}
TestArguments(String file) {
if ( file == null )
return ;
try {
init(new FileInputStream(file)) ;
}
catch ( Exception ex ) {
System.err.println("Unable to load args file "+file) ;
}
}
void init(InputStream stream) {
BufferedReader reader = null ;
String line = null ;
String start_tag = null ;
String class_name = null ;
String method_name = null ;
java.util.List args = new ArrayList() ;
try {
reader = new BufferedReader(new InputStreamReader(stream));
while ((line = reader.readLine()) != null ) {
line = line.trim() ; // trim white spaces
if ( line.startsWith("</") ) { // check if end tag
// process an end tag only if
// we had processed a start tag AND
// the end tag markup is the same as the start tag
if ( start_tag != null &&
line.substring(2).startsWith(start_tag)) {
if ( DEFAULT_TAG.equals(start_tag) ) {
this.defaultArgs = (String[])
args.toArray(STRING_ARRAY);
}
else {
argsMap.put(class_name+"."+method_name,
args.toArray(STRING_ARRAY));
}
args.clear();
}
start_tag = null;
}
else
if ( line.startsWith("<args>")) { // check for <args>
int end_index = line.indexOf("</args>") ;
if ( start_tag == null || end_index == -1) {
continue ; // we have not seen a start tag or
// the end markup for args is missing
}
String arg = line.substring("<args>".length(),
end_index).trim() ;
if ( arg != null && arg.length() > 0 ) {
args.add(arg) ;
}
}
else
if ( line.startsWith("<") ) { // check for start tag
int end_index = line.indexOf(">") ;
if ( end_index < 0 )
continue ; // no markup termination
line = line.substring(1, end_index).trim() ;
if ( line.length() < 0 )
continue ; // no content inside markup
end_index = line.lastIndexOf('-') ;
start_tag = line ;
// start_tag is either a valid testcase or "default"
// tag
if ( end_index > 0 ) {
class_name =
line.substring(0, end_index).replace('-', '.');
method_name = line.substring(end_index+1);
}
else
if ( !DEFAULT_TAG.equals(line) ) {
start_tag = null ;
}
}
}
}
catch ( Exception ex ) {
}
finally {
try {
reader.close();
}
catch( Exception ex) {
}
}
}
String[] getArgs(Class testClass, String methodName) {
String[] args = null ;
args = (String[])
this.argsMap.get(testClass.getName()+"."+methodName) ;
if ( args != null )
return args ;
return defaultArgs ;
}
}