From 9d3fe6206b71fe9b5a2eb579f0fe70e9cf46339e Mon Sep 17 00:00:00 2001 From: Michael Bogdanov Date: Wed, 7 Feb 2024 15:06:12 +0100 Subject: [PATCH] Test framework refactoring: switch to BookDescription instead of raw paths --- .../orion/viewer/test/SimpleBookTest.kt | 6 +- .../orion/viewer/test/engine/SearchTest.kt | 17 ++-- .../orion/viewer/test/engine/SelectionTest.kt | 13 +-- .../orion/viewer/test/framework/BaseTest.kt | 89 ------------------- .../orion/viewer/test/framework/BookTest.kt | 12 +-- .../viewer/test/framework/bitmapUtils.kt | 57 ++++++++++++ .../test/rendering/FlexibleBitmapTest.kt | 2 +- 7 files changed, 83 insertions(+), 113 deletions(-) create mode 100644 orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/framework/bitmapUtils.kt diff --git a/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/SimpleBookTest.kt b/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/SimpleBookTest.kt index 3a2d5d119..2e4dca3d2 100644 --- a/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/SimpleBookTest.kt +++ b/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/SimpleBookTest.kt @@ -8,13 +8,13 @@ import org.junit.runners.Parameterized import universe.constellation.orion.viewer.test.framework.BookDescription import universe.constellation.orion.viewer.test.framework.BookTest -class SimpleBookTest(private val bookDescription: BookDescription) : BookTest(bookDescription) { +class SimpleBookTest(bookDescription: BookDescription) : BookTest(bookDescription) { companion object { @JvmStatic @Parameterized.Parameters(name = "Open book {0} with expected page count {1} and outlines {2}") - fun testData(): Iterable> { - return BookDescription.values().map { arrayOf(it) } + fun testData(): Iterable> { + return BookDescription.testData() } } diff --git a/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/engine/SearchTest.kt b/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/engine/SearchTest.kt index 5a5622546..7e9102937 100644 --- a/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/engine/SearchTest.kt +++ b/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/engine/SearchTest.kt @@ -3,26 +3,27 @@ package universe.constellation.orion.viewer.test.engine import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runners.Parameterized +import universe.constellation.orion.viewer.test.framework.BookDescription import universe.constellation.orion.viewer.test.framework.BookTest class SearchTest( - path: String, + bookDescription: BookDescription, private val page1Based: Int, private val text: String, private val occurrences: Int -) : BookTest(path) { +) : BookTest(bookDescription) { companion object { @JvmStatic @Parameterized.Parameters(name = "Test `{2}` text search on page {1} at {0}") fun testData(): Iterable> { return listOf( - arrayOf(SICP, 12, "These programs", 1), - arrayOf(SICP, 12, "These", 2), - arrayOf(SICP, 12, "12334", 0), - arrayOf(ALICE, 6, "tunnel", 1), - arrayOf(ALICE, 6, "Then", 3), - arrayOf(ALICE, 6, "The123", 0) + arrayOf(BookDescription.SICP, 12, "These programs", 1), + arrayOf(BookDescription.SICP, 12, "These", 2), + arrayOf(BookDescription.SICP, 12, "12334", 0), + arrayOf(BookDescription.ALICE, 6, "tunnel", 1), + arrayOf(BookDescription.ALICE, 6, "Then", 3), + arrayOf(BookDescription.ALICE, 6, "The123", 0) ) } } diff --git a/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/engine/SelectionTest.kt b/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/engine/SelectionTest.kt index 6904ece96..447b3ae8e 100644 --- a/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/engine/SelectionTest.kt +++ b/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/engine/SelectionTest.kt @@ -5,25 +5,26 @@ import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runners.Parameterized import universe.constellation.orion.viewer.selection.SelectionAutomata +import universe.constellation.orion.viewer.test.framework.BookDescription import universe.constellation.orion.viewer.test.framework.BookTest class SelectionTest( - path: String, + bookDescription: BookDescription, private val page1Based: Int, private val absoluteRect: Rect, private val isSingleWord: Boolean, private val expectedText: String -) : BookTest(path) { +) : BookTest(bookDescription) { companion object { @JvmStatic @Parameterized.Parameters(name = "Test text selection in {0} with singleWord={3} expected text {4}") fun testData(): Iterable> { return listOf( - arrayOf(SICP, 12, Rect(242, 172, 242 + 140, 172 + 8), false, "These programs"), - arrayOf(SICP, 12, Rect(250, 176, 250 + 0, 176 + 0), true, "These"), - arrayOf(ALICE, 6, Rect(1288, 517, 1288 + 115, 517 + 50), false, "tunnel "), - arrayOf(ALICE, 6, Rect(518, 556, 518 + 0, 556 + 0), true, "The ") + arrayOf(BookDescription.SICP, 12, Rect(242, 172, 242 + 140, 172 + 8), false, "These programs"), + arrayOf(BookDescription.SICP, 12, Rect(250, 176, 250 + 0, 176 + 0), true, "These"), + arrayOf(BookDescription.ALICE, 6, Rect(1288, 517, 1288 + 115, 517 + 50), false, "tunnel "), + arrayOf(BookDescription.ALICE, 6, Rect(518, 556, 518 + 0, 556 + 0), true, "The ") ) } } diff --git a/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/framework/BaseTest.kt b/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/framework/BaseTest.kt index cb7a51f8d..e49372419 100644 --- a/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/framework/BaseTest.kt +++ b/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/framework/BaseTest.kt @@ -11,22 +11,15 @@ import androidx.test.rule.GrantPermissionRule import androidx.test.uiautomator.By import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.Until -import org.junit.Assert import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Rule import org.junit.rules.TestName -import universe.constellation.orion.viewer.BuildConfig -import universe.constellation.orion.viewer.FileUtil import universe.constellation.orion.viewer.R import universe.constellation.orion.viewer.djvu.DjvuDocument import universe.constellation.orion.viewer.document.Document -import universe.constellation.orion.viewer.document.DocumentWithCaching import universe.constellation.orion.viewer.document.DocumentWithCachingImpl import java.io.File -import java.io.FileOutputStream -import java.io.IOException -import kotlin.math.abs internal const val MANUAL_DEBUG = false @@ -76,89 +69,7 @@ abstract class BaseTest { const val ALICE: String = "aliceinw.djvu" const val DJVU_SPEC: String = "DjVu3Spec.djvu" - - const val ORION_PKG: String = BuildConfig.APPLICATION_ID - } -} - -fun openTestBook(relativePath: String): DocumentWithCaching { - val fileOnSdcard = extractFileFromTestData(relativePath) - return FileUtil.openFile(fileOnSdcard) -} - -fun openTestBook(bookDescription: BookDescription): DocumentWithCaching { - return openTestBook(bookDescription.path) -} - -fun extractFileFromTestData(fileName: String): File { - val outFile = File(BaseTest.testFolder, fileName) - if (outFile.exists()) { - return outFile - } - try { - outFile.parentFile!!.mkdirs() - outFile.createNewFile() - } catch (e: IOException) { - throw RuntimeException("Couldn't create new file " + outFile.absolutePath, e) } - val input = InstrumentationRegistry.getInstrumentation().context.assets.open( - getFileUnderTestData(fileName) - ) - val bufferedOutputStream = FileOutputStream(outFile).buffered() - input.buffered().copyTo(bufferedOutputStream) - bufferedOutputStream.close() - return outFile -} - -fun getFileUnderTestData(relativePath: String): String = "testData/$relativePath" - -internal fun dumpBitmap(prefix: String = "test", suffix: String, bitmap: Bitmap) { - val file = Environment.getExternalStorageDirectory().path + "/orion/$prefix$suffix.png" - println("saving dump into $file") - val file1 = File(file) - file1.parentFile?.mkdirs() - file1.createNewFile() - FileOutputStream(file).use { stream -> - bitmap.compress( - Bitmap.CompressFormat.PNG, - 100, - stream - ) - stream.close() - } -} - -internal const val DEFAULT_COLOR_DELTA = 3 - -//TODO check color difference reasons -internal fun compareBitmaps(partData: IntArray, fullData: IntArray, bitmapWidth: Int, message: String = "Fail", colorDelta: Int = DEFAULT_COLOR_DELTA, additionalDebugActions: () -> Unit) { - if (!partData.contentEquals(fullData)) { - if (MANUAL_DEBUG) { - additionalDebugActions() - } - for ( i in partData.indices) { - if (partData[i] != fullData[i]) { - val colorDiff = colorDiff(partData[i], fullData[i]) - if (colorDiff > colorDelta) { - Assert.fail("$message: different pixels at line " + i / bitmapWidth + " and position " + i % bitmapWidth + ": " + partData[i] + " vs " + fullData[i] + " diff=" + colorDiff) - } - } - } - } -} - -internal fun colorDiff(a: Int, b: Int): Int { - val a1 = a and 0xFF000000u.toInt() ushr 24 - val a2 = a and 0xFF0000 ushr 16 - val a3 = a and 0xFF00 ushr 8 - val a4 = a and 0xFF - - val b1 = b and 0xFF000000u.toInt() ushr 24 - val b2 = b and 0xFF0000 ushr 16 - val b3 = b and 0xFF00 ushr 8 - val b4 = b and 0xFF - println(abs(a1-b1) * 1 + abs(a2-b2) * 10 + abs(a3-b3) * 100 + abs(a4-b4) * 1000) - return abs(a1-b1) + abs(a2-b2) + abs(a3-b3) + abs(a4-b4) } internal fun isDjvuDocument(document: Document): Boolean { diff --git a/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/framework/BookTest.kt b/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/framework/BookTest.kt index 2b0dbab95..29949283a 100644 --- a/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/framework/BookTest.kt +++ b/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/framework/BookTest.kt @@ -7,15 +7,14 @@ import org.junit.After import org.junit.runner.RunWith import org.junit.runners.Parameterized import universe.constellation.orion.viewer.BuildConfig +import universe.constellation.orion.viewer.FileUtil import universe.constellation.orion.viewer.OrionViewerActivity import java.io.File @RunWith(Parameterized::class) -abstract class BookTest(path: String) : BaseTest() { +abstract class BookTest(protected val bookDescription: BookDescription) : BaseTest() { - constructor(bookDescription: BookDescription): this(bookDescription.path) - - private val documentDelegate = lazy { openTestBook(path) } + private val documentDelegate = lazy { bookDescription.openBook() } protected val document by documentDelegate @@ -40,19 +39,20 @@ enum class BookDescription( DJVU_SPEC(BaseTest.DJVU_SPEC, 71, null, 1, 100, Point(2539, 3295)); fun toOpenIntent(): Intent { - val path = extractFileFromTestData(path) return Intent(Intent.ACTION_VIEW).apply { setClassName( BuildConfig.APPLICATION_ID, OrionViewerActivity::class.qualifiedName!! ) - data = Uri.fromFile(path) + data = Uri.fromFile(asFile()) addCategory(Intent.CATEGORY_DEFAULT) } } fun asFile() = File(BaseTest.testFolder, path) + fun openBook() = FileUtil.openFile(asFile()) + companion object { private fun testEntries(): List { return if (MANUAL_DEBUG) { diff --git a/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/framework/bitmapUtils.kt b/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/framework/bitmapUtils.kt new file mode 100644 index 000000000..464c459be --- /dev/null +++ b/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/framework/bitmapUtils.kt @@ -0,0 +1,57 @@ +package universe.constellation.orion.viewer.test.framework + +import android.graphics.Bitmap +import android.os.Environment +import org.junit.Assert +import java.io.File +import java.io.FileOutputStream +import kotlin.math.abs + +internal fun dumpBitmap(prefix: String = "test", suffix: String, bitmap: Bitmap) { + val file = Environment.getExternalStorageDirectory().path + "/orion/$prefix$suffix.png" + println("saving dump into $file") + val file1 = File(file) + file1.parentFile?.mkdirs() + file1.createNewFile() + FileOutputStream(file).use { stream -> + bitmap.compress( + Bitmap.CompressFormat.PNG, + 100, + stream + ) + stream.close() + } +} + +internal const val DEFAULT_COLOR_DELTA = 3 + +//TODO check color difference reasons +internal fun compareBitmaps(partData: IntArray, fullData: IntArray, bitmapWidth: Int, message: String = "Fail", colorDelta: Int = DEFAULT_COLOR_DELTA, additionalDebugActions: () -> Unit) { + if (!partData.contentEquals(fullData)) { + if (MANUAL_DEBUG) { + additionalDebugActions() + } + for ( i in partData.indices) { + if (partData[i] != fullData[i]) { + val colorDiff = colorDiff(partData[i], fullData[i]) + if (colorDiff > colorDelta) { + Assert.fail("$message: different pixels at line " + i / bitmapWidth + " and position " + i % bitmapWidth + ": " + partData[i] + " vs " + fullData[i] + " diff=" + colorDiff) + } + } + } + } +} + +internal fun colorDiff(a: Int, b: Int): Int { + val a1 = a and 0xFF000000u.toInt() ushr 24 + val a2 = a and 0xFF0000 ushr 16 + val a3 = a and 0xFF00 ushr 8 + val a4 = a and 0xFF + + val b1 = b and 0xFF000000u.toInt() ushr 24 + val b2 = b and 0xFF0000 ushr 16 + val b3 = b and 0xFF00 ushr 8 + val b4 = b and 0xFF + println(abs(a1-b1) * 1 + abs(a2-b2) * 10 + abs(a3-b3) * 100 + abs(a4-b4) * 1000) + return abs(a1-b1) + abs(a2-b2) + abs(a3-b3) + abs(a4-b4) +} \ No newline at end of file diff --git a/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/rendering/FlexibleBitmapTest.kt b/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/rendering/FlexibleBitmapTest.kt index 2d6027dbb..b5c1daebe 100644 --- a/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/rendering/FlexibleBitmapTest.kt +++ b/orion-viewer/src/androidTest/kotlin/universe/constellation/orion/viewer/test/rendering/FlexibleBitmapTest.kt @@ -19,7 +19,7 @@ import universe.constellation.orion.viewer.test.framework.compareBitmaps import universe.constellation.orion.viewer.view.ColorStuff import java.nio.IntBuffer -class FlexibleBitmapTest(private val bookDescription: BookDescription) : BookTest(bookDescription) { +class FlexibleBitmapTest(bookDescription: BookDescription) : BookTest(bookDescription) { companion object { @JvmStatic