|
| 1 | +package org.schabi.newpipe.settings |
| 2 | + |
| 3 | +import android.content.SharedPreferences |
| 4 | +import org.junit.Assert |
| 5 | +import org.junit.Test |
| 6 | +import org.mockito.Mockito |
| 7 | +import org.schabi.newpipe.settings.export.BackupFileLocator |
| 8 | +import org.schabi.newpipe.settings.export.ImportExportManager |
| 9 | +import org.schabi.newpipe.streams.io.StoredFileHelper |
| 10 | +import us.shandian.giga.io.FileStream |
| 11 | +import java.io.File |
| 12 | +import java.io.IOException |
| 13 | +import java.nio.file.Files |
| 14 | + |
| 15 | +class ImportAllCombinationsTest { |
| 16 | + |
| 17 | + companion object { |
| 18 | + private val classloader = ImportExportManager::class.java.classLoader!! |
| 19 | + } |
| 20 | + |
| 21 | + private enum class Ser(val id: String) { |
| 22 | + YES("ser"), |
| 23 | + VULNERABLE("vulnser"), |
| 24 | + NO("noser"); |
| 25 | + } |
| 26 | + |
| 27 | + private data class FailData( |
| 28 | + val containsDb: Boolean, |
| 29 | + val containsSer: Ser, |
| 30 | + val containsJson: Boolean, |
| 31 | + val filename: String, |
| 32 | + val throwable: Throwable, |
| 33 | + ) |
| 34 | + |
| 35 | + private fun testZipCombination( |
| 36 | + containsDb: Boolean, |
| 37 | + containsSer: Ser, |
| 38 | + containsJson: Boolean, |
| 39 | + filename: String, |
| 40 | + runTest: (test: () -> Unit) -> Unit, |
| 41 | + ) { |
| 42 | + val zipFile = File(classloader.getResource(filename)?.file!!) |
| 43 | + val zip = Mockito.mock(StoredFileHelper::class.java, Mockito.withSettings().stubOnly()) |
| 44 | + Mockito.`when`(zip.stream).then { FileStream(zipFile) } |
| 45 | + |
| 46 | + val fileLocator = Mockito.mock( |
| 47 | + BackupFileLocator::class.java, |
| 48 | + Mockito.withSettings().stubOnly() |
| 49 | + ) |
| 50 | + val db = File.createTempFile("newpipe_", "") |
| 51 | + val dbJournal = File.createTempFile("newpipe_", "") |
| 52 | + val dbWal = File.createTempFile("newpipe_", "") |
| 53 | + val dbShm = File.createTempFile("newpipe_", "") |
| 54 | + Mockito.`when`(fileLocator.db).thenReturn(db) |
| 55 | + Mockito.`when`(fileLocator.dbJournal).thenReturn(dbJournal) |
| 56 | + Mockito.`when`(fileLocator.dbShm).thenReturn(dbShm) |
| 57 | + Mockito.`when`(fileLocator.dbWal).thenReturn(dbWal) |
| 58 | + |
| 59 | + if (containsDb) { |
| 60 | + runTest { |
| 61 | + Assert.assertTrue(ImportExportManager(fileLocator).extractDb(zip)) |
| 62 | + Assert.assertFalse(dbJournal.exists()) |
| 63 | + Assert.assertFalse(dbWal.exists()) |
| 64 | + Assert.assertFalse(dbShm.exists()) |
| 65 | + Assert.assertTrue("database file size is zero", Files.size(db.toPath()) > 0) |
| 66 | + } |
| 67 | + } else { |
| 68 | + runTest { |
| 69 | + Assert.assertFalse(ImportExportManager(fileLocator).extractDb(zip)) |
| 70 | + Assert.assertTrue(dbJournal.exists()) |
| 71 | + Assert.assertTrue(dbWal.exists()) |
| 72 | + Assert.assertTrue(dbShm.exists()) |
| 73 | + Assert.assertEquals(0, Files.size(db.toPath())) |
| 74 | + } |
| 75 | + } |
| 76 | + |
| 77 | + val preferences = Mockito.mock(SharedPreferences::class.java, Mockito.withSettings().stubOnly()) |
| 78 | + var editor = Mockito.mock(SharedPreferences.Editor::class.java) |
| 79 | + Mockito.`when`(preferences.edit()).thenReturn(editor) |
| 80 | + Mockito.`when`(editor.commit()).thenReturn(true) |
| 81 | + |
| 82 | + when (containsSer) { |
| 83 | + Ser.YES -> runTest { |
| 84 | + Assert.assertTrue(ImportExportManager(fileLocator).exportHasSerializedPrefs(zip)) |
| 85 | + ImportExportManager(fileLocator).loadSerializedPrefs(zip, preferences) |
| 86 | + |
| 87 | + Mockito.verify(editor, Mockito.times(1)).clear() |
| 88 | + Mockito.verify(editor, Mockito.times(1)).commit() |
| 89 | + Mockito.verify(editor, Mockito.atLeastOnce()) |
| 90 | + .putBoolean(Mockito.anyString(), Mockito.anyBoolean()) |
| 91 | + Mockito.verify(editor, Mockito.atLeastOnce()) |
| 92 | + .putString(Mockito.anyString(), Mockito.anyString()) |
| 93 | + Mockito.verify(editor, Mockito.atLeastOnce()) |
| 94 | + .putInt(Mockito.anyString(), Mockito.anyInt()) |
| 95 | + } |
| 96 | + Ser.VULNERABLE -> runTest { |
| 97 | + Assert.assertTrue(ImportExportManager(fileLocator).exportHasSerializedPrefs(zip)) |
| 98 | + Assert.assertThrows(ClassNotFoundException::class.java) { |
| 99 | + ImportExportManager(fileLocator).loadSerializedPrefs(zip, preferences) |
| 100 | + } |
| 101 | + |
| 102 | + Mockito.verify(editor, Mockito.never()).clear() |
| 103 | + Mockito.verify(editor, Mockito.never()).commit() |
| 104 | + } |
| 105 | + Ser.NO -> runTest { |
| 106 | + Assert.assertFalse(ImportExportManager(fileLocator).exportHasSerializedPrefs(zip)) |
| 107 | + Assert.assertThrows(IOException::class.java) { |
| 108 | + ImportExportManager(fileLocator).loadSerializedPrefs(zip, preferences) |
| 109 | + } |
| 110 | + |
| 111 | + Mockito.verify(editor, Mockito.never()).clear() |
| 112 | + Mockito.verify(editor, Mockito.never()).commit() |
| 113 | + } |
| 114 | + } |
| 115 | + |
| 116 | + // recreate editor mock so verify() behaves correctly |
| 117 | + editor = Mockito.mock(SharedPreferences.Editor::class.java) |
| 118 | + Mockito.`when`(preferences.edit()).thenReturn(editor) |
| 119 | + Mockito.`when`(editor.commit()).thenReturn(true) |
| 120 | + |
| 121 | + if (containsJson) { |
| 122 | + runTest { |
| 123 | + Assert.assertTrue(ImportExportManager(fileLocator).exportHasJsonPrefs(zip)) |
| 124 | + ImportExportManager(fileLocator).loadJsonPrefs(zip, preferences) |
| 125 | + |
| 126 | + Mockito.verify(editor, Mockito.times(1)).clear() |
| 127 | + Mockito.verify(editor, Mockito.times(1)).commit() |
| 128 | + Mockito.verify(editor, Mockito.atLeastOnce()) |
| 129 | + .putBoolean(Mockito.anyString(), Mockito.anyBoolean()) |
| 130 | + Mockito.verify(editor, Mockito.atLeastOnce()) |
| 131 | + .putString(Mockito.anyString(), Mockito.anyString()) |
| 132 | + Mockito.verify(editor, Mockito.atLeastOnce()) |
| 133 | + .putInt(Mockito.anyString(), Mockito.anyInt()) |
| 134 | + } |
| 135 | + } else { |
| 136 | + runTest { |
| 137 | + Assert.assertFalse(ImportExportManager(fileLocator).exportHasJsonPrefs(zip)) |
| 138 | + Assert.assertThrows(IOException::class.java) { |
| 139 | + ImportExportManager(fileLocator).loadJsonPrefs(zip, preferences) |
| 140 | + } |
| 141 | + |
| 142 | + Mockito.verify(editor, Mockito.never()).clear() |
| 143 | + Mockito.verify(editor, Mockito.never()).commit() |
| 144 | + } |
| 145 | + } |
| 146 | + } |
| 147 | + |
| 148 | + @Test |
| 149 | + fun `Importing all possible combinations of zip files`() { |
| 150 | + val failedAssertions = mutableListOf<FailData>() |
| 151 | + for (containsDb in listOf(true, false)) { |
| 152 | + for (containsSer in Ser.entries) { |
| 153 | + for (containsJson in listOf(true, false)) { |
| 154 | + val filename = "settings/${if (containsDb) "db" else "nodb"}_${ |
| 155 | + containsSer.id}_${if (containsJson) "json" else "nojson"}.zip" |
| 156 | + testZipCombination(containsDb, containsSer, containsJson, filename) { test -> |
| 157 | + try { |
| 158 | + test() |
| 159 | + } catch (e: Throwable) { |
| 160 | + failedAssertions.add( |
| 161 | + FailData( |
| 162 | + containsDb, containsSer, containsJson, |
| 163 | + filename, e |
| 164 | + ) |
| 165 | + ) |
| 166 | + } |
| 167 | + } |
| 168 | + } |
| 169 | + } |
| 170 | + } |
| 171 | + |
| 172 | + if (failedAssertions.isNotEmpty()) { |
| 173 | + for (a in failedAssertions) { |
| 174 | + println( |
| 175 | + "Assertion failed with containsDb=${a.containsDb}, containsSer=${ |
| 176 | + a.containsSer}, containsJson=${a.containsJson}, filename=${a.filename}:" |
| 177 | + ) |
| 178 | + a.throwable.printStackTrace() |
| 179 | + println() |
| 180 | + } |
| 181 | + Assert.fail("${failedAssertions.size} assertions failed") |
| 182 | + } |
| 183 | + } |
| 184 | +} |
0 commit comments