Initial commit
This commit is contained in:
commit
6072b2ba29
844 changed files with 220532 additions and 0 deletions
|
|
@ -0,0 +1,105 @@
|
|||
// BaseTtsSynthesizerTest.kt
|
||||
package com.aryan.reader.tts
|
||||
|
||||
import android.speech.tts.TextToSpeech
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class BaseTtsSynthesizerTest {
|
||||
|
||||
@get:Rule
|
||||
val mainDispatcherRule = MainDispatcherRule()
|
||||
|
||||
private lateinit var synthesizer: BaseTtsSynthesizer
|
||||
private var ttsEngineAvailable = false
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
// Ensure TTS is available on the device/emulator before running tests
|
||||
val tts = TextToSpeech(ApplicationProvider.getApplicationContext(), null)
|
||||
if (tts.engines.isNotEmpty()) {
|
||||
ttsEngineAvailable = true
|
||||
synthesizer = BaseTtsSynthesizer(ApplicationProvider.getApplicationContext())
|
||||
}
|
||||
tts.shutdown()
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
if (this::synthesizer.isInitialized) {
|
||||
synthesizer.shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun initialize_initializesTtsEngineSuccessfully() {
|
||||
if (!ttsEngineAvailable) return
|
||||
|
||||
runBlocking {
|
||||
// This will throw if it fails
|
||||
withTimeout(10000L) {
|
||||
synthesizer.initialize()
|
||||
}
|
||||
// No assertion needed, success is not throwing an exception.
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun synthesizeToFile_withValidText_createsAudioFile() {
|
||||
if (!ttsEngineAvailable) return
|
||||
|
||||
runBlocking {
|
||||
withTimeout(15000L) {
|
||||
synthesizer.initialize()
|
||||
val (file, returnedText) = synthesizer.synthesizeToFile("This is a test.")
|
||||
|
||||
assertThat(file).isNotNull()
|
||||
assertThat(file?.exists()).isTrue()
|
||||
assertThat(file?.length()).isGreaterThan(0L)
|
||||
assertThat(returnedText).isEqualTo("This is a test.")
|
||||
|
||||
file?.delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun synthesizeToFile_withBlankText_returnsNullFile() {
|
||||
if (!ttsEngineAvailable) return
|
||||
|
||||
runBlocking {
|
||||
synthesizer.initialize()
|
||||
val (file, returnedText) = synthesizer.synthesizeToFile(" ")
|
||||
|
||||
assertThat(file).isNull()
|
||||
assertThat(returnedText).isEqualTo(" ")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun synthesizeToFile_withoutInitializingFirst_initializesAndSucceeds() {
|
||||
if (!ttsEngineAvailable) return
|
||||
|
||||
runBlocking {
|
||||
withTimeout(15000L) {
|
||||
val (file, returnedText) = synthesizer.synthesizeToFile("This should work.")
|
||||
|
||||
assertThat(file).isNotNull()
|
||||
assertThat(file?.exists()).isTrue()
|
||||
assertThat(file?.length()).isGreaterThan(0L)
|
||||
assertThat(returnedText).isEqualTo("This should work.")
|
||||
|
||||
file?.delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.aryan.reader.tts
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestDispatcher
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.resetMain
|
||||
import kotlinx.coroutines.test.setMain
|
||||
import org.junit.rules.TestWatcher
|
||||
import org.junit.runner.Description
|
||||
|
||||
/**
|
||||
* A JUnit TestRule that sets the Main dispatcher to a TestDispatcher for the duration of a test.
|
||||
* This allows tests to execute coroutines on the Main dispatcher without needing a real Android environment.
|
||||
*/
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class MainDispatcherRule(
|
||||
private val testDispatcher: TestDispatcher = UnconfinedTestDispatcher()
|
||||
) : TestWatcher() {
|
||||
override fun starting(description: Description) {
|
||||
Dispatchers.setMain(testDispatcher)
|
||||
}
|
||||
|
||||
override fun finished(description: Description) {
|
||||
Dispatchers.resetMain()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
// TtsUtilsTest.kt
|
||||
package com.aryan.reader.tts
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class TtsUtilsTest {
|
||||
|
||||
@Test
|
||||
fun splitTextIntoChunks_withShortText_returnsSingleChunk() {
|
||||
val text = "This is a short sentence."
|
||||
val chunks = splitTextIntoChunks(text, 100)
|
||||
assertThat(chunks).containsExactly("This is a short sentence.")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun splitTextIntoChunks_withMultipleSentences_splitsCorrectly() {
|
||||
val text = "First sentence. Second sentence! Third sentence? And a fourth."
|
||||
val chunks = splitTextIntoChunks(text, 20)
|
||||
assertThat(chunks).containsExactly(
|
||||
"First sentence.",
|
||||
"Second sentence!",
|
||||
"Third sentence?",
|
||||
"And a fourth."
|
||||
).inOrder()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun splitTextIntoChunks_combinesShortSentences() {
|
||||
val text = "First. Second. Third. Fourth."
|
||||
val chunks = splitTextIntoChunks(text, maxLengthPerChunk = 20)
|
||||
assertThat(chunks).containsExactly(
|
||||
"First. Second.",
|
||||
"Third. Fourth."
|
||||
).inOrder()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun splitTextIntoChunks_withLongSentence_doesNotSplitSentence() {
|
||||
val text = "This is a very long sentence that exceeds the maximum chunk length but has no punctuation to split on."
|
||||
val chunks = splitTextIntoChunks(text, 50)
|
||||
assertThat(chunks).containsExactly(text)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun splitTextIntoChunks_withEmptyText_returnsEmptyList() {
|
||||
val text = ""
|
||||
val chunks = splitTextIntoChunks(text, 100)
|
||||
assertThat(chunks).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun splitTextIntoChunks_withBlankText_returnsEmptyList() {
|
||||
val text = " "
|
||||
val chunks = splitTextIntoChunks(text, 100)
|
||||
assertThat(chunks).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun splitTextIntoChunks_handlesAbbreviations() {
|
||||
val text = "Mr. Smith went to Washington. Dr. Jones followed."
|
||||
val chunks = splitTextIntoChunks(text, 40)
|
||||
assertThat(chunks).containsExactly(
|
||||
"Mr. Smith went to Washington.",
|
||||
"Dr. Jones followed."
|
||||
).inOrder()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue