/* * 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.ide.eclipse.adt.wizards.newproject.StubProjectWizard; import com.android.ide.eclipse.tests.SdkTestCase; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkConstants; 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.swt.widgets.Display; import java.io.File; 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 SdkTestCase { 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); final StubProjectWizard newProjCreator = new StubProjectWizard( name, path, target); newProjCreator.init(null, null); // need to run finish on ui thread since it invokes a perspective switch Display.getDefault().syncExec(new Runnable() { public void run() { newProjCreator.performFinish(); } }); 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, "")); } } } 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() { 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; } 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; } } }