diff --git a/compiler/testData/android/converter/AndroidManifest.xml b/compiler/testData/android/converter/singleFile/AndroidManifest.xml similarity index 100% rename from compiler/testData/android/converter/AndroidManifest.xml rename to compiler/testData/android/converter/singleFile/AndroidManifest.xml diff --git a/compiler/testData/android/converter/singleFile/MyActivity.kt b/compiler/testData/android/converter/singleFile/MyActivity.kt new file mode 100644 index 00000000000..3d61c9fb897 --- /dev/null +++ b/compiler/testData/android/converter/singleFile/MyActivity.kt @@ -0,0 +1,27 @@ +package com.myapp + +import android.app.Activity +import android.view.View +import android.widget.* + +class MyActivity(): Activity() { + val textViewWidget = TextView() + val editTextWidget = EditText() + val buttonWidget = Button() + + override fun findViewById(id: Int): View? { + return when (id) { + R.id.textView1 -> textViewWidget + R.id.password -> editTextWidget + R.id.login -> buttonWidget + else -> null + } + } + + fun test(): String { + return if (password.toString() == "EditText" && + textView1.toString() == "TextView" && + login.toString() == "Button" ) + "OK" else "NOTOK" + } +} \ No newline at end of file diff --git a/compiler/testData/android/converter/singleFile/R.kt b/compiler/testData/android/converter/singleFile/R.kt index 26312f1cc99..3e9f1eb1b9f 100644 --- a/compiler/testData/android/converter/singleFile/R.kt +++ b/compiler/testData/android/converter/singleFile/R.kt @@ -1,13 +1,14 @@ +package com.myapp class R { class id { class object { val item_detail_container = 0 - val textView1 = 0 - val password = 0 - val textView2 = 0 - val passwordConfirmation = 0 - val login = 0 + val textView1 = 1 + val password = 2 + val textView2 = 3 + val passwordConfirmation = 4 + val login = 5 } } } \ No newline at end of file diff --git a/compiler/testData/android/converter/singleFile/layout.kt b/compiler/testData/android/converter/singleFile/layout.kt index b5313bcf548..c8ebd646620 100644 --- a/compiler/testData/android/converter/singleFile/layout.kt +++ b/compiler/testData/android/converter/singleFile/layout.kt @@ -1,16 +1,18 @@ +package com.myapp + import android.app.Activity import android.view.View import android.widget.* val Activity.item_detail_container: FrameLayout - get() = findViewById(R.id.item_detail_container) as FrameLayout + get() = findViewById(0) as FrameLayout val Activity.textView1: TextView - get() = findViewById(R.id.textView1) as TextView + get() = findViewById(0) as TextView val Activity.password: EditText - get() = findViewById(R.id.password) as EditText + get() = findViewById(0) as EditText val Activity.login: Button - get() = findViewById(R.id.login) as Button + get() = findViewById(0) as Button diff --git a/compiler/testData/android/converter/singleFile/res/layout.xml b/compiler/testData/android/converter/singleFile/res/layout/layout.xml similarity index 100% rename from compiler/testData/android/converter/singleFile/res/layout.xml rename to compiler/testData/android/converter/singleFile/res/layout/layout.xml diff --git a/compiler/testData/android/fakeHelpers/Activity.kt b/compiler/testData/android/fakeHelpers/Activity.kt index 88f02ca8dbe..08eb86d4f26 100644 --- a/compiler/testData/android/fakeHelpers/Activity.kt +++ b/compiler/testData/android/fakeHelpers/Activity.kt @@ -1,6 +1,6 @@ package android.app import android.view.View -trait Activity { - fun findViewById(id: Int): View? +abstract class Activity { + open abstract fun findViewById(id: Int): View? } \ No newline at end of file diff --git a/compiler/testData/android/fakeHelpers/View.kt b/compiler/testData/android/fakeHelpers/View.kt index 7b26684cb6e..c5b8f7610f0 100644 --- a/compiler/testData/android/fakeHelpers/View.kt +++ b/compiler/testData/android/fakeHelpers/View.kt @@ -1,3 +1,3 @@ package android.view -class View \ No newline at end of file +trait View \ No newline at end of file diff --git a/compiler/testData/android/fakeHelpers/Widgets.kt b/compiler/testData/android/fakeHelpers/Widgets.kt index 587457ebbf0..2f1d5ba5884 100644 --- a/compiler/testData/android/fakeHelpers/Widgets.kt +++ b/compiler/testData/android/fakeHelpers/Widgets.kt @@ -1,6 +1,16 @@ package android.widget -class EditText -class TextView -class Button -class FrameLayout \ No newline at end of file +import android.view.View + +class EditText: View { + override fun toString(): String {return "EditText"} +} +class TextView: View { + override fun toString(): String {return "TextView"} +} +class Button: View { + override fun toString(): String {return "Button"} +} +class FrameLayout: View { + override fun toString(): String {return "FrameLayout"} +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/AndroidXmlTest.java b/compiler/tests/org/jetbrains/jet/codegen/AndroidXmlTest.java deleted file mode 100644 index 1fa42858570..00000000000 --- a/compiler/tests/org/jetbrains/jet/codegen/AndroidXmlTest.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.jetbrains.jet.codegen; - -import com.intellij.openapi.util.Disposer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.ConfigurationKind; -import org.jetbrains.jet.JetTestCaseBuilder; -import org.jetbrains.jet.JetTestUtils; -import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; -import org.jetbrains.jet.lang.psi.JetFile; -import org.jetbrains.jet.lang.resolve.android.AndroidUIXmlParser; -import org.jetbrains.jet.lang.resolve.android.CliAndroidUIXmlParser; -import org.jetbrains.jet.test.TestCaseWithTmpdir; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Scanner; - -public class AndroidXmlTest extends TestCaseWithTmpdir { - - private final File singleFileDir = new File(getTestDataPath() + "/converter/singleFile/res/"); - private final File fakeActivitySrc = new File(getTestDataPath() + "/fakeHelpers/Activity.kt"); - private final File fakeViewSrc = new File(getTestDataPath() + "/fakeHelpers/View.kt"); - private final File fakeWidgetsSrc = new File(getTestDataPath() + "/fakeHelpers/Widgets.kt"); - - @Override - public void setUp() throws Exception { - super.setUp(); - } - - @NotNull - private static String getTestDataPath() { - return JetTestCaseBuilder.getTestDataPathBase() + "/android"; - } - - @SuppressWarnings({"ResultOfMethodCallIgnored", "IOResourceOpenedButNotSafelyClosed"}) - protected static String loadOrCreate(File file, String data) throws IOException { - try { - return new Scanner(file, "UTF-8" ).useDelimiter("\\A").next(); - } catch (IOException e) { - file.createNewFile(); - FileWriter fileWriter = new FileWriter(file); - fileWriter.write(data); - fileWriter.close(); - fail("Empty expected data, creating from actual"); - return data; - } - } - - public void testCompileResult() throws Exception { - JetCoreEnvironment jetCoreEnvironment = JetTestUtils.createEnvironmentWithMockJdkAndIdeaAnnotations(getTestRootDisposable(), - ConfigurationKind.ALL); - String text = new CliAndroidUIXmlParser(jetCoreEnvironment.getProject(), singleFileDir.getAbsolutePath()).parseToString(); - - JetFile psiFile = JetTestUtils.createFile("dummy.kt", text, jetCoreEnvironment.getProject()); - JetFile fakeActivity = JetTestUtils.loadJetFile(jetCoreEnvironment.getProject(), fakeActivitySrc); - JetFile fakeView = JetTestUtils.loadJetFile(jetCoreEnvironment.getProject(), fakeViewSrc); - JetFile fakeWidgets = JetTestUtils.loadJetFile(jetCoreEnvironment.getProject(), fakeWidgetsSrc); - JetFile fakeRClass = JetTestUtils.loadJetFile(jetCoreEnvironment.getProject(), - new File(getTestDataPath() + "/converter/singleFile/R.kt")); - List files = new ArrayList(); - files.add(psiFile); - files.add(fakeActivity); - files.add(fakeView); - files.add(fakeRClass); - files.add(fakeWidgets); - GenerationUtils.compileManyFilesGetGenerationStateForTest(jetCoreEnvironment.getProject(), files); - Disposer.dispose(getTestRootDisposable()); - } - - public void testConverterOneFile() throws Exception { - JetCoreEnvironment jetCoreEnvironment = JetTestUtils.createEnvironmentWithMockJdkAndIdeaAnnotations(getTestRootDisposable(), - ConfigurationKind.ALL); - AndroidUIXmlParser parser = new CliAndroidUIXmlParser(jetCoreEnvironment.getProject(), singleFileDir.getAbsolutePath()); - - String actual = parser.parseToString(); - String expected = loadOrCreate(new File(getTestDataPath() + "/converter/singleFile/layout.kt"), actual); - - assertEquals(expected, actual); - } -} diff --git a/compiler/tests/org/jetbrains/jet/lang/resolve/android/AndroidXmlTest.java b/compiler/tests/org/jetbrains/jet/lang/resolve/android/AndroidXmlTest.java new file mode 100644 index 00000000000..ab3f04a1cd5 --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/lang/resolve/android/AndroidXmlTest.java @@ -0,0 +1,175 @@ +package org.jetbrains.jet.lang.resolve.android; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.*; +import org.jetbrains.jet.cli.jvm.JVMConfigurationKeys; +import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; +import org.jetbrains.jet.codegen.GenerationUtils; +import org.jetbrains.jet.codegen.state.GenerationState; +import org.jetbrains.jet.config.CompilerConfiguration; +import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.test.TestCaseWithTmpdir; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.*; + +public class AndroidXmlTest extends TestCaseWithTmpdir { + + private final File singleFileDir = new File(getTestDataPath() + "/converter/singleFile/res/layout/"); + private final File fakeActivitySrc = new File(getTestDataPath() + "/fakeHelpers/Activity.kt"); + private final File fakeViewSrc = new File(getTestDataPath() + "/fakeHelpers/View.kt"); + private final File fakeWidgetsSrc = new File(getTestDataPath() + "/fakeHelpers/Widgets.kt"); + private final File fakeMyActivitySrc = new File(getTestDataPath() + "/converter/singleFile/MyActivity.kt"); + private final String singleFileResPath = getTestDataPath() + "/converter/singleFile/res/layout/"; + + public static class ByteClassLoader extends URLClassLoader { + + private Queue q; + private final Map extraClassDefs = new HashMap(); + + @NotNull + @Override + protected Class findClass(String name) throws ClassNotFoundException { + final Class aClass = extraClassDefs.get(name); + if (aClass != null) return aClass; + else return super.findClass(name); + } + + public ByteClassLoader(URL[] urls, ClassLoader parent, List files) { + super(urls, parent); + q = new LinkedList(files); + } + + private void loadBytes(OutputFile f) { + try { + final byte[] b = f.asByteArray(); + final String name = relPathToClassName(f.getRelativePath()); + final Class aClass = defineClass(name, b, 0, b.length); + extraClassDefs.put(name, aClass); + q.remove(f); + } catch (NoClassDefFoundError e) { + OutputFile found = findByClassName(e.getMessage()); + if (found == null) throw e; + else { + loadBytes(found); + loadBytes(f); + } + } + } + + public void loadFiles() { + OutputFile f = q.peek(); + while (f != null) { + loadBytes(f); + f = q.peek(); + } + } + + private OutputFile findByClassName(String name) { + String path = classNameToRelPath(name); + for (OutputFile file: q) + if (file.getRelativePath().equals(path)) return file; + return null; + } + + private String relPathToClassName(String path) { + return path.replace(".class", "").replace("/", "."); + } + + private String classNameToRelPath(String name) { + return name.replace(".", "/").concat(".class"); + } + } + + @Override + public void setUp() throws Exception { + super.setUp(); + } + + @NotNull + private static String getTestDataPath() { + return JetTestCaseBuilder.getTestDataPathBase() + "/android"; + } + + @SuppressWarnings({"ResultOfMethodCallIgnored", "IOResourceOpenedButNotSafelyClosed"}) + protected static String loadOrCreate(File file, String data) throws IOException { + try { + return new Scanner(file, "UTF-8" ).useDelimiter("\\A").next(); + } catch (IOException e) { + file.createNewFile(); + FileWriter fileWriter = new FileWriter(file); + fileWriter.write(data); + fileWriter.close(); + fail("Empty expected data, creating from actual"); + return data; + } + } + + private GenerationState compileManyFilesGetGenerationState(List files, String resPath) throws IOException { + JetCoreEnvironment jetCoreEnvironment = getEnvironment(resPath); + Project project = jetCoreEnvironment.getProject(); + + List jetFiles = new ArrayList(files.size()); + for (File file: files) { + jetFiles.add(JetTestUtils.loadJetFile(project, file)); + } + + return GenerationUtils.compileManyFilesGetGenerationStateForTest(project, jetFiles); + } + + private JetCoreEnvironment getEnvironment(String resPath) { + CompilerConfiguration configuration = JetTestUtils.compilerConfigurationForTests(ConfigurationKind.ALL, + TestJdkKind.MOCK_JDK); + configuration.put(JVMConfigurationKeys.ANDROID_RES_PATH, resPath); + return JetCoreEnvironment.createForTests(getTestRootDisposable(), + configuration); + } + + public void testCompileResult() throws Exception { + List files = addDefaultFiles(); + + compileManyFilesGetGenerationState(files, singleFileResPath); + Disposer.dispose(getTestRootDisposable()); + } + + private List addDefaultFiles() { + final File fakeRClass = new File(getTestDataPath() + "/converter/singleFile/R.kt"); + List files = new ArrayList(); + files.add(fakeActivitySrc); + files.add(fakeViewSrc); + files.add(fakeRClass); + files.add(fakeWidgetsSrc); + return files; + } + + public void testConverterOneFile() throws Exception { + JetCoreEnvironment jetCoreEnvironment = getEnvironment(singleFileResPath); + AndroidUIXmlParser parser = new CliAndroidUIXmlParser(jetCoreEnvironment.getProject(), singleFileDir.getAbsolutePath()); + + String actual = parser.parseToString(); + String expected = loadOrCreate(new File(getTestDataPath() + "/converter/singleFile/layout.kt"), actual); + + assertEquals(expected, actual); + } + + public void testGeneratedByteCode() throws Exception { + + String resPath = getTestDataPath() + "/converter/singleFile/res/layout/"; + List files = addDefaultFiles(); + + files.add(fakeMyActivitySrc); + GenerationState state = compileManyFilesGetGenerationState(files, resPath); + ByteClassLoader classLoader = new ByteClassLoader(new URL[] {}, getClass().getClassLoader(), state.getFactory().asList()); + classLoader.loadFiles(); + final Class activity = classLoader.findClass("com.myapp.MyActivity"); + String res =(String) activity.getMethod("test").invoke(activity.newInstance()); + Disposer.dispose(getTestRootDisposable()); + assertEquals("OK", res); + } +}