blob: 3fb705dfb98046b34a0270c8c285e591a3db233b [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.0 (the "License"); you
* may not use this file except in compliance with the License. You may obtain a
* copy of the License at
*
* http://www.eclipse.org/org/documents/epl-v10.php
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.ide.eclipse.tests.functests.sampleProjects;
import com.android.SdkConstants;
import com.android.ide.eclipse.adt.AdtUtils;
import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectCreator;
import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState;
import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState.Mode;
import com.android.ide.eclipse.tests.SdkLoadingTestCase;
import com.android.sdklib.IAndroidTarget;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.widgets.Display;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Test case that verifies all SDK sample projects can be imported, and built in
* Eclipse.
* <p/>
* TODO: add support for deploying apps onto emulator and verifying successful
* execution there
*
*/
public class SampleProjectTest extends SdkLoadingTestCase {
private static final Logger sLogger = Logger.getLogger(SampleProjectTest.class.getName());
/**
* Finds all samples projects in set SDK and verify they can be built in Eclipse.
* <p/>
* TODO: add install and run on emulator test
* @throws CoreException
*/
public void testSamples() throws CoreException {
// TODO: For reporting purposes, it would be better if a separate test success or failure
// could be reported for each sample
IAndroidTarget[] targets = getSdk().getTargets();
for (IAndroidTarget target : targets) {
doTestSamplesForTarget(target);
}
}
private void doTestSamplesForTarget(IAndroidTarget target) throws CoreException {
String path = target.getPath(IAndroidTarget.SAMPLES);
File samples = new File(path);
if (samples.isDirectory()) {
File[] files = samples.listFiles();
for (File file : files) {
if (file.isDirectory()) {
doTestSampleProject(file.getName(), file.getAbsolutePath(), target);
}
}
}
}
/**
* Tests the sample project with the given name
*
* @param target - SDK target of project
* @param name - name of sample project to test
* @param path - absolute file system path
* @throws CoreException
*/
private void doTestSampleProject(String name, String path, IAndroidTarget target)
throws CoreException {
IProject iproject = null;
try {
sLogger.log(Level.INFO, String.format("Testing sample %s for target %s", name,
target.getName()));
prepareProject(path, target);
IRunnableContext context = new IRunnableContext() {
@Override
public void run(boolean fork, boolean cancelable, IRunnableWithProgress runnable)
throws InvocationTargetException, InterruptedException {
runnable.run(new NullProgressMonitor());
}
};
NewProjectWizardState state = new NewProjectWizardState(Mode.SAMPLE);
state.projectName = name;
state.target = target;
state.packageName = "com.android.samples";
state.activityName = name;
state.applicationName = name;
state.chosenSample = new File(path);
state.useDefaultLocation = false;
state.createActivity = false;
NewProjectCreator creator = new NewProjectCreator(state, context);
creator.createAndroidProjects();
iproject = validateProjectExists(name);
validateNoProblems(iproject);
}
catch (CoreException e) {
sLogger.log(Level.SEVERE,
String.format("Unexpected exception when creating sample project %s " +
"for target %s", name, target.getName()));
throw e;
} finally {
if (iproject != null) {
iproject.delete(false, true, new NullProgressMonitor());
}
}
}
private void prepareProject(String path, IAndroidTarget target) {
if (target.getVersion().isPreview()) {
// need to explicitly set preview's version in manifest for project to compile
final String manifestPath = path + File.separatorChar +
SdkConstants.FN_ANDROID_MANIFEST_XML;
AndroidManifestWriter manifestWriter =
AndroidManifestWriter.parse(manifestPath);
assertNotNull(String.format("could not read manifest %s", manifestPath),
manifestWriter);
assertTrue(manifestWriter.setMinSdkVersion(target.getVersion().getApiString()));
}
}
private IProject validateProjectExists(String name) {
IProject iproject = getIProject(name);
assertTrue(String.format("%s project not created", name), iproject.exists());
assertTrue(String.format("%s project not opened", name), iproject.isOpen());
return iproject;
}
private IProject getIProject(String name) {
IProject iproject = ResourcesPlugin.getWorkspace().getRoot()
.getProject(name);
return iproject;
}
private void validateNoProblems(IProject iproject) throws CoreException {
waitForBuild(iproject);
boolean hasErrors = false;
StringBuilder failureBuilder = new StringBuilder(String.format("%s project has errors:",
iproject.getName()));
IMarker[] markers = iproject.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE);
if (markers != null && markers.length > 0) {
// the project has marker(s). even though they are "problem" we
// don't know their severity. so we loop on them and figure if they
// are warnings or errors
for (IMarker m : markers) {
int s = m.getAttribute(IMarker.SEVERITY, -1);
if (s == IMarker.SEVERITY_ERROR) {
hasErrors = true;
failureBuilder.append("\n");
failureBuilder.append(m.getAttribute(IMarker.MESSAGE, ""));
}
}
}
failureBuilder.append("Project location: " + AdtUtils.getAbsolutePath(iproject));
assertFalse(failureBuilder.toString(), hasErrors);
}
/**
* Waits for build to complete.
*
* @param iproject
*/
private void waitForBuild(final IProject iproject) {
final BuiltProjectDeltaVisitor deltaVisitor = new BuiltProjectDeltaVisitor(iproject);
IResourceChangeListener newBuildListener = new IResourceChangeListener() {
@Override
public void resourceChanged(IResourceChangeEvent event) {
try {
event.getDelta().accept(deltaVisitor);
}
catch (CoreException e) {
fail();
}
}
};
iproject.getWorkspace().addResourceChangeListener(newBuildListener,
IResourceChangeEvent.POST_BUILD);
// poll build listener to determine when build is done
// loop max of 1200 times * 50 ms = 60 seconds
final int maxWait = 1200;
for (int i=0; i < maxWait; i++) {
if (deltaVisitor.isProjectBuilt()) {
return;
}
try {
Thread.sleep(50);
}
catch (InterruptedException e) {
// ignore
}
if (Display.getCurrent() != null) {
Display.getCurrent().readAndDispatch();
}
}
sLogger.log(Level.SEVERE, "expected build event never happened?");
fail(String.format("Expected build event never happened for %s", iproject.getName()));
}
/**
* Scans a given IResourceDelta looking for a "build event" change for given IProject
*
*/
private class BuiltProjectDeltaVisitor implements IResourceDeltaVisitor {
private IProject mIProject;
private boolean mIsBuilt;
public BuiltProjectDeltaVisitor(IProject iproject) {
mIProject = iproject;
mIsBuilt = false;
}
@Override
public boolean visit(IResourceDelta delta) {
if (mIProject.equals(delta.getResource())) {
setBuilt(true);
return false;
}
return true;
}
private synchronized void setBuilt(boolean b) {
mIsBuilt = b;
}
public synchronized boolean isProjectBuilt() {
return mIsBuilt;
}
}
}