Done now rather than later: the application ID is permanent once published -- Play treats a change as an entirely different app -- so this is the last cheap moment to choose it. applicationId / namespace dev.jasonmross.mediaconverter -> org.libremediaconverter source tree java/dev/jasonmross/mediaconverter -> java/org/libremediaconverter gradle project AndroidMediaConverter -> LibreMediaConverter theme Theme.MediaConverter -> Theme.LibreMediaConverter compose theme MediaConverterTheme -> LibreMediaConverterTheme display name "Media Converter" -> "LibreMediaConverter" org.* rather than dev.jasonmross.* because "Libre" signals a project rather than a personal app, and a project-owned namespace lets maintainership move later without the identifier contradicting reality. The source trees moved with git mv so history follows the files instead of showing 42 deletions beside 42 additions. Verified after the rename: 66 unit tests, and 40 instrumented tests on an API 36 emulator, 0 failures. The built APK reports org.libremediaconverter, and no stale jasonmross, AndroidMediaConverter or MediaConverterTheme identifiers remain anywhere in the tree. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
75 lines
2.4 KiB
Kotlin
75 lines
2.4 KiB
Kotlin
package org.libremediaconverter.fallback
|
|
|
|
import android.content.Context
|
|
import android.net.Uri
|
|
import org.libremediaconverter.convert.ConversionDependencies
|
|
import org.libremediaconverter.convert.HardwareTranscoder
|
|
import org.libremediaconverter.convert.OutputPublisher
|
|
import org.libremediaconverter.convert.SoftwareTranscoder
|
|
import org.libremediaconverter.model.ConversionRequest
|
|
import java.io.File
|
|
|
|
/**
|
|
* Test doubles that force the failure paths.
|
|
*
|
|
* These exist because error handling is otherwise the least-tested code in the app: by
|
|
* definition it only runs when something goes wrong, which is exactly what a healthy
|
|
* test run avoids. Without a way to inject failure, the branches a user meets on a bad
|
|
* day are the ones that were never executed.
|
|
*/
|
|
object FakeFailures {
|
|
|
|
class ExplodingHardware(private val message: String = "hardware exploded") : HardwareTranscoder {
|
|
var called = false
|
|
override suspend fun transcode(
|
|
input: Uri,
|
|
output: File,
|
|
videoMimeType: String,
|
|
onProgress: (Int) -> Unit,
|
|
) {
|
|
called = true
|
|
throw IllegalStateException(message)
|
|
}
|
|
|
|
override fun close() = Unit
|
|
}
|
|
|
|
class ExplodingSoftware(private val message: String = "software exploded") : SoftwareTranscoder {
|
|
var called = false
|
|
override suspend fun run(
|
|
request: ConversionRequest,
|
|
inputPath: String,
|
|
output: File,
|
|
durationMs: Long,
|
|
onProgress: (Int) -> Unit,
|
|
) {
|
|
called = true
|
|
throw IllegalStateException(message)
|
|
}
|
|
}
|
|
|
|
/** Records that it ran and writes a plausible output, without doing real work. */
|
|
class RecordingSoftware : SoftwareTranscoder {
|
|
var called = false
|
|
override suspend fun run(
|
|
request: ConversionRequest,
|
|
inputPath: String,
|
|
output: File,
|
|
durationMs: Long,
|
|
onProgress: (Int) -> Unit,
|
|
) {
|
|
called = true
|
|
output.parentFile?.mkdirs()
|
|
output.writeBytes(ByteArray(1024))
|
|
onProgress(100)
|
|
}
|
|
}
|
|
|
|
class FullDisk(context: Context) : OutputPublisher(context) {
|
|
override fun hasSpaceFor(bytes: Long): Boolean = false
|
|
}
|
|
|
|
/** Restores the real implementations. Always call this from @After. */
|
|
fun reset() = ConversionDependencies.reset()
|
|
}
|