| /* |
| * 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; |
| } |
| } |
| } |