diff --git a/.idea/modules.xml b/.idea/modules.xml index a7a32bf50d1..449020550e8 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -3,6 +3,7 @@ + diff --git a/.idea/runConfigurations/Codegen_Tests_on_Android.xml b/.idea/runConfigurations/Codegen_Tests_on_Android.xml new file mode 100644 index 00000000000..aa4ac011622 --- /dev/null +++ b/.idea/runConfigurations/Codegen_Tests_on_Android.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Kotlin.iml b/Kotlin.iml index 35246be9050..3f39175111a 100644 --- a/Kotlin.iml +++ b/Kotlin.iml @@ -4,6 +4,7 @@ + diff --git a/compiler/android-tests/android-module/AndroidManifest.xml b/compiler/android-tests/android-module/AndroidManifest.xml new file mode 100644 index 00000000000..627a286628c --- /dev/null +++ b/compiler/android-tests/android-module/AndroidManifest.xml @@ -0,0 +1,21 @@ + + + + + + + + + + diff --git a/compiler/android-tests/android-module/ant.properties b/compiler/android-tests/android-module/ant.properties new file mode 100644 index 00000000000..aec48be768c --- /dev/null +++ b/compiler/android-tests/android-module/ant.properties @@ -0,0 +1,18 @@ +# This file is used to override default values used by the Ant build system. +# +# This file must be checked into Version Control Systems, as it is +# integral to the build system of your project. + +# This file is only used by the Ant script. + +# You can use this to override default values such as +# 'source.dir' for the location of your java source folder and +# 'out.dir' for the location of your output folder. + +# You can also use it define how the release builds are signed by declaring +# the following properties: +# 'key.store' for the location of your keystore and +# 'key.alias' for the name of the key to use. +# The password will be asked during the build when you use the 'release' target. + +tested.project.dir=tested-module diff --git a/compiler/android-tests/android-module/build.xml b/compiler/android-tests/android-module/build.xml new file mode 100644 index 00000000000..2d553f57e5f --- /dev/null +++ b/compiler/android-tests/android-module/build.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/compiler/android-tests/android-module/local.properties b/compiler/android-tests/android-module/local.properties new file mode 100644 index 00000000000..fa2279a272b --- /dev/null +++ b/compiler/android-tests/android-module/local.properties @@ -0,0 +1,12 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must *NOT* be checked into Version Control Systems, +# as it contains information specific to your local configuration. + +# location of the SDK. This is only used by Ant +# For customization when using a Version Control System, please read the +# header note. +#sdk.dir=compiler/android-tests/android-module/android-sdk/android-sdk-windows +#sdk.dir.relative=android-sdk/android-sdk-windows + diff --git a/compiler/android-tests/android-module/proguard-project.txt b/compiler/android-tests/android-module/proguard-project.txt new file mode 100644 index 00000000000..f2fe1559a21 --- /dev/null +++ b/compiler/android-tests/android-module/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/compiler/android-tests/android-module/project.properties b/compiler/android-tests/android-module/project.properties new file mode 100644 index 00000000000..6f9611b1426 --- /dev/null +++ b/compiler/android-tests/android-module/project.properties @@ -0,0 +1,14 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}\tools\proguard\proguard-android.txt:proguard-project.txt + +# Project target. +target=android-10 diff --git a/compiler/android-tests/android-module/src/org/jetbrains/jet/compiler/android/AbstractCodegenTestCaseOnAndroid.java b/compiler/android-tests/android-module/src/org/jetbrains/jet/compiler/android/AbstractCodegenTestCaseOnAndroid.java new file mode 100644 index 00000000000..9d6fb547270 --- /dev/null +++ b/compiler/android-tests/android-module/src/org/jetbrains/jet/compiler/android/AbstractCodegenTestCaseOnAndroid.java @@ -0,0 +1,41 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * 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 org.jetbrains.jet.compiler.android; + +import junit.framework.TestCase; + +import java.lang.reflect.Method; + +/** + * @author Natalia.Ukhorskaya + */ + +public class AbstractCodegenTestCaseOnAndroid extends TestCase { + + protected void invokeBoxMethod(String filePath) throws Exception { + try { + Class clazz; + clazz = Class.forName(filePath.replaceAll("\\\\|-|\\.|/", "_") + ".namespace"); + Method method; + method = clazz.getMethod("box"); + assertEquals("OK", method.invoke(null)); + } + catch (Throwable e) { + throw new RuntimeException("File: " + filePath, e); + } + } +} diff --git a/compiler/android-tests/android-module/tested-module/AndroidManifest.xml b/compiler/android-tests/android-module/tested-module/AndroidManifest.xml new file mode 100644 index 00000000000..62a659797e9 --- /dev/null +++ b/compiler/android-tests/android-module/tested-module/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/compiler/android-tests/android-tests.iml b/compiler/android-tests/android-tests.iml new file mode 100644 index 00000000000..5ea86e39b57 --- /dev/null +++ b/compiler/android-tests/android-tests.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/compiler/android-tests/src/org/jetbrains/jet/compiler/CodegenTestsOnAndroidRunner.java b/compiler/android-tests/src/org/jetbrains/jet/compiler/CodegenTestsOnAndroidRunner.java new file mode 100644 index 00000000000..ca3e5c9c972 --- /dev/null +++ b/compiler/android-tests/src/org/jetbrains/jet/compiler/CodegenTestsOnAndroidRunner.java @@ -0,0 +1,221 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * 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 org.jetbrains.jet.compiler; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.util.io.FileUtil; +import junit.framework.*; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.compiler.ant.AntRunner; +import org.jetbrains.jet.compiler.download.SDKDownloader; +import org.jetbrains.jet.compiler.emulator.Emulator; +import org.jetbrains.jet.compiler.run.PermissionManager; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Natalia.Ukhorskaya + */ + +public class CodegenTestsOnAndroidRunner { + private static final Pattern ERROR_IN_TEST_OUTPUT_PATTERN = + Pattern.compile("([\\s]+at .*| Caused .*| java.lang.RuntimeException: File: .*|[\\s]+\\.\\.\\. .* more| Error in .*)"); + private static final Pattern NUMBER_OF_TESTS_IF_FAILED = Pattern.compile("Tests run: ([0-9]*), Failures: ([0-9]*), Errors: ([0-9]*)"); + private static final Pattern NUMBER_OF_TESTS_OK = Pattern.compile(" OK \\(([0-9]*) tests\\)"); + + private final PathManager pathManager; + + public static TestSuite getTestSuite(PathManager pathManager) { + return new CodegenTestsOnAndroidRunner(pathManager).generateTestSuite(); + } + + private CodegenTestsOnAndroidRunner(PathManager pathManager) { + this.pathManager = pathManager; + } + + private TestSuite generateTestSuite() { + TestSuite suite = new TestSuite("MySuite"); + + String resultOutput = runTests(); + // Test name -> stackTrace + final Map resultMap = parseOutputForFailedTests(resultOutput); + final Statistics statistics; + + // If map is empty => there are no failed tests + if (resultMap.isEmpty()) { + // Clear tmp folder where we run android tests + FileUtil.delete(new File(pathManager.getTmpFolder())); + + statistics = parseOutputForTestsNumberIfTestsPassed(resultOutput); + } + else { + statistics = parseOutputForTestsNumberIfThereIsFailedTests(resultOutput); + + for (final Map.Entry entry : resultMap.entrySet()) { + + suite.addTest(new TestCase("run") { + @Override + public String getName() { + return entry.getKey(); + } + + @Override + protected void runTest() throws Throwable { + Assert.fail(entry.getValue() + "See more information in log above."); + } + }); + } + } + + Assert.assertNotNull("Cannot parse number of failed tests from final line", statistics); + Assert.assertEquals("Number of stackTraces != failed tests on the final line", resultMap.size(), + statistics.failed + statistics.errors); + + suite.addTest(new TestCase("run") { + @Override + public String getName() { + return "testAll: Total: " + statistics.total + ", Failures: " + statistics.failed + ", Errors: " + statistics.errors; + } + + @Override + protected void runTest() throws Throwable { + Assert.assertTrue(true); + } + }); + + return suite; + } + + + /* + Output example: + [exec] Error in testKt344: + [exec] java.lang.RuntimeException: File: compiler\testData\codegen\regressions\kt344.jet + [exec] at org.jetbrains.jet.compiler.android.AbstractCodegenTestCaseOnAndroid.invokeBoxMethod(AbstractCodegenTestCaseOnAndroid.java:38) + [exec] at org.jetbrains.jet.compiler.android.CodegenTestCaseOnAndroid.testKt344(CodegenTestCaseOnAndroid.java:595) + [exec] at java.lang.reflect.Method.invokeNative(Native Method) + [exec] at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169) + [exec] Caused by: java.lang.reflect.InvocationTargetException + [exec] at java.lang.reflect.Method.invokeNative(Native Method) + [exec] at org.jetbrains.jet.compiler.android.AbstractCodegenTestCaseOnAndroid.invokeBoxMethod(AbstractCodegenTestCaseOnAndroid.java:35) + [exec] ... 13 more + [exec] Caused by: java.lang.VerifyError: compiler_testData_codegen_regressions_kt344_jet.namespace$t6$foo$1 + [exec] at compiler_testData_codegen_regressions_kt344_jet.namespace.t6(dummy.jet:94) + [exec] at compiler_testData_codegen_regressions_kt344_jet.namespace.box(dummy.jet:185) + [exec] ... 16 more + [exec] ............... + [exec] Error in testKt529: + */ + private Map parseOutputForFailedTests(String output) { + Map result = new HashMap(); + StringBuilder builder = new StringBuilder(); + String failedTestNamePrefix = " Error in "; + String lastFailedTestName = ""; + Matcher matcher = ERROR_IN_TEST_OUTPUT_PATTERN.matcher(output); + while (matcher.find()) { + String groupValue = matcher.group(); + if (groupValue.startsWith(failedTestNamePrefix)) { + if (builder.length() > 0) { + result.put(lastFailedTestName, builder.toString()); + builder.delete(0, builder.length()); + } + lastFailedTestName = groupValue.substring(failedTestNamePrefix.length()); + } + builder.append(groupValue); + builder.append("\n"); + } + if (builder.length() > 0) { + result.put(lastFailedTestName, builder.toString()); + } + return result; + } + + //[exec] Tests run: 225, Failures: 0, Errors: 2 + @Nullable + private Statistics parseOutputForTestsNumberIfThereIsFailedTests(String output) { + Matcher matcher = NUMBER_OF_TESTS_IF_FAILED.matcher(output); + if (matcher.find()) { + return new Statistics(Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)), + Integer.parseInt(matcher.group(3))); + } + return null; + } + + //[exec] OK (223 tests) + @Nullable + private Statistics parseOutputForTestsNumberIfTestsPassed(String output) { + Matcher matcher = NUMBER_OF_TESTS_OK.matcher(output); + if (matcher.find()) { + return new Statistics(Integer.parseInt(matcher.group(1)), 0, 0); + } + return null; + } + + + public String runTests() { + ApplicationManager.setApplication(null, new Disposable() { + @Override + public void dispose() { + } + }); + + File rootForAndroidDependencies = new File(pathManager.getDependenciesRoot()); + if (!rootForAndroidDependencies.exists()) { + rootForAndroidDependencies.mkdirs(); + } + + SDKDownloader downloader = new SDKDownloader(pathManager); + Emulator emulator = new Emulator(pathManager); + AntRunner antRunner = new AntRunner(pathManager); + downloader.downloadAll(); + downloader.unzipAll(); + + PermissionManager.setPermissions(pathManager); + + antRunner.packLibraries(); + + emulator.createEmulator(); + emulator.startEmulator(); + try { + emulator.waitEmulatorStart(); + antRunner.cleanOutput(); + antRunner.compileSources(); + antRunner.installApplicationOnEmulator(); + return antRunner.runTestsOnEmulator(); + } + finally { + emulator.stopEmulator(); + } + } + + private static class Statistics { + public final int total; + public final int errors; + public final int failed; + + private Statistics(int total, int failed, int errors) { + this.total = total; + this.failed = failed; + this.errors = errors; + } + } +} diff --git a/compiler/android-tests/src/org/jetbrains/jet/compiler/PathManager.java b/compiler/android-tests/src/org/jetbrains/jet/compiler/PathManager.java new file mode 100644 index 00000000000..e7e9da3bba6 --- /dev/null +++ b/compiler/android-tests/src/org/jetbrains/jet/compiler/PathManager.java @@ -0,0 +1,84 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * 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 org.jetbrains.jet.compiler; + +/** + * @author Natalia.Ukhorskaya + */ + +public class PathManager { + + private final String tmpFolder; + private final String rootFolder; + + public PathManager(String rootFolder, String tmpFolder) { + this.tmpFolder = tmpFolder; + this.rootFolder = rootFolder; + } + + public String getPlatformFolderInAndroidSdk() { + return getAndroidSdkRoot() + "/platforms"; + } + + public String getPlatformToolsFolderInAndroidSdk() { + return getAndroidSdkRoot() + "/platform-tools"; + } + + public String getToolsFolderInAndroidSdk() { + return getAndroidSdkRoot() + "/tools"; + } + + public String getOutputForCompiledFiles() { + return tmpFolder + "/libs/codegen-test-output"; + } + + public String getLibsFolderInAndroidTestedModuleTmpFolder() { + return tmpFolder + "/tested-module/libs"; + } + + public String getLibsFolderInAndroidTmpFolder() { + return tmpFolder + "/libs"; + } + + public String getSrcFolderInAndroidTmpFolder() { + return tmpFolder + "/src"; + } + + public String getAndroidSdkRoot() { + return getDependenciesRoot() + "/android-sdk"; + } + + public String getDependenciesRoot() { + return rootFolder + "/android.tests.dependencies"; + } + + public String getRootForDownload() { + return getDependenciesRoot() + "/download"; + } + + public String getAntBinDirectory() { + return getDependenciesRoot() + "/apache-ant-1.8.0/bin"; + } + + public String getAndroidModuleRoot() { + return rootFolder + "/compiler/android-tests/android-module"; + } + + public String getTmpFolder() { + return tmpFolder; + } +} diff --git a/compiler/android-tests/src/org/jetbrains/jet/compiler/ant/AntRunner.java b/compiler/android-tests/src/org/jetbrains/jet/compiler/ant/AntRunner.java new file mode 100644 index 00000000000..c3aa814a57c --- /dev/null +++ b/compiler/android-tests/src/org/jetbrains/jet/compiler/ant/AntRunner.java @@ -0,0 +1,116 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * 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 org.jetbrains.jet.compiler.ant; + +import com.intellij.execution.configurations.GeneralCommandLine; +import com.intellij.openapi.util.SystemInfo; +import org.jetbrains.jet.compiler.PathManager; +import org.jetbrains.jet.compiler.run.RunUtils; +import org.jetbrains.jet.compiler.run.result.RunResult; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Natalia.Ukhorskaya + */ + +public class AntRunner { + private final List listOfAntCommands; + + public AntRunner(PathManager pathManager) { + listOfAntCommands = new ArrayList(); + String antCmdName = SystemInfo.isWindows ? "ant.bat" : "ant"; + listOfAntCommands.add(pathManager.getAntBinDirectory() + "/" + antCmdName); + listOfAntCommands.add("-Dsdk.dir=" + pathManager.getAndroidSdkRoot()); + listOfAntCommands.add("-buildfile"); + listOfAntCommands.add(pathManager.getTmpFolder() + "/build.xml"); + } + + /* Pack compiled sources on first step to one jar file */ + public void packLibraries() { + System.out.println("Pack libraries..."); + RunResult result = RunUtils.execute(generateCommandLine("pack_libraries")); + if (!result.getStatus()) { + throw new RuntimeException(result.getOutput()); + } + } + + /* Clean output directory */ + public void cleanOutput() { + System.out.println("Clearing output directory..."); + RunResult result = RunUtils.execute(generateCommandLine("clean")); + if (!result.getStatus()) { + throw new RuntimeException(result.getOutput()); + } + } + + public void compileSources() { + System.out.println("Compiling sources..."); + RunResult result = RunUtils.execute(generateCommandLine("debug")); + if (!result.getStatus()) { + throw new RuntimeException(result.getOutput()); + } + } + + public void installApplicationOnEmulator() { + System.out.println("Installing apk..."); + RunResult result = RunUtils.execute(generateCommandLine("installt")); + String resultOutput = result.getOutput(); + if (!isInstallSuccessful(resultOutput)) { + installApplicationOnEmulator(); + return; + } else { + System.out.println(resultOutput); + } + if (!result.getStatus()) { + throw new RuntimeException(resultOutput); + } + } + + public String runTestsOnEmulator() { + System.out.println("Running tests..."); + RunResult result = RunUtils.execute(generateCommandLine("test")); + String resultOutput = result.getOutput(); + if (!result.getStatus()) { + throw new RuntimeException(resultOutput); + } + else { + return resultOutput; + } + } + + private static boolean isInstallSuccessful(String output) { + if (output.contains("Is the system running?")) { + try { + System.out.println("Device not ready. Waiting for 20 sec."); + Thread.sleep(20000); + return false; + } + catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + return true; + } + + private GeneralCommandLine generateCommandLine(String taskName) { + GeneralCommandLine commandLine = new GeneralCommandLine(listOfAntCommands); + commandLine.addParameter(taskName); + return commandLine; + } +} diff --git a/compiler/android-tests/src/org/jetbrains/jet/compiler/download/SDKDownloader.java b/compiler/android-tests/src/org/jetbrains/jet/compiler/download/SDKDownloader.java new file mode 100644 index 00000000000..417e48a5a5d --- /dev/null +++ b/compiler/android-tests/src/org/jetbrains/jet/compiler/download/SDKDownloader.java @@ -0,0 +1,224 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * 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 org.jetbrains.jet.compiler.download; + +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.io.FileUtil; +import org.jetbrains.jet.compiler.PathManager; +import org.jetbrains.jet.compiler.run.RunUtils; + +import java.io.*; +import java.net.URL; +import java.net.URLConnection; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +/** + * @author Natalia.Ukhorskaya + */ + +public class SDKDownloader { + private final String platformZipPath; + private final String platformToolsZipPath; + private final String toolsZipPath; + private final String antZipPath; + + private final PathManager pathManager; + + public SDKDownloader(PathManager pathManager) { + this.pathManager = pathManager; + platformZipPath = pathManager.getRootForDownload() + "/platforms.zip"; + platformToolsZipPath = pathManager.getRootForDownload() + "/platform-tools.zip"; + toolsZipPath = pathManager.getRootForDownload() + "/tools.zip"; + antZipPath = pathManager.getRootForDownload() + "/apache-ant-1.8.0.zip"; + } + + public void downloadPlatform() { + download("https://dl-ssl.google.com/android/repository/android-2.3.3_r02-linux.zip", platformZipPath); //Same for all platforms + } + + public void downloadPlatformTools() { + String downloadURL; + if (SystemInfo.isWindows) { + downloadURL = "http://dl-ssl.google.com/android/repository/platform-tools_r11-windows.zip"; + } + else if (SystemInfo.isMac) { + downloadURL = "http://dl-ssl.google.com/android/repository/platform-tools_r11-macosx.zip"; + } + else if (SystemInfo.isUnix) { + downloadURL = "http://dl-ssl.google.com/android/repository/platform-tools_r11-linux.zip"; + } + else { + throw new IllegalStateException("Your operating system doesn't supported yet."); + } + download(downloadURL, platformToolsZipPath); + } + + public void downloadTools() { + String downloadURL; + if (SystemInfo.isWindows) { + downloadURL = "http://dl.google.com/android/repository/tools_r19-windows.zip"; + } + else if (SystemInfo.isMac) { + downloadURL = "http://dl.google.com/android/repository/tools_r19-macosx.zip"; + } + else if (SystemInfo.isUnix) { + downloadURL = "http://dl.google.com/android/repository/tools_r19-linux.zip"; + } + else { + throw new IllegalStateException("Your operating system doesn't supported yet."); + } + download(downloadURL, toolsZipPath); + } + + public void downloadAnt() { + download("http://archive.apache.org/dist/ant/binaries/apache-ant-1.8.0-bin.zip", antZipPath); + } + + public void downloadAll() { + downloadTools(); + downloadPlatform(); + downloadPlatformTools(); + downloadAnt(); + } + + public void unzipAll() { + unzip(platformZipPath, pathManager.getPlatformFolderInAndroidSdk()); + unzip(platformToolsZipPath, pathManager.getAndroidSdkRoot()); + unzip(toolsZipPath, pathManager.getAndroidSdkRoot()); + unzip(antZipPath, pathManager.getDependenciesRoot()); + } + + public void deleteAll() { + delete(platformZipPath); + delete(platformToolsZipPath); + delete(toolsZipPath); + delete(antZipPath); + } + + protected void download(String urlString, String output) { + System.out.println("Start downloading: " + urlString + " to " + output); + OutputStream outStream = null; + URLConnection urlConnection = null; + + InputStream is = null; + try { + URL Url; + byte[] buf; + int read; + //int written = 0; + Url = new URL(urlString); + + File outputFile = new File(output); + outputFile.getParentFile().mkdirs(); + if (outputFile.exists()) { + System.out.println("File was already downloaded: " + output); + return; + } + outputFile.createNewFile(); + FileOutputStream outputStream = new FileOutputStream(outputFile); + outStream = new BufferedOutputStream(outputStream); + + urlConnection = Url.openConnection(); + is = urlConnection.getInputStream(); + buf = new byte[1024]; + while ((read = is.read(buf)) != -1) { + outStream.write(buf, 0, read); + //written += read; + } + } + catch (Exception e) { + throw new RuntimeException(e); + } + finally { + RunUtils.close(outStream); + } + System.out.println("Finish downloading: " + urlString + " to " + output); + } + + protected void unzip(String pathToFile, String outputFolder) { + System.out.println("Start unzipping: " + pathToFile + " to " + outputFolder); + String pathToUnzip; + if (outputFolder.equals(pathManager.getPlatformFolderInAndroidSdk())) { + pathToUnzip = outputFolder; + } + else { + pathToUnzip = outputFolder + "/" + FileUtil.getNameWithoutExtension(new File(pathToFile)); + } + if (new File(pathToUnzip).listFiles() != null) { + System.out.println("File was already unzipped: " + pathToFile); + return; + } + try { + byte[] buf = new byte[1024]; + ZipInputStream zipinputstream = null; + ZipEntry zipentry; + zipinputstream = new ZipInputStream(new FileInputStream(pathToFile)); + + zipentry = zipinputstream.getNextEntry(); + try { + while (zipentry != null) { + String entryName = zipentry.getName(); + int n; + File outputFile = new File(outputFolder + "/" + entryName); + + if (zipentry.isDirectory()) { + outputFile.mkdirs(); + zipinputstream.closeEntry(); + zipentry = zipinputstream.getNextEntry(); + continue; + } + else { + File parentFile = outputFile.getParentFile(); + if (parentFile != null && !parentFile.exists()) { + parentFile.mkdirs(); + } + outputFile.createNewFile(); + } + + FileOutputStream fileoutputstream = new FileOutputStream(outputFile); + try { + while ((n = zipinputstream.read(buf, 0, 1024)) > -1) { + fileoutputstream.write(buf, 0, n); + } + } + finally { + fileoutputstream.close(); + } + zipinputstream.closeEntry(); + zipentry = zipinputstream.getNextEntry(); + } + + zipinputstream.close(); + } + catch (IOException e) { + System.err.println("Entry name: " + zipentry.getName()); + e.printStackTrace(); + } + } + catch (Exception e) { + e.printStackTrace(); + } + System.out.println("Finish unzipping: " + pathToFile + " to " + outputFolder); + } + + protected void delete(String filePath) { + File file = new File(filePath); + file.delete(); + } +} + diff --git a/compiler/android-tests/src/org/jetbrains/jet/compiler/emulator/Emulator.java b/compiler/android-tests/src/org/jetbrains/jet/compiler/emulator/Emulator.java new file mode 100644 index 00000000000..e82755d5909 --- /dev/null +++ b/compiler/android-tests/src/org/jetbrains/jet/compiler/emulator/Emulator.java @@ -0,0 +1,123 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * 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 org.jetbrains.jet.compiler.emulator; + +import com.intellij.execution.configurations.GeneralCommandLine; +import com.intellij.openapi.util.SystemInfo; +import org.jetbrains.jet.compiler.PathManager; +import org.jetbrains.jet.compiler.run.RunUtils; +import org.jetbrains.jet.compiler.run.result.RunResult; + +/** + * @author Natalia.Ukhorskaya + */ + +public class Emulator { + + private final PathManager pathManager; + + public Emulator(PathManager pathManager) { + this.pathManager = pathManager; + } + + private GeneralCommandLine getCreateCommand() { + GeneralCommandLine commandLine = new GeneralCommandLine(); + String androidCmdName = SystemInfo.isWindows ? "android.bat" : "android"; + commandLine.setExePath(pathManager.getToolsFolderInAndroidSdk() + "/" + androidCmdName); + commandLine.addParameter("create"); + commandLine.addParameter("avd"); + commandLine.addParameter("--force"); + commandLine.addParameter("-n"); + commandLine.addParameter("my_avd"); + commandLine.addParameter("-t"); + commandLine.addParameter("1"); + return commandLine; + } + + private GeneralCommandLine getStartCommand() { + GeneralCommandLine commandLine = new GeneralCommandLine(); + String emulatorCmdName = SystemInfo.isWindows ? "emulator.exe" : "emulator"; + commandLine.setExePath(pathManager.getToolsFolderInAndroidSdk() + "/" + emulatorCmdName); + commandLine.addParameter("-avd"); + commandLine.addParameter("my_avd"); + commandLine.addParameter("-no-audio"); + commandLine.addParameter("-no-window"); + return commandLine; + } + + private GeneralCommandLine getWaitCommand() { + GeneralCommandLine commandLine = new GeneralCommandLine(); + String adbCmdName = SystemInfo.isWindows ? "adb.exe" : "adb"; + commandLine.setExePath(pathManager.getPlatformToolsFolderInAndroidSdk() + "/" + adbCmdName); + commandLine.addParameter("wait-for-device"); + return commandLine; + } + + private GeneralCommandLine getStopCommandForAdb() { + GeneralCommandLine commandLine = new GeneralCommandLine(); + String adbCmdName = SystemInfo.isWindows ? "adb.exe" : "adb"; + commandLine.setExePath(pathManager.getPlatformToolsFolderInAndroidSdk() + "/" + adbCmdName); + commandLine.addParameter("kill-server"); + return commandLine; + } + + private GeneralCommandLine getStopCommand() { + GeneralCommandLine commandLine = new GeneralCommandLine(); + if (SystemInfo.isWindows) { + commandLine.setExePath("taskkill"); + commandLine.addParameter("/F"); + commandLine.addParameter("/IM"); + commandLine.addParameter("emulator-arm.exe"); + } + else { + commandLine.setExePath(pathManager.getPlatformToolsFolderInAndroidSdk() + "/adb"); + commandLine.addParameter("emu"); + commandLine.addParameter("kill"); + } + return commandLine; + } + + public void createEmulator() { + System.out.println("Creating emulator..."); + checkResult(RunUtils.execute(getCreateCommand(), "no")); + } + + + public void startEmulator() { + System.out.println("Starting emulator..."); + checkResult(RunUtils.executeOnSeparateThread(getStartCommand(), false)); + } + + + public void waitEmulatorStart() { + System.out.println("Waiting for emulator start..."); + checkResult(RunUtils.execute(getWaitCommand())); + } + + public void stopEmulator() { + System.out.println("Stopping emulator..."); + checkResult(RunUtils.execute(getStopCommand())); + System.out.println("Stopping adb..."); + checkResult(RunUtils.execute(getStopCommandForAdb())); + } + + private static void checkResult(RunResult result) { + if (!result.getStatus()) { + throw new RuntimeException(result.getOutput()); + } + } +} diff --git a/compiler/android-tests/src/org/jetbrains/jet/compiler/run/PermissionManager.java b/compiler/android-tests/src/org/jetbrains/jet/compiler/run/PermissionManager.java new file mode 100644 index 00000000000..50ad8975670 --- /dev/null +++ b/compiler/android-tests/src/org/jetbrains/jet/compiler/run/PermissionManager.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * 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 org.jetbrains.jet.compiler.run; + +import com.intellij.execution.configurations.GeneralCommandLine; +import com.intellij.openapi.util.SystemInfo; +import org.jetbrains.jet.compiler.PathManager; + +/** + * @author Natalia.Ukhorskaya + */ + +public class PermissionManager { + private PermissionManager() { + } + + public static void setPermissions(PathManager pathManager) { + if (!SystemInfo.isWindows) { + RunUtils.execute(generateChmodCmd(pathManager.getPlatformToolsFolderInAndroidSdk() + "/aapt")); + RunUtils.execute(generateChmodCmd(pathManager.getPlatformToolsFolderInAndroidSdk() + "/adb")); + RunUtils.execute(generateChmodCmd(pathManager.getPlatformToolsFolderInAndroidSdk() + "/dx")); + RunUtils.execute(generateChmodCmd(pathManager.getToolsFolderInAndroidSdk() + "/emulator")); + RunUtils.execute(generateChmodCmd(pathManager.getToolsFolderInAndroidSdk() + "/tools/ddms")); + RunUtils.execute(generateChmodCmd(pathManager.getToolsFolderInAndroidSdk() + "/tools/android")); + RunUtils.execute(generateChmodCmd(pathManager.getToolsFolderInAndroidSdk() + "/tools/emulator-arm")); + RunUtils.execute(generateChmodCmd(pathManager.getToolsFolderInAndroidSdk() + "/tools/zipalign")); + RunUtils.execute(generateChmodCmd(pathManager.getAntBinDirectory() + "/ant")); + } + } + + private static GeneralCommandLine generateChmodCmd(String path) { + GeneralCommandLine commandLine = new GeneralCommandLine(); + commandLine.setExePath("chmod"); + commandLine.addParameter("u+x"); + commandLine.addParameter(path); + return commandLine; + } +} diff --git a/compiler/android-tests/src/org/jetbrains/jet/compiler/run/RunUtils.java b/compiler/android-tests/src/org/jetbrains/jet/compiler/run/RunUtils.java new file mode 100644 index 00000000000..aee8c51e686 --- /dev/null +++ b/compiler/android-tests/src/org/jetbrains/jet/compiler/run/RunUtils.java @@ -0,0 +1,184 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * 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 org.jetbrains.jet.compiler.run; + +import com.google.common.base.Charsets; +import com.intellij.execution.ExecutionException; +import com.intellij.execution.configurations.GeneralCommandLine; +import com.intellij.execution.process.OSProcessHandler; +import com.intellij.execution.process.ProcessAdapter; +import com.intellij.execution.process.ProcessEvent; +import com.intellij.execution.process.ProcessOutputTypes; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.Ref; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.compiler.run.result.RunResult; + +import java.io.Closeable; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * @author Natalia.Ukhorskaya + */ + +public class RunUtils { + private RunUtils() { + } + + public static RunResult execute(final GeneralCommandLine commandLine) { + return run(commandLine, null); + } + + public static RunResult execute(final GeneralCommandLine commandLine, @Nullable String input) { + return run(commandLine, input); + } + + public static RunResult executeOnSeparateThread(final GeneralCommandLine commandLine, boolean waitForEnd) { + return executeOnSeparateThread(commandLine, waitForEnd, null); + } + + public static RunResult executeOnSeparateThread(final GeneralCommandLine commandLine, + boolean waitForEnd, + @Nullable final String input) { + final Ref resultRef = new Ref(); + Thread t = new Thread(new Runnable() { + @Override + public void run() { + resultRef.set(RunUtils.run(commandLine, input)); + } + }); + + t.start(); + + if (waitForEnd) { + try { + t.wait(300000); + return resultRef.get(); + } + catch (InterruptedException e) { + new RunResult(false, getStackTrace(e)); + } + } + return new RunResult(true, "OK"); + } + + private static RunResult run(final GeneralCommandLine commandLine, @Nullable final String input) { + final StringBuilder stdOut = new StringBuilder(); + final StringBuilder stdErr = new StringBuilder(); + + final OSProcessHandler handler; + try { + handler = new OSProcessHandler(commandLine.createProcess(), commandLine.getCommandLineString(), Charsets.UTF_8); + if (input != null) { + handler.getProcessInput().write(input.getBytes()); + } + close(handler.getProcessInput()); + } + catch (ExecutionException e) { + return new RunResult(false, getStackTrace(e)); + } + catch (IOException e) { + return new RunResult(false, getStackTrace(e)); + } + + final ProcessAdapter listener = new ProcessAdapter() { + @Override + public void onTextAvailable(final ProcessEvent event, final Key outputType) { + String str = event.getText(); + if (outputType == ProcessOutputTypes.STDOUT || outputType == ProcessOutputTypes.SYSTEM) { + stdOut.append(str); + if (!commandLine.getCommandLineString().contains("install")) { + System.out.print(str); + } + } + else if (outputType == ProcessOutputTypes.STDERR) { + stdErr.append(str); + System.err.print(str); + } + } + }; + + handler.addProcessListener(listener); + handler.startNotify(); + + try { + handler.waitFor(300000); + } + catch (ProcessCanceledException e) { + return new RunResult(false, getStackTrace(e)); + } + + if (!handler.isProcessTerminated()) { + return new RunResult(false, "Timeout exception: execution was terminated after 5 min."); + } + + handler.removeProcessListener(listener); + + int exitCode = handler.getProcess().exitValue(); + + if (exitCode != 0) { + return new RunResult(false, builderToString(stdOut) + builderToString(stdErr)); + } + else { + String output = builderToString(stdOut) + builderToString(stdErr); + if (!isResultOk(output)) { + return new RunResult(false, output); + } + return new RunResult(true, output); + } + } + + private static String builderToString(StringBuilder builder) { + return builder.length() > 0 ? builder.toString() : ""; + } + + public static void close(Closeable closeable) { + try { + if (closeable != null) { + closeable.close(); + } + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static String getStackTrace(Throwable t) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + try { + printWriter.write(t.getMessage()); + printWriter.write("\n"); + t.printStackTrace(printWriter); + } + finally { + close(printWriter); + } + return writer.toString(); + } + + public static boolean isResultOk(String output) { + if (output.contains("BUILD FAILED") + || output.contains("Build failed")) { + return false; + } + return true; + } +} diff --git a/compiler/android-tests/src/org/jetbrains/jet/compiler/run/result/RunResult.java b/compiler/android-tests/src/org/jetbrains/jet/compiler/run/result/RunResult.java new file mode 100644 index 00000000000..565d47163a7 --- /dev/null +++ b/compiler/android-tests/src/org/jetbrains/jet/compiler/run/result/RunResult.java @@ -0,0 +1,41 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * 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 org.jetbrains.jet.compiler.run.result; + +/** + * @author Natalia.Ukhorskaya + */ + +public class RunResult { + private final boolean status; + private final String output; + + public RunResult(boolean ok, String output) { + status = ok; + this.output = output; + } + + //true - ok + //false - fail + public boolean getStatus() { + return status; + } + + public String getOutput() { + return output; + } +} diff --git a/compiler/android-tests/tests/org/jetbrains/jet/compiler/android/AndroidRunner.java b/compiler/android-tests/tests/org/jetbrains/jet/compiler/android/AndroidRunner.java new file mode 100644 index 00000000000..035a9ca794e --- /dev/null +++ b/compiler/android-tests/tests/org/jetbrains/jet/compiler/android/AndroidRunner.java @@ -0,0 +1,53 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * 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 org.jetbrains.jet.compiler.android; + +import com.google.common.io.Files; +import com.intellij.openapi.util.io.FileUtil; +import junit.framework.TestSuite; +import org.jetbrains.jet.compiler.CodegenTestsOnAndroidRunner; +import org.jetbrains.jet.compiler.PathManager; + +import java.io.File; + +/** + * @author Natalia.Ukhorskaya + */ + +public class AndroidRunner extends TestSuite { + + public static TestSuite suite() throws Throwable { + File tmpFolder = Files.createTempDir(); + System.out.println("Created temporary folder for running android tests: " + tmpFolder.getAbsolutePath()); + File rootFolder = new File(""); + PathManager pathManager = new PathManager(rootFolder.getAbsolutePath(), tmpFolder.getAbsolutePath()); + + FileUtil.copyDir(new File(pathManager.getAndroidModuleRoot()), new File(pathManager.getTmpFolder())); + + try { + CodegenTestsOnAndroidGenerator.generate(pathManager); + } + catch(Throwable e) { + FileUtil.delete(new File(pathManager.getTmpFolder())); + throw new RuntimeException(e); + } + + System.out.println("Run tests on android..."); + return CodegenTestsOnAndroidRunner.getTestSuite(pathManager); + } + +} diff --git a/compiler/android-tests/tests/org/jetbrains/jet/compiler/android/CodegenTestsOnAndroidGenerator.java b/compiler/android-tests/tests/org/jetbrains/jet/compiler/android/CodegenTestsOnAndroidGenerator.java new file mode 100644 index 00000000000..af649bd8f8f --- /dev/null +++ b/compiler/android-tests/tests/org/jetbrains/jet/compiler/android/CodegenTestsOnAndroidGenerator.java @@ -0,0 +1,203 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * 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 org.jetbrains.jet.compiler.android; + +import com.google.common.collect.Lists; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.testFramework.UsefulTestCase; +import junit.framework.Assert; +import org.jetbrains.jet.JetTestUtils; +import org.jetbrains.jet.cli.jvm.compiler.CompileEnvironmentUtil; +import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; +import org.jetbrains.jet.codegen.*; +import org.jetbrains.jet.compiler.PathManager; +import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.psi.JetPsiFactory; +import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode; +import org.jetbrains.jet.test.generator.Printer; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Natalia.Ukhorskaya + */ + +public class CodegenTestsOnAndroidGenerator extends UsefulTestCase { + + private final PathManager pathManager; + private final String testClassPackage = "org.jetbrains.jet.compiler.android"; + private final String testClassName = "CodegenTestCaseOnAndroid"; + private final String baseTestClassPackage = "org.jetbrains.jet.compiler.android"; + private final String baseTestClassName = "AbstractCodegenTestCaseOnAndroid"; + private final String generatorName = "CodegenTestsOnAndroidGenerator"; + + private JetCoreEnvironment environmentWithMockJdk = JetTestUtils.createEnvironmentWithMockJdkAndIdeaAnnotations(myTestRootDisposable, CompilerSpecialMode.JDK_HEADERS); + private JetCoreEnvironment environmentWithFullJdk = JetTestUtils.createEnvironmentWithFullJdk(myTestRootDisposable); + + private final Pattern packagePattern = Pattern.compile("package (.*)"); + + private final List generatedTestNames = Lists.newArrayList(); + + public static void generate(PathManager pathManager) throws Throwable { + new CodegenTestsOnAndroidGenerator(pathManager).generateOutputFiles(); + } + + private CodegenTestsOnAndroidGenerator(PathManager pathManager) { + this.pathManager = pathManager; + } + + private void generateOutputFiles() throws Throwable { + prepareAndroidModule(); + generateAndSave(); + } + + private void prepareAndroidModule() throws IOException { + System.out.println("Copying kotlin-runtime.jar in android module..."); + copyKotlinRuntimeJar(); + + System.out.println("Check \"libs\" folder in tested android module..."); + File libsFolderInTestedModule = new File(pathManager.getLibsFolderInAndroidTestedModuleTmpFolder()); + if (!libsFolderInTestedModule.exists()) { + libsFolderInTestedModule.mkdirs(); + } + } + + private void copyKotlinRuntimeJar() throws IOException { + File kotlinRuntimeJar = new File(pathManager.getLibsFolderInAndroidTmpFolder() + "/kotlin-runtime.jar"); + File kotlinRuntimeInDist = new File("dist/kotlinc/lib/kotlin-runtime.jar"); + Assert.assertTrue("kotlin-runtime.jar in dist/kotlnc/lib/ doesn't exists. Run dist ant task before generating test for android.", + kotlinRuntimeInDist.exists()); + FileUtil.copy(kotlinRuntimeInDist, kotlinRuntimeJar); + } + + private void generateAndSave() throws Throwable { + System.out.println("Generating test files..."); + StringBuilder out = new StringBuilder(); + Printer p = new Printer(out); + + p.print(FileUtil.loadFile(new File("injector-generator/copyright.txt"))); + p.println("package " + testClassPackage + ";"); + p.println(); + p.println("import ", baseTestClassPackage, ".", baseTestClassName, ";"); + p.println(); + p.println("/* This class is generated by " + generatorName + ". DO NOT MODIFY MANUALLY */"); + p.println("public class ", testClassName, " extends ", baseTestClassName, " {"); + p.pushIndent(); + + File testDataSources = new File("compiler/testData/codegen/"); + generateTestMethodsForDirectory(p, testDataSources); + + p.popIndent(); + p.println("}"); + + String testSourceFilePath = + pathManager.getSrcFolderInAndroidTmpFolder() + "/" + testClassPackage.replace(".", "/") + "/" + testClassName + ".java"; + FileUtil.writeToFile(new File(testSourceFilePath), out.toString()); + } + + private void generateTestMethodsForDirectory(Printer p, File dir) throws IOException { + File[] files = dir.listFiles(); + Assert.assertNotNull("Folder with testData is empty: " + dir.getAbsolutePath(), files); + Set excludedFiles = SpecialFiles.getExcludedFiles(); + Set filesCompiledWithoutStdLib = SpecialFiles.getFilesCompiledWithoutStdLib(); + for (File file : files) { + if (excludedFiles.contains(file.getName())) { + continue; + } + if (file.isDirectory()) { + generateTestMethodsForDirectory(p, file); + } + else { + String text = FileUtil.loadFile(file, true); + + if (hasBoxMethod(text)) { + String generatedTestName = generateTestName(file.getName()); + String packageName = file.getPath().replaceAll("\\\\|-|\\.|/", "_"); + text = changePackage(packageName, text); + final ClassFileFactory factory; + if (filesCompiledWithoutStdLib.contains(file.getName())) { + factory = getFactoryFromText(file.getAbsolutePath(), text, environmentWithMockJdk); + } + else { + factory = getFactoryFromText(file.getAbsolutePath(), text, environmentWithFullJdk); + } + + generateTestMethod(p, generatedTestName, StringUtil.escapeStringCharacters(file.getPath())); + File outputDir = new File(pathManager.getOutputForCompiledFiles()); + if (!outputDir.exists()) { + outputDir.mkdirs(); + } + Assert.assertTrue("Cannot create directory for compiled files", outputDir.exists()); + + CompileEnvironmentUtil.writeToOutputDirectory(factory, outputDir); + } + } + } + } + + private ClassFileFactory getFactoryFromText(String filePath, String text, JetCoreEnvironment jetEnvironment) { + JetFile psiFile = JetPsiFactory.createFile(jetEnvironment.getProject(), text); + ClassFileFactory factory; + try { + factory = GenerationUtils.compileFileGetClassFileFactoryForTest(psiFile, jetEnvironment.getCompilerDependencies().getCompilerSpecialMode()); + } + catch (Throwable e) { + throw new RuntimeException("Cannot compile: " + filePath + "\n" + text, e); + } + return factory; + } + + private boolean hasBoxMethod(String text) { + return text.contains("fun box()"); + } + + private String changePackage(String testName, String text) { + if (text.contains("package ")) { + Matcher matcher = packagePattern.matcher(text); + return matcher.replaceAll("package " + testName); + } + else { + return "package " + testName + ";\n" + text; + } + } + + private void generateTestMethod(Printer p, String testName, String namespace) { + p.println("public void test" + testName + "() throws Exception {"); + p.pushIndent(); + p.println("invokeBoxMethod(\"" + namespace + "\");"); + p.popIndent(); + p.println("}"); + p.println(); + } + + private String generateTestName(String fileName) { + String result = FileUtil.getNameWithoutExtension(StringUtil.capitalize(fileName)); + + int i = 0; + while (generatedTestNames.contains(result)) { + result += "_" + i++; + } + generatedTestNames.add(result); + return result; + } +} diff --git a/compiler/android-tests/tests/org/jetbrains/jet/compiler/android/SpecialFiles.java b/compiler/android-tests/tests/org/jetbrains/jet/compiler/android/SpecialFiles.java new file mode 100644 index 00000000000..9cbb45c8a6e --- /dev/null +++ b/compiler/android-tests/tests/org/jetbrains/jet/compiler/android/SpecialFiles.java @@ -0,0 +1,95 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * 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 org.jetbrains.jet.compiler.android; + +import com.google.common.collect.Sets; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author Natalia.Ukhorskaya + */ + +public class SpecialFiles { + private static final Set excludedFiles = Sets.newHashSet(); + private static final Set filesCompiledWithoutStdLib = Sets.newHashSet(); + + static { + fillExcludedFiles(); + fillFilesCompiledWithoutStdLib(); + } + + public static Set getExcludedFiles() { + return excludedFiles; + } + + public static Set getFilesCompiledWithoutStdLib() { + return filesCompiledWithoutStdLib; + } + + private static void fillFilesCompiledWithoutStdLib() { + filesCompiledWithoutStdLib.add("kt1953_class.kt"); // Exception in code + filesCompiledWithoutStdLib.add("basicmethodSuperClass.jet"); // Exception in code + filesCompiledWithoutStdLib.add("kt1980.kt"); // OVERLOAD_RESOLUTION_AMBIGUITY + filesCompiledWithoutStdLib.add("kt503.jet"); // OVERLOAD_RESOLUTION_AMBIGUITY + filesCompiledWithoutStdLib.add("kt504.jet"); // OVERLOAD_RESOLUTION_AMBIGUITY + filesCompiledWithoutStdLib.add("kt772.jet"); // OVERLOAD_RESOLUTION_AMBIGUITY + filesCompiledWithoutStdLib.add("kt773.jet"); // OVERLOAD_RESOLUTION_AMBIGUITY + filesCompiledWithoutStdLib.add("kt796_797.jet"); // OVERLOAD_RESOLUTION_AMBIGUITY + filesCompiledWithoutStdLib.add("kt950.jet"); // OVERLOAD_RESOLUTION_AMBIGUITY + } + + private static void fillExcludedFiles() { + excludedFiles.add("referencesStaticInnerClassMethod.kt"); // Must compile Java files before + excludedFiles.add("referencesStaticInnerClassMethodL2.kt"); // Must compile Java files before + excludedFiles.add("namespaceQualifiedMethod.jet"); // Cannot change package name + excludedFiles.add("kt1482_2279.kt"); // Cannot change package name + excludedFiles.add("kt1482.kt"); // Cannot change package name + excludedFiles.add("importFromClassObject.jet"); // Cannot find usages in Codegen tests + excludedFiles.add("withtypeparams.jet"); // Cannot find usages in Codegen tests + excludedFiles.add("kt1113.kt"); // Commented + excludedFiles.add("kt326.jet"); // Commented + excludedFiles.add("kt694.jet"); // Commented + excludedFiles.add("kt285.jet"); // Commented + excludedFiles.add("kt857.jet"); // Commented + excludedFiles.add("kt1120.kt"); // Commented + excludedFiles.add("kt1213.kt"); // Commented + excludedFiles.add("kt882.jet"); // Commented + excludedFiles.add("kt789.jet"); // Commented + excludedFiles.add("isTypeParameter.jet"); // Commented + excludedFiles.add("nullability.jet"); // Commented + excludedFiles.add("genericFunction.jet"); // Commented + excludedFiles.add("forwardTypeParameter.jet"); // Commented + excludedFiles.add("kt259.jet"); // Commented + excludedFiles.add("classObjectMethod.jet"); // Commented + excludedFiles.add("kt1592.kt"); // Codegen don't execute blackBoxFile() on it + + excludedFiles.add("box.kt"); // MultiFileTest + + excludedFiles.add("kt684.jet"); // StackOverflow with StringBuilder (escape()) + + excludedFiles.add("kt1199.kt"); // Bug KT-2202 + excludedFiles.add("kt344.jet"); // Bug KT-2251 + excludedFiles.add("kt529.kt"); // Bug + } + + private SpecialFiles() { + } +}