diff --git a/core/src/main/kotlin/com/malinskiy/marathon/report/html/HtmlSummaryReporter.kt b/core/src/main/kotlin/com/malinskiy/marathon/report/html/HtmlSummaryReporter.kt index 34e5206de..608aa0dfe 100644 --- a/core/src/main/kotlin/com/malinskiy/marathon/report/html/HtmlSummaryReporter.kt +++ b/core/src/main/kotlin/com/malinskiy/marathon/report/html/HtmlSummaryReporter.kt @@ -43,7 +43,7 @@ class HtmlSummaryReporter( * - suites/suiteId.json * - suites/deviceId/testId.json */ - @Suppress("LongMethod") + @Suppress("CyclomaticComplexMethod", "LongMethod") override fun generate(executionReport: ExecutionReport) { val summary = executionReport.summary if (summary.pools.isEmpty()) return @@ -57,13 +57,17 @@ class HtmlSummaryReporter( val formattedDate = SimpleDateFormat("HH:mm:ss z, MMM d yyyy").apply { timeZone = TimeZone.getTimeZone("UTC") }.format(Date()) val appJs = File(outputDir, "app.min.js") - inputStreamFromResources("html-report/app.min.js").copyTo(appJs.outputStream()) + inputStreamFromResources("html-report/app.min.js").use { input -> + appJs.outputStream().use { input.copyTo(it) } + } val appCss = File(outputDir, "app.min.css") - inputStreamFromResources("html-report/app.min.css").copyTo(appCss.outputStream()) + inputStreamFromResources("html-report/app.min.css").use { input -> + appCss.outputStream().use { input.copyTo(it) } + } // index.html is a page that can render all kinds of inner pages: Index, Suite, Test. - val indexHtml = inputStreamFromResources("html-report/index.html").reader().readText() + val indexHtml = inputStreamFromResources("html-report/index.html").reader().use { it.readText() } val indexHtmlFile = File(outputDir, "index.html") diff --git a/core/src/main/kotlin/com/malinskiy/marathon/report/timeline/TimelineReporter.kt b/core/src/main/kotlin/com/malinskiy/marathon/report/timeline/TimelineReporter.kt index 815e2d358..2cb7d452e 100644 --- a/core/src/main/kotlin/com/malinskiy/marathon/report/timeline/TimelineReporter.kt +++ b/core/src/main/kotlin/com/malinskiy/marathon/report/timeline/TimelineReporter.kt @@ -20,15 +20,20 @@ internal class TimelineReporter( val indexHtmlFile = File(timelineDir, "index.html") val chartCss = File(timelineDir, "chart.css") - inputStreamFromResources("timeline/chart.css").copyTo(chartCss.outputStream()) + inputStreamFromResources("timeline/chart.css").use { input -> + chartCss.outputStream().use { input.copyTo(it) } + } val chartJs = File(timelineDir, "chart.js") - inputStreamFromResources("timeline/chart.js").copyTo(chartJs.outputStream()) + inputStreamFromResources("timeline/chart.js").use { input -> + chartJs.outputStream().use { input.copyTo(it) } + } val json = gson.toJson(provider.generate(executionReport)) - val index = inputStreamFromResources("timeline/index.html") - val indexText = index.reader().readText() - indexHtmlFile.writeText(indexText.replace("\${dataset}", json)) + inputStreamFromResources("timeline/index.html").use { input -> + val indexText = input.reader().readText() + indexHtmlFile.writeText(indexText.replace("\${dataset}", json)) + } } private fun inputStreamFromResources(path: String): InputStream = diff --git a/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/ApkParser.kt b/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/ApkParser.kt index 821f07d12..c1b8f70d4 100644 --- a/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/ApkParser.kt +++ b/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/ApkParser.kt @@ -1,5 +1,6 @@ package com.malinskiy.marathon.android +import com.android.SdkConstants import com.shazam.axmlparser.AXMLParser import java.io.File import java.io.IOException @@ -7,20 +8,17 @@ import java.io.InputStream import java.util.zip.ZipFile class ApkParser { - @Suppress( - "ComplexMethod", - "ThrowsCount", - "TooGenericExceptionThrown", - "NestedBlockDepth" - ) fun parseInstrumentationInfo(apk: File): InstrumentationInfo { - var apkInputStream: InputStream? = null - try { - val zip = ZipFile(apk) - val entry = zip.getEntry("AndroidManifest.xml") - apkInputStream = zip.getInputStream(entry) + return ZipFile(apk).use { zip -> + val androidManifest = zip.getEntry(SdkConstants.ANDROID_MANIFEST_XML) + zip.getInputStream(androidManifest).use { parseAndroidManifest(it) } + } + } - val parser = AXMLParser(apkInputStream) + @Suppress("CyclomaticComplexMethod", "NestedBlockDepth") + private fun parseAndroidManifest(inputStream: InputStream): InstrumentationInfo { + try { + val parser = AXMLParser(inputStream) var eventType = parser.type var appPackage: String? = null @@ -60,9 +58,7 @@ class ApkParser { return InstrumentationInfo(appPackage, testPackage, testRunnerClass) } catch (e: IOException) { - throw RuntimeException("Unable to parse test app AndroidManifest.xml.", e) - } finally { - apkInputStream?.close() + throw IOException("Unable to parse test app AndroidManifest.xml.", e) } } } diff --git a/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/executor/listeners/screenshot/GifSequenceWriter.kt b/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/executor/listeners/screenshot/GifSequenceWriter.kt index fd13e85eb..ccd32bb7d 100644 --- a/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/executor/listeners/screenshot/GifSequenceWriter.kt +++ b/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/executor/listeners/screenshot/GifSequenceWriter.kt @@ -11,6 +11,7 @@ package com.malinskiy.marathon.android.executor.listeners.screenshot // Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. import java.awt.image.RenderedImage +import java.io.Closeable import java.io.File import java.io.IOException import javax.imageio.IIOException @@ -42,7 +43,7 @@ constructor( imageType: Int, timeBetweenFramesMS: Int, loopContinuously: Boolean -) { +) : Closeable { private var gifWriter: ImageWriter private var imageWriteParam: ImageWriteParam private var imageMetaData: IIOMetadata @@ -125,7 +126,7 @@ constructor( * stream, just finishes off the GIF. */ @Throws(IOException::class) - fun close() { + override fun close() { gifWriter.endWriteSequence() } diff --git a/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/executor/listeners/screenshot/ScreenCapturer.kt b/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/executor/listeners/screenshot/ScreenCapturer.kt index aa900df26..7b69a0cfa 100644 --- a/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/executor/listeners/screenshot/ScreenCapturer.kt +++ b/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/executor/listeners/screenshot/ScreenCapturer.kt @@ -33,27 +33,27 @@ class ScreenCapturer( FileType.SCREENSHOT, AttachmentType.SCREENSHOT ) - val outputStream = FileImageOutputStream(attachment.file) - val writer = GifSequenceWriter(outputStream, TYPE_INT_ARGB, DELAY, true) - var targetOrientation = UNDEFINED - while (isActive) { - val capturingTimeMillis = measureTimeMillis { - getScreenshot(targetOrientation)?.let { - if (targetOrientation == UNDEFINED) { - // remember the target orientation - targetOrientation = it.getOrientation() + FileImageOutputStream(attachment.file).use { outputStream -> + GifSequenceWriter(outputStream, TYPE_INT_ARGB, DELAY, true).use { writer -> + var targetOrientation = UNDEFINED + while (isActive) { + val capturingTimeMillis = measureTimeMillis { + getScreenshot(targetOrientation)?.let { + if (targetOrientation == UNDEFINED) { + // remember the target orientation + targetOrientation = it.getOrientation() + } + writer.writeToSequence(it) + } } - writer.writeToSequence(it) + val sleepTimeMillis = when { + (DELAY - capturingTimeMillis) < 0 -> 0 + else -> DELAY - capturingTimeMillis + } + delay(sleepTimeMillis) } } - val sleepTimeMillis = when { - (DELAY - capturingTimeMillis) < 0 -> 0 - else -> DELAY - capturingTimeMillis - } - delay(sleepTimeMillis) } - writer.close() - outputStream.close() } private fun getScreenshot(targetOrientation: Int): RenderedImage? { diff --git a/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/executor/logcat/BatchLogSaver.kt b/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/executor/logcat/BatchLogSaver.kt index 88e8f3a25..b64fa8fd4 100644 --- a/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/executor/logcat/BatchLogSaver.kt +++ b/vendor/vendor-android/base/src/main/kotlin/com/malinskiy/marathon/android/executor/logcat/BatchLogSaver.kt @@ -6,6 +6,7 @@ import com.malinskiy.marathon.report.logs.Log import com.malinskiy.marathon.report.logs.LogEvent import com.malinskiy.marathon.report.logs.LogTest import kotlinx.coroutines.CompletableDeferred +import java.io.Closeable import java.io.File import java.io.Writer import java.time.ZoneId @@ -50,7 +51,7 @@ class BatchLogSaver { class Event(val event: LogEvent) : SaveEntry() } - private class LogSaver { + private class LogSaver : Closeable { private val logFile: File = createTempFile() .also { @@ -72,7 +73,7 @@ class BatchLogSaver { } } - fun close() { + override fun close() { try { fileWriter.close() } finally {