package com.mobilesorcery.sdk.testing.internal.ui.wizards;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.text.MessageFormat;
import java.util.Set;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.dialogs.ContainerSelectionDialog;
import com.mobilesorcery.sdk.core.IBuildConfiguration;
import com.mobilesorcery.sdk.core.MoSyncProject;
import com.mobilesorcery.sdk.core.Util;
import com.mobilesorcery.sdk.internal.builder.MoSyncBuilderVisitor;
import com.mobilesorcery.sdk.testing.TestPlugin;
import com.mobilesorcery.sdk.testing.project.MoSyncProjectTestManager;
import com.mobilesorcery.sdk.ui.BuildConfigurationsContentProvider;
import com.mobilesorcery.sdk.ui.BuildConfigurationsLabelProvider;
public class TestCaseCreationPage extends WizardPage {
class PageListener implements Listener {
public void handleEvent(Event event) {
if (event.type == SWT.Selection && event.widget == projectButton) {
handleProjectButtonSelected();
}
updateUI();
}
}
private static final String TEST_SETUP_FILE_NAME = "__ide_setup.cpp";
private MoSyncProject initialProject;
private Text sourceFolder;
private Button projectButton;
private PageListener listener;
private Text testCaseName;
private Group buildConfigs;
private ComboViewer debugBuildCfgs;
private ComboViewer releaseBuildCfgs;
private MoSyncProject previousProject;
private Button createSetupFile;
private boolean hasSetupFile;
protected TestCaseCreationPage(MoSyncProject initialProject) {
super("ProjectSelection");
setTitle("Select project to configure for testing");
this.initialProject = initialProject;
}
public void validate() {
String message = null;
int severity = IMessageProvider.INFORMATION;
MoSyncProject projectToConfigure = getProjectToConfigure();
IResource sourceFolderFile = getSourceFolderFile();
if (sourceFolderFile == null || !sourceFolderFile.getProject().exists()) {
message = "Please specify a valid source folder (project/path)";
severity = IMessageProvider.ERROR;
} else if (sourceFolderFile.exists()) {
if (projectToConfigure == null) {
message = "The source folder must be located in a MoSync enabled project";
severity = IMessageProvider.ERROR;
} else {
boolean isTestFolder = new MoSyncProjectTestManager(projectToConfigure).isTestResource(sourceFolderFile);
if (!isTestFolder && !Util.isEmptyDirectory(sourceFolderFile.getLocation().toFile())) {
message = MessageFormat.format("Directory {0} is not empty - this may cause build problems.", sourceFolderFile.getFullPath());
severity = IMessageProvider.WARNING;
}
}
}
String testCaseName = this.testCaseName.getText();
if (message == null && Util.isEmpty(testCaseName)) {
message = "Test case name cannot be empty";
severity = IMessageProvider.ERROR;
} else if (message == null) {
IPath testCasePath = sourceFolderFile.getLocation().append(testCaseName);
if (testCasePath.segmentCount() > 1) {
IFile testCaseResource = ResourcesPlugin.getWorkspace().getRoot().getFile(testCasePath);
if (!MoSyncBuilderVisitor.hasExtension(testCaseResource, MoSyncBuilderVisitor.CPP_SOURCE_FILE_EXTS)) {
message = "Test case name must be a c++ file";
severity = IMessageProvider.ERROR;
}
}
}
if (getTestCaseFile() != null && getTestCaseFile().exists()) {
message = "Test case file already exists";
severity = IMessageProvider.ERROR;
}
setMessage(message, severity);
setPageComplete(severity != IMessageProvider.ERROR);
}
private MoSyncProject getProjectToConfigure() {
IResource sourceFolderFile = getSourceFolderFile();
if (sourceFolderFile == null) {
return null;
}
return MoSyncProject.create(sourceFolderFile.getProject());
}
public void createControl(Composite parent) {
Composite control = new Composite(parent, SWT.NONE);
control.setLayout(new GridLayout(3, false));
listener = new PageListener();
createSourceFolderEditor(control);
createTestCaseEditor(control);
createBuildConfigsGroup(control);
initUI();
setControl(control);
}
private void createBuildConfigsGroup(Composite control) {
buildConfigs = new Group(control, SWT.NONE);
buildConfigs.setText("Build &Configurations");
buildConfigs.setLayout(new GridLayout(2, false));
buildConfigs.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false, 3, 1));
Label buildConfigsInfo = new Label(buildConfigs, SWT.WRAP);
buildConfigsInfo.setText("Select configurations to base test configurations on:\n" +
"(Include paths, libraries, etc from the selected configurations will be used " +
"by the test configuration.)");
buildConfigsInfo.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false, 2, 1));
Label releaseBuildCfgsLabel = new Label(buildConfigs, SWT.NONE);
releaseBuildCfgsLabel.setText("Test:");
releaseBuildCfgs = new ComboViewer(buildConfigs, SWT.READ_ONLY);
releaseBuildCfgs.getCombo().setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
Label debugBuildCfgsLabel = new Label(buildConfigs, SWT.NONE);
debugBuildCfgsLabel.setText("Test/Debug:");
debugBuildCfgs = new ComboViewer(buildConfigs, SWT.READ_ONLY);
debugBuildCfgs.getCombo().setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
}
protected void createSourceFolderEditor(Composite parent) {
Label sourceFolderLabel = new Label(parent, SWT.NONE);
sourceFolderLabel.setText("&Source Folder");
sourceFolder = new Text(parent, SWT.SINGLE | SWT.BORDER);
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
sourceFolder.setLayoutData(gd);
sourceFolder.setText(createInitialTestFolder());
sourceFolder.addListener(SWT.Modify, listener);
projectButton = new Button(parent, SWT.PUSH);
projectButton.setText("Browse...");
projectButton.addListener(SWT.Selection, listener);
}
private String createInitialTestFolder() {
if (initialProject != null) {
return new Path(initialProject.getWrappedProject().getName(), "/test").toPortableString();
}
return "";
}
private void createTestCaseEditor(Composite parent) {
Label testCaseNameLabel = new Label(parent, SWT.NONE);
testCaseNameLabel.setText("Test File &Name");
testCaseName = new Text(parent, SWT.SINGLE | SWT.BORDER);
testCaseName.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1));
testCaseName.addListener(SWT.Modify, listener);
createSetupFile = new Button(parent, SWT.CHECK);
createSetupFile.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1));
createSetupFile.setText("Integrate test runner with IDE (will generate a setup file)");
}
protected void handleProjectButtonSelected() {
IContainer container = selectContainer();
if (container == null) {
return;
}
String containerName = container.getFullPath().toPortableString();
sourceFolder.setText(containerName);
updateUI();
}
private void initUI() {
hasSetupFile = hasSetupFile(initialProject);
updateUI();
}
private boolean hasSetupFile(MoSyncProject project) {
if (project == null) {
return false;
}
MoSyncProjectTestManager mgr = new MoSyncProjectTestManager(project);
Set<IPath> testResources = mgr.getTestResources();
for (IPath testResource : testResources) {
IFile setupFile = project.getWrappedProject().getFile(testResource.append(TEST_SETUP_FILE_NAME));
if (setupFile.exists()) {
return true;
}
}
return false;
}
private void updateUI() {
validate();
initialProject = getSourceFolderFile() == null ? null : MoSyncProject.create(getSourceFolderFile().getProject());
boolean showDebugCfgs = false;
boolean showReleaseCfgs = false;
if (previousProject != initialProject) {
hasSetupFile = hasSetupFile(initialProject);
previousProject = initialProject;
if (initialProject != null) {
Set<String> debugCfgs = initialProject.getBuildConfigurationsOfType(IBuildConfiguration.DEBUG_TYPE);
Set<String> releaseCfgs = initialProject.getBuildConfigurationsOfType(IBuildConfiguration.RELEASE_TYPE);
Set<String> testCfgs = initialProject.getBuildConfigurationsOfType(TestPlugin.TEST_BUILD_CONFIGURATION_TYPE);
showDebugCfgs = testCfgs.isEmpty() && debugCfgs.size() > 1;
showReleaseCfgs = testCfgs.isEmpty() && releaseCfgs.size() > 1;
debugBuildCfgs.setContentProvider(new BuildConfigurationsContentProvider(initialProject, IBuildConfiguration.DEBUG_TYPE));
releaseBuildCfgs.setContentProvider(new BuildConfigurationsContentProvider(initialProject, IBuildConfiguration.RELEASE_TYPE));
debugBuildCfgs.setLabelProvider(new BuildConfigurationsLabelProvider(initialProject));
releaseBuildCfgs.setLabelProvider(new BuildConfigurationsLabelProvider(initialProject));
debugBuildCfgs.setInput(initialProject);
releaseBuildCfgs.setInput(initialProject);
if (debugCfgs.size() > 0) {
debugBuildCfgs.setSelection(new StructuredSelection(debugCfgs.toArray()[0]));
}
if (releaseCfgs.size() > 0) {
releaseBuildCfgs.setSelection(new StructuredSelection(releaseCfgs.toArray()[0]));
}
}
}
createSetupFile.setSelection(!hasSetupFile);
createSetupFile.setVisible(!hasSetupFile);
buildConfigs.setVisible(showDebugCfgs || showReleaseCfgs);
debugBuildCfgs.getCombo().setEnabled(showDebugCfgs);
releaseBuildCfgs.getCombo().setEnabled(showReleaseCfgs);
}
private IContainer selectContainer() {
// MoSyncProjectSelectionDialog dialog = new
// MoSyncProjectSelectionDialog(getShell());
IContainer dialogRoot = initialProject == null ? ResourcesPlugin.getWorkspace().getRoot() : initialProject.getWrappedProject();
ContainerSelectionDialog dialog = new ContainerSelectionDialog(
getShell(), dialogRoot, true,
"Select location of test case source file");
// dialog.setInitialProject(initialProject.getWrappedProject());
// return dialog.selectProject();
if (dialog.open() == ContainerSelectionDialog.OK) {
Object[] result = dialog.getResult();
if (result != null && result.length > 0) {
IPath path = (IPath) result[0];
return (IContainer) ResourcesPlugin.getWorkspace().getRoot().findMember(path, false);
}
}
return null;
}
public IFile configureProject() throws CoreException {
try {
IResource sourceFolderFile = getSourceFolderFile();
// TODO: Not finished.
IProject project = sourceFolderFile.getProject();
MoSyncProjectTestManager tm = new MoSyncProjectTestManager(MoSyncProject.create(project));
IBuildConfiguration debugPrototype = getPrototypeConfiguration(true);
IBuildConfiguration releasePrototype = getPrototypeConfiguration(false);
tm.setPrototypeConfiguration(debugPrototype, true);
tm.setPrototypeConfiguration(releasePrototype, false);
tm.assignTestResource(sourceFolderFile.getProjectRelativePath(), true);
tm.configureProject();
if (createSetupFile.getSelection() && !hasSetupFile) {
createSetupFile();
}
return createMainTestFile();
} catch (Exception e) {
if (e instanceof CoreException) {
throw (CoreException) e;
}
throw new CoreException(new Status(IStatus.ERROR, TestPlugin.PLUGIN_ID, e.getMessage(), e));
}
}
private IBuildConfiguration getPrototypeConfiguration(boolean isDebug) {
ComboViewer source = isDebug ? debugBuildCfgs : releaseBuildCfgs;
IStructuredSelection selection = (IStructuredSelection) source.getSelection();
if (!selection.isEmpty()) {
String cfgId = (String) selection.getFirstElement();
return initialProject.getBuildConfiguration(cfgId);
}
return null;
}
private void createSetupFile() throws IOException, CoreException {
IFile testSetupFile = getTestSetupFile();
createTestFile(testSetupFile, "/test_setup_template.c");
}
private IFile createMainTestFile() throws IOException, CoreException {
IFile testCaseFile = getTestCaseFile();
return createTestFile(testCaseFile, "/test_template.c");
}
private IFile createTestFile(IFile testCaseFile, String templateResource) throws IOException, CoreException {
// TODO: Templates? Several suites per project? One small step at a time.
InputStream is = null;
try {
if (testCaseFile == null) {
throw new CoreException(new Status(IStatus.ERROR, TestPlugin.PLUGIN_ID, "No test case file provided"));
}
IResource testCaseFolder = getSourceFolderFile();
if (!testCaseFolder.exists()) {
IFolder testCaseFolderFolder = (IFolder) testCaseFolder;
testCaseFolderFolder.create(true, true, null);
}
URL template = TestPlugin.getDefault().getBundle().getResource(templateResource);
is = template.openStream();
testCaseFile.create(is, true, null);
return testCaseFile;
} finally {
Util.safeClose(is);
}
}
private IResource getSourceFolderFile() {
Path sourceFolderPath = new Path(sourceFolder.getText());
if (sourceFolderPath.segmentCount() == 0) {
return null;
}
if (sourceFolderPath.segmentCount() == 1) {
return ResourcesPlugin.getWorkspace().getRoot().getProject(sourceFolderPath.lastSegment());
}
IFolder sourceFolderFile = ResourcesPlugin.getWorkspace().getRoot().getFolder(sourceFolderPath);
return sourceFolderFile;
}
private IFile getTestSetupFile() {
return getTestFile(TEST_SETUP_FILE_NAME);
}
private IFile getTestCaseFile() {
return getTestFile(testCaseName.getText());
}
private IFile getTestFile(String name) {
if (getSourceFolderFile() == null) {
return null;
}
IPath testCasePath = getSourceFolderFile().getFullPath().append(name);
IFile testCaseFile = ResourcesPlugin.getWorkspace().getRoot().getFile(testCasePath);
return testCaseFile;
}
}