/*******************************************************************************
* Copyright (c) 2012 Google, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Google, Inc. - initial API and implementation
*******************************************************************************/
package com.windowtester.codegen;
import org.eclipse.jdt.core.IType;
import org.eclipse.swt.SWT;
import com.windowtester.codegen.assembly.block.CodeBlock;
import com.windowtester.codegen.assembly.unit.FieldUnit;
import com.windowtester.codegen.assembly.unit.ImportUnit;
import com.windowtester.codegen.assembly.unit.MethodUnit;
import com.windowtester.codegen.assembly.unit.Modifier;
import com.windowtester.codegen.generator.setup.ISetupHandler;
import com.windowtester.codegen.util.FreshMethodNameFinder;
import com.windowtester.recorder.event.user.SemanticKeyDownEvent;
import com.windowtester.runtime.swt.internal.preferences.ICodeGenConstants;
/**
* A builder for WindowTester JUnit test cases.
*/
public class TestCaseBuilder extends SourceTypeBuilder implements ITestCaseBuilder {
/** The root test block */
private CodeBlock _root = new CodeBlock("");
/** A pointer to the current (active/last added) block */
private CodeBlock _current;
/** A Mapper instance */
// private WidgetMapper mapper = new WidgetMapper();
/** Initialization flag */
protected boolean _initialized;
//TODO: make this user configurable
private String _uiContextInstanceName = "ui";
private SourceStringBuilder _stringBuilder;
//populated in subclasses
protected ISetupHandler[] handlers = new ISetupHandler[]{};
/**
* Create an instance.
* @param name - the name of the test case
* @param pkg - the package of the test case
*/
public TestCaseBuilder(String name, String pkg) {
super(name, pkg);
_stringBuilder = new SourceStringBuilder(this);
}
protected SourceStringBuilder getStringBuilder() {
return _stringBuilder;
}
////////////////////////////////////////////////////////////////////////////
//
// Initialization (boiler plate method creation)
//
////////////////////////////////////////////////////////////////////////////
/* (non-Javadoc)
* @see com.windowtester.codegen.ITestCaseBuilder#prime()
*/
public void prime() {
//no-op: all done in init();
}
/**
* Setup boiler plate imports, setUp method (if specified), testMethod, etc.
*/
protected void init() {
addBoilerPlateImports();
//setExtends("UITestCase");
//addHelperFields(); ... now in superclass
addBoilerPlateMethods();
}
/**
* Add basic boilerplate methods (setUp(), suite...)
*/
protected void addBoilerPlateMethods() {
addConstructor();
//TODO: this should be a user pref...
//addMethod(getSuiteMethod());
//addMethod(getSetUpMethod());
//addMethod(getTearDownMethod());
addMethod(getMainMethod());
}
/**
* Add a constructor (if required).
*/
protected void addConstructor() {
MethodUnit consMethod = getConsMethod();
if (consMethod != null)
addMethod(consMethod);
}
/**
* Add helper fields (_uiContext)
*/
protected void addHelperFields() {
String body = "/** The UIContext instance.*/" + NEW_LINE + "private IUIContext _uiContext;" + NEW_LINE;
addHelperField("IUIContext", "_uiContext", body);
}
/**
* Add a field.
* @param type - the type of the field
* @param name - the name of the field
* @param body - the body of the field
*/
private void addHelperField(String type, String name, String body) {
FieldUnit field = new FieldUnit(type,name);
field.setBody(new CodeBlock(body));
addField(field);
}
protected void addBoilerPlateImports() {
String[] defaults = {
"junit.extensions.UITestCase",
"com.windowtester.swt.IUIContext",
"com.windowtester.swt.WidgetLocator"
};
for (int i = 0; i < defaults.length; i++) {
addImport(new ImportUnit(defaults[i]));
}
}
////////////////////////////////////////////////////////////////////////////
//
// Boiler plate method bodies
//
////////////////////////////////////////////////////////////////////////////
/**
* Get the main test method.
* @return main test method
*/
protected MethodUnit getMainMethod() {
String mthName = "test" + getName();
if (mthName.endsWith("Test"))
mthName = mthName.substring(0, mthName.length() - 4);
MethodUnit m = new MethodUnit(mthName);
String comment = "/**" + NEW_LINE + "* Main test method." + NEW_LINE + "*/";
m.setComment(comment);
m.addModifier(Modifier.PUBLIC);
m.addThrows("Exception");
//add pointer to IUIContext instance
_root = new CodeBlock(getUIContextInitilizationBlock());
//set the main method's body to be the method under construction
m.setBody(_root);
return m;
}
protected String getUIContextInitilizationBlock() {
StringBuffer sb = new StringBuffer();
sb.append(getUIContextTypeName()).append(' ').append(getUIContextInstanceName()).append(" = ").append(getUIContextGetterName()).append(";").append(NEW_LINE);
return sb.toString();
}
public String getUIContextGetterName() {
return "getUIContext()";
}
/**
* Get the name of the UIContext type.
*/
public String getUIContextTypeName() {
return "IUIContext";
}
/**
* Get the name of the UIContext instance.
*/
public String getUIContextInstanceName() {
return _uiContextInstanceName;
}
// /**
// * Get a method unit describing the suite method for this test.
// * @return boiler plate suite method
// */
// private MethodUnit getSuiteMethod() {
// MethodUnit m = new MethodUnit("suite");
// String comment = "/** @return the test suite" + NEW_LINE + "*/";
// m.setComment(comment);
// m.addModifier(Modifier.PUBLIC);
// m.addModifier(Modifier.STATIC);
// m.setReturnType("Test");
//
// StringBuffer sb = new StringBuffer();
// sb.append("return new ActivePDETestSuite(").append(NEW_LINE).
// append(getName()).append(".class, ").
// append(getName()).append(".class.getName());").append(NEW_LINE);
// CodeBlock block = new CodeBlock(sb.toString());
// m.setBody(block);
// return m;
// }
// /**
// * Get the boiler plate setup method body.
// * @return boiler plate setup method body
// */
// private MethodUnit getSetUpMethod() {
// MethodUnit m = new MethodUnit("setUp");
// String comment = "/* @see junit.framework.TestCase#setUp()" + NEW_LINE + "*/";
// m.setComment(comment);
// m.addModifier(Modifier.PROTECTED);
// m.addThrows("Exception");
//
// StringBuffer sb = new StringBuffer();
// sb.append("super.setUp();").append(NEW_LINE).
// append("_uiContext = UIContextFactory.createContext(Display.getCurrent());").append(NEW_LINE).
// append("registerWidgetInfo();").append(NEW_LINE);
//
// CodeBlock block = new CodeBlock(sb.toString());
// m.setBody(block);
// return m;
// }
/**
* Get the boiler plate tearDown method.
* @return boiler plate tearDown method body
*/
protected MethodUnit getTearDownMethod() {
MethodUnit m = new MethodUnit("tearDown");
String comment = "/* @see junit.framework.TestCase#tearDown()" + NEW_LINE + "*/";
m.setComment(comment);
m.addModifier(Modifier.PROTECTED);
m.addThrows("Exception");
StringBuffer sb = new StringBuffer();
sb.append("_uiContext.dispose();").append(NEW_LINE).
append("super.tearDown();").append(NEW_LINE);
CodeBlock block = new CodeBlock(sb.toString());
m.setBody(block);
return m;
}
// /**
// * Get the boiler plate registerWidgetInfo method.
// * NOTE: if there were no widget registrations, this will return null.
// * @return boiler plate registerWidgetInfo method body
// */
// protected MethodUnit getWidgetRegistrationMethod() {
//
// Set mappings = mapper.getMappings();
//
// /*
// * Fast return if there are no mapppings to register
// */
// if (mappings.isEmpty())
// return null;
//
// MethodUnit m = new MethodUnit("registerWidgetInfo");
// String comment = "/* Register widgets." + NEW_LINE + "*/";
// m.setComment(comment);
// m.addModifier(Modifier.PROTECTED);
//
// StringBuffer sb = new StringBuffer();
// sb.append(getUIContextInitilizationBlock());
//
//
// String constructorCall, key, name;
// WidgetLocator locator;
//
// /*
// * A flag to tell us whether a widget was registered.
// * The no-registration case should not generate a method.
// */
// boolean registeredWidget = false;
//
// for (Iterator iter = mappings.iterator(); iter.hasNext();) {
// Map.Entry mapping = (Map.Entry) iter.next();
// key = mapping.getKey().toString();
// locator = (WidgetLocator)mapping.getValue();
// /*
// * Check for naming conflicts
// */
// name = locator.getData("name");
// //if it's named and there was no conflict, we don't emit a locator
// if (name != null && name.equals(key)) {
// //do nothing
// } else {
//
// //note the registration
// registeredWidget = true;
//
// //if it's named and the name is not the key we have a collision case
// if (name != null && !name.equals(key)) {
// sb.append("//FIXME: name of named widget not used due to naming conflict").append(NEW_LINE);
// }
// //add imports for locator class
// locator.accept(new IWidgetLocatorVisitor() {
// public void visit(WidgetLocator wl) {
// addImport(new ImportUnit(wl.getClass().getName()));
// }
// });
//
// constructorCall = WidgetLocatorService.getJavaString(locator);
// sb.append(getUIContextInstanceName()).append(".register(\"").append(key).append("\", ").append(constructorCall).append(");").append(NEW_LINE);
// }
// }
//
// //if there were no widget registrations return an empty method
// if (!registeredWidget)
// return null;
//
// CodeBlock block = new CodeBlock(sb.toString());
// m.setBody(block);
// return m;
// }
/**
* Get the boiler plate test constructor.
* @return method for the boilerplate constructor
*/
protected MethodUnit getConsMethod() {
// MethodUnit m = new MethodUnit(getName());
// String comment = "/**" + NEW_LINE + "* Create an Instance" + NEW_LINE + "* @param testName" + NEW_LINE + "*/";
// m.setComment(comment);
//
// m.setConstructor(true);
// m.addModifier(Modifier.PUBLIC);
// m.addParameter(new Parameter("String", "testName"));
//
// CodeBlock block = new CodeBlock("super(testName);" + NEW_LINE);
// m.setBody(block);
// return m;
return null;
}
////////////////////////////////////////////////////////////////////////////
//
// Cutom keys
//
////////////////////////////////////////////////////////////////////////////
/* (non-Javadoc)
* @see com.windowtester.codegen.ITestCaseBuilder#getKeyEventImport()
*/
public ImportUnit getKeyEventImport() {
return new ImportUnit("org.eclipse.swt.SWT");
}
/* (non-Javadoc)
* @see com.windowtester.codegen.ITestCaseBuilder#getControlKey()
*/
public String getControlKey() {
return "SWT.CTRL";
}
/* (non-Javadoc)
* @see com.windowtester.codegen.ITestCaseBuilder#parseControlKey(com.windowtester.recorder.event.user.SemanticKeyDownEvent)
*/
public String parseControlKey(SemanticKeyDownEvent kde) {
/*
* This has been hacked for awt key events -- needs to be pluggable
*/
String key = kde.getKey();
if (isTab(key))
return "SWT.TAB";
if (isEnter(key))
return "SWT.CR";
switch(kde.getKeyCode()) {
case SWT.ARROW_RIGHT :
return "SWT.ARROW_RIGHT";
case SWT.ARROW_LEFT :
return "SWT.ARROW_LEFT";
case SWT.ARROW_UP :
return "SWT.ARROW_UP";
case SWT.ARROW_DOWN :
return "SWT.ARROW_DOWN";
default :
return null;
}
}
/**
* Check for control characters
* @param key - the character to check
* @return true if the key is a control character
*/
protected boolean isControl(String key) {
return key != null && Character.isISOControl(key.charAt(0));
}
/**
* Check for a backspace.
* @param key - the character to check
* @return true if the key is a backspace
*/
protected boolean isBackSpace(String key) {
return key.charAt(0) == '\b';
}
/**
* Check for a tab.
* @param key - the character to check
* @return true if the key is a tab
*/
protected boolean isTab(String key) {
return key.charAt(0) == '\t';
}
/**
* Check for an enter key.
* @param key - the character to check
* @return true if the key is an 'enter'
*/
protected boolean isEnter(String key) {
return key.charAt(0) == ICodeGenConstants.NEW_LINE.charAt(0) || key.charAt(0) == '\r';
}
////////////////////////////////////////////////////////////////////////////
//
// Construction
//
////////////////////////////////////////////////////////////////////////////
/* (non-Javadoc)
* @see com.windowtester.codegen.ISourceTypeBuilder#add(com.windowtester.codegen.assembly.CodeBlock)
*/
public void add(CodeBlock block) {
if (!_initialized) {
init();
_initialized = true;
}
_current = block;
_root.addChild(block);
}
/* (non-Javadoc)
* @see com.windowtester.codegen.ISourceTypeBuilder#assemble()
*/
public IType assemble() {
// AST ast = new AST();
// CompilationUnit unit = ast.newCompilationUnit();
// PackageDeclaration packageDeclaration = ast.newPackageDeclaration();
// packageDeclaration.setName(ast.newSimpleName("test"));
// unit.setPackage(packageDeclaration);
//
// for (Iterator iter = getImports().iterator(); iter.hasNext();) {
// ImportUnit element = (ImportUnit) iter.next();
//
// }
return null;
}
/* (non-Javadoc)
* @see com.windowtester.codegen.ITestCaseBuilder#build()
*/
public String build() {
// //main has been constructed now, so the mapper is populated with references
// //we need to register
// if (getMapper().getMappings().size() > 0) {
// addMethod(getWidgetRegistrationMethod());
//
// // add registered types next:
// Set mappings = mapper.getMappings();
// for (Iterator iter = mappings.iterator(); iter.hasNext();) {
// Map.Entry entry = (Map.Entry) iter.next();
// WidgetLocator info = (WidgetLocator) entry.getValue();
// info.accept(new IWidgetLocatorVisitor() {
// public void visit(WidgetLocator info) {
// addImport(new ImportUnit(info.getTargetClass()
// .getName()));
// }
// });
// }
//
// }
return getStringBuilder().build();
}
/* (non-Javadoc)
* @see com.windowtester.codegen.ISourceTypeBuilder#getCurrentBlock()
*/
public CodeBlock getCurrentBlock() {
return _current;
}
public CodeBlock getRootBlock() {
return _root;
}
/**
* Set the current root pointer to this block
* @param block
*/
public void setCurrentRoot(CodeBlock block) {
_root = block;
}
/* (non-Javadoc)
* @see com.windowtester.codegen.ITestCaseBuilder#getFreshVariable(java.lang.String)
*/
public String getFreshVariable(String string) {
// TODO [author=pq] not clear if we need to generate variables anymore
throw new UnsupportedOperationException();
}
/**
* @see com.windowtester.codegen.ITestCaseBuilder#getFreshMethod(java.lang.String)
*/
public String getFreshMethod(String prefix) {
return new FreshMethodNameFinder(getMethods()).find(prefix);
}
// /**
// * @see com.windowtester.codegen.ITestCaseBuilder#getMapper()
// */
// public WidgetMapper getMapper() {
// return mapper;
// }
/* (non-Javadoc)
* @see com.windowtester.codegen.ITestCaseBuilder#getSetupHandlers()
*/
public ISetupHandler[] getSetupHandlers() {
return handlers;
}
}