/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 * * 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.tools.idea.gradle.project; import com.android.builder.model.AndroidProject; import com.android.tools.idea.gradle.GradleSyncState; import com.android.tools.idea.templates.AndroidGradleTestCase; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.intellij.openapi.project.Project; import org.gradle.tooling.model.UnsupportedMethodException; import org.jetbrains.annotations.Nullable; import java.io.*; import java.lang.reflect.*; import java.util.*; public class AndroidGradleProjectDataTest extends AndroidGradleTestCase { MyInterface myProxy; private static void assertProxyCollectionEquals(@Nullable Collection<MyInterface> expected, @Nullable Collection<MyInterface> actual) { if (expected == null) { assertNull(actual); return; } assertNotNull(actual); Iterator<MyInterface> a = expected.iterator(); Iterator<MyInterface> b = actual.iterator(); while (a.hasNext()) { assertTrue(b.hasNext()); assertProxyEquals(a.next(), b.next()); } assertFalse(b.hasNext()); } private static void assertProxyCollectionEquals(@Nullable Map<String, Collection<MyInterface>> expected, @Nullable Map<String, Collection<MyInterface>> actual) { if (expected == null) { assertNull(actual); return; } assertNotNull(actual); assertEquals(expected.keySet(), actual.keySet()); for (String key : expected.keySet()) { assertProxyCollectionEquals(expected.get(key), actual.get(key)); } } private static void assertProxyEquals(MyInterface expected, MyInterface actual) { assertEquals(expected.getString(), actual.getString()); assertEquals(expected.getFile(), actual.getFile()); assertEquals(expected.getNativeBoolean(), actual.getNativeBoolean()); assertEquals(expected.getStringCollection(), actual.getStringCollection()); assertEquals(expected.getBooleanList(), actual.getBooleanList()); assertEquals(expected.getStringSet(), actual.getStringSet()); assertProxyCollectionEquals(expected.getProxyCollection(), actual.getProxyCollection()); assertProxyCollectionEquals(expected.getProxyList(), actual.getProxyList()); assertProxyCollectionEquals(expected.getMapToProxy(), actual.getMapToProxy()); UnsupportedMethodException exception = null; try { expected.doesNotExist(); fail("Original method should throw."); } catch (UnsupportedMethodException e) { // Expected. exception = e; } try { actual.doesNotExist(); fail("Reproxy should also throw."); } catch (UnsupportedMethodException e) { assertEquals(e.getClass(), exception.getClass()); assertEquals(e.getMessage(), exception.getMessage()); } } private static MyInterface createProxyInstance(boolean recurse) { final MyInterfaceImpl delegate = new MyInterfaceImpl(recurse); return (MyInterface)Proxy.newProxyInstance(MyInterface.class.getClassLoader(), new Class[]{MyInterface.class}, new InvocationHandler() { @Override public Object invoke(Object o, Method method, Object[] objects) throws Throwable { try { return method.invoke(delegate, objects); } catch (InvocationTargetException e) { throw e.getCause(); } } }); } private static void assertTypeIsSupported(Package reproxy, Class<?> clazz) { if (!clazz.isPrimitive() && clazz.getPackage().equals(reproxy)) { for (Method method : clazz.getMethods()) { if (Modifier.isPublic(method.getModifiers())) { assertTypeIsSupported(reproxy, method.getReturnType()); } } } else { assertTrue("Unsupported type " + clazz, AndroidGradleProjectData.isSupported(clazz)); } } @Override public void setUp() throws Exception { super.setUp(); myProxy = createProxyInstance(true); } public void testReproxy() throws Exception { MyInterface reproxy = AndroidGradleProjectData.reproxy(MyInterface.class, myProxy); assertNotSame(reproxy, myProxy); assertNotNull(reproxy); assertProxyEquals(myProxy, reproxy); } public void testEquality() throws Exception { MyInterface reproxy = AndroidGradleProjectData.reproxy(MyInterface.class, myProxy); MyInterface reproxy2 = AndroidGradleProjectData.reproxy(MyInterface.class, myProxy); assertNotNull(reproxy); assertNotNull(reproxy2); assertNotSame(reproxy, myProxy); assertFalse(myProxy.equals(reproxy)); assertFalse(myProxy.hashCode() == reproxy.hashCode()); assertFalse(reproxy.equals(myProxy)); assertFalse(reproxy.hashCode() == myProxy.hashCode()); assertTrue(reproxy.equals(reproxy)); assertTrue(reproxy.hashCode() == reproxy.hashCode()); assertFalse(reproxy.equals(reproxy2)); assertFalse(reproxy.hashCode() == reproxy2.hashCode()); assertFalse(reproxy2.equals(reproxy)); assertFalse(reproxy2.hashCode() == reproxy.hashCode()); } public void testToString() throws Exception { MyInterface reproxy = AndroidGradleProjectData.reproxy(MyInterface.class, myProxy); assertNotNull(myProxy.toString()); assertNotNull(reproxy); assertNotNull(reproxy.toString()); } public void testSupportedTypes() throws Exception { assertTypeIsSupported(AndroidProject.class.getPackage(), AndroidProject.class); } public void testEndToEnd() throws Exception { if (!CAN_SYNC_PROJECTS) { System.err.println("AndroidGradleProjectDataTest.testEndToEnd temporarily disabled"); return; } loadProject("projects/projectWithAppandLib"); Project project = myAndroidFacet.getModule().getProject(); GradleSyncState syncState = GradleSyncState.getInstance(project); long previousSyncTime = syncState.getLastGradleSyncTimestamp(); AndroidGradleProjectData data = AndroidGradleProjectData.createFrom(project); assertNotNull(data); Map<String, byte[]> checksums = data.getFileChecksums(); assertEquals(7, checksums.size()); assertContainsElements(checksums.keySet(), "gradle.properties", "local.properties", "build.gradle", "settings.gradle", "app/build.gradle", "lib/build.gradle"); String home = System.getProperty("user.home"); if (home != null) { File userProperties = new File(new File(home), ".gradle/gradle.properties"); assertContainsElements(checksums.keySet(), userProperties.getPath()); } Map<String, AndroidGradleProjectData.ModuleData> modules = data.getModuleData(); assertEquals(3, modules.size()); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(outputStream); oos.writeObject(data); oos.close(); ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); ObjectInputStream ois = new ObjectInputStream(inputStream); AndroidGradleProjectData newData = (AndroidGradleProjectData)ois.readObject(); ois.close(); // Clear the sync state to make sure we set it correctly. syncState.resetTimestamp(); assertTrue(newData.applyTo(project)); assertEquals(previousSyncTime, syncState.getLastGradleSyncTimestamp()); // Test applying without a module. String moduleName = myAndroidFacet.getModule().getName(); Map<String, AndroidGradleProjectData.ModuleData> newModules = newData.getModuleData(); newModules.remove(moduleName); assertFalse(newData.applyTo(project)); } interface MyInterface { String getString(); File getFile(); boolean getNativeBoolean(); @Nullable Collection<String> getStringCollection(); @Nullable Collection<MyInterface> getProxyCollection(); @Nullable List<Boolean> getBooleanList(); @Nullable List<MyInterface> getProxyList(); @Nullable Set<String> getStringSet(); @Nullable Map<String, Collection<MyInterface>> getMapToProxy(); boolean doesNotExist() throws UnsupportedMethodException; } static class MyInterfaceImpl implements MyInterface { final boolean recurse; MyInterfaceImpl(boolean recurse) { this.recurse = recurse; } @Override public String getString() { return "aString"; } @Override public File getFile() { return new File("a/sample/file"); } @Override public boolean getNativeBoolean() { return true; } @Override public Collection<String> getStringCollection() { return Lists.newArrayList("one", "two", "three"); } @Override public Collection<MyInterface> getProxyCollection() { return recurse ? Sets.newHashSet(createProxyInstance(false)) : null; } @Override public List<Boolean> getBooleanList() { return ImmutableList.of(false, true); } @Override public List<MyInterface> getProxyList() { return recurse ? Lists.newArrayList(createProxyInstance(false)) : null; } @Override public Set<String> getStringSet() { return Sets.newHashSet("a", "a", "b"); } @Override public Map<String, Collection<MyInterface>> getMapToProxy() { if (!recurse) return null; return ImmutableMap.<String, Collection<MyInterface>>of("one", Sets.<MyInterface>newHashSet(new MyInterfaceImpl(false)), "two", Lists.newArrayList(createProxyInstance(false), createProxyInstance(false))); } @Override public boolean doesNotExist() throws UnsupportedMethodException { throw new UnsupportedMethodException("This method doesn't exist"); } } }