Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/android-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ jobs:
./gradlew --version
java -version

- name: Bootstrap Android SDK (Tier 0)
env:
TERM: dumb
run: bash scripts/agent/healthcheck.sh --tier 0

- name: Run unit tests
env:
JAVA_TOOL_OPTIONS: -Xmx2g -Dfile.encoding=UTF-8
Expand Down Expand Up @@ -79,6 +84,11 @@ jobs:
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v3

- name: Bootstrap Android SDK (Tier 0)
env:
TERM: dumb
run: bash scripts/agent/healthcheck.sh --tier 0

- name: Build debug & androidTest APKs
env:
JAVA_TOOL_OPTIONS: -Xmx2g -Dfile.encoding=UTF-8
Expand Down Expand Up @@ -132,6 +142,11 @@ jobs:
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v3

- name: Bootstrap Android SDK (Tier 0)
env:
TERM: dumb
run: bash scripts/agent/healthcheck.sh --tier 0

- name: Run lint
env:
JAVA_TOOL_OPTIONS: -Xmx2g -Dfile.encoding=UTF-8
Expand Down
20 changes: 20 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ jobs:
- name: Make gradlew executable
run: chmod +x ./gradlew

- name: Bootstrap Android SDK (Tier 0)
env:
TERM: dumb
run: bash scripts/agent/healthcheck.sh --tier 0

- name: Quick Compile Test (Fail Fast)
run: ./gradlew compileDebugKotlin compileDebugJava --stacktrace

Expand Down Expand Up @@ -89,6 +94,11 @@ jobs:
- name: Make gradlew executable
run: chmod +x ./gradlew

- name: Bootstrap Android SDK (Tier 0)
env:
TERM: dumb
run: bash scripts/agent/healthcheck.sh --tier 0

- name: Accept Android SDK Licenses
run: yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses || true

Expand Down Expand Up @@ -134,6 +144,11 @@ jobs:
- name: Make gradlew executable
run: chmod +x ./gradlew

- name: Bootstrap Android SDK (Tier 0)
env:
TERM: dumb
run: bash scripts/agent/healthcheck.sh --tier 0

- name: Accept Android SDK Licenses
run: yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses || true

Expand Down Expand Up @@ -188,6 +203,11 @@ jobs:
- name: Make gradlew executable
run: chmod +x ./gradlew

- name: Bootstrap Android SDK (Tier 0)
env:
TERM: dumb
run: bash scripts/agent/healthcheck.sh --tier 0

- name: Accept Android SDK Licenses
run: yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses || true

Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ jobs:
./gradlew --version
java -version

- name: Bootstrap Android SDK (Tier 0)
env:
TERM: dumb
run: bash scripts/agent/healthcheck.sh --tier 0

- name: Run unit tests (no daemon)
env:
JAVA_TOOL_OPTIONS: -Xmx2g -Dfile.encoding=UTF-8
Expand Down
9 changes: 5 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,11 @@ Thumbs.db
# Firebase configuration
**/google-services.json

# Agent temporary files
.claude/
.amazonq/cli-todo-lists/
.kilocode/
# Agent temporary files
.claude/
.amazonq/cli-todo-lists/
.kilocode/
.android-sdk/

# Keep important documentation but ignore temp files
!README.md
Expand Down
1 change: 1 addition & 0 deletions SaidIt/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ dependencies {
testImplementation(libs.mockito.core)
testImplementation(libs.mockito.kotlin)
testImplementation(libs.robolectric)
testRuntimeOnly(libs.robolectric.android.all)
testImplementation(libs.coroutines.test)
// Hilt testing for Robolectric/JUnit
testImplementation(libs.hilt.android.testing)
Expand Down
5 changes: 5 additions & 0 deletions SaidIt/src/test/kotlin/eu/mrogalski/android/ViewsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,17 @@ import android.widget.TextView
import org.junit.Assert.*
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.*
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config

/**
* Comprehensive unit tests for Views utility functions.
* Tests both legacy Java-compatible methods and modern Kotlin extensions.
*/
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [34])
class ViewsTest {

private lateinit var rootViewGroup: ViewGroup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import org.robolectric.RobolectricTestRunner
import org.robolectric.RuntimeEnvironment
import org.robolectric.annotation.Config
import org.robolectric.shadows.ShadowApplication
import org.robolectric.Shadows
import org.robolectric.shadows.ShadowNotificationManager

/**
Expand Down Expand Up @@ -78,7 +79,7 @@ class NotifyFileReceiverTest {
receiver.onSuccess(testUri)

// Then
val shadowNotificationManager = ShadowNotificationManager.shadowOf(
val shadowNotificationManager = Shadows.shadowOf(
context.getSystemService(Context.NOTIFICATION_SERVICE) as android.app.NotificationManager
)
val notifications = shadowNotificationManager.allNotifications
Expand All @@ -97,7 +98,7 @@ class NotifyFileReceiverTest {
receiver.onSuccess(testUri)

// Then
val shadowNotificationManager = ShadowNotificationManager.shadowOf(
val shadowNotificationManager = Shadows.shadowOf(
context.getSystemService(Context.NOTIFICATION_SERVICE) as android.app.NotificationManager
)
val notifications = shadowNotificationManager.allNotifications
Expand All @@ -117,7 +118,7 @@ class NotifyFileReceiverTest {
receiver.onSuccess(testUri)

// Then
val shadowNotificationManager = ShadowNotificationManager.shadowOf(
val shadowNotificationManager = Shadows.shadowOf(
context.getSystemService(Context.NOTIFICATION_SERVICE) as android.app.NotificationManager
)
val notification = shadowNotificationManager.getNotification(43)
Expand All @@ -134,7 +135,7 @@ class NotifyFileReceiverTest {
receiver.onFailure(exception)

// Then - no exception thrown, no notification posted
val shadowNotificationManager = ShadowNotificationManager.shadowOf(
val shadowNotificationManager = Shadows.shadowOf(
context.getSystemService(Context.NOTIFICATION_SERVICE) as android.app.NotificationManager
)
val notifications = shadowNotificationManager.allNotifications
Expand Down Expand Up @@ -224,15 +225,15 @@ class NotifyFileReceiverTest {

// Test without permission
receiver.onSuccess(testUri)
var shadowNotificationManager = ShadowNotificationManager.shadowOf(
var shadowNotificationManager = Shadows.shadowOf(
context.getSystemService(Context.NOTIFICATION_SERVICE) as android.app.NotificationManager
)
assertEquals(0, shadowNotificationManager.allNotifications.size)

// Grant permission and test again
ShadowApplication.getInstance().grantPermissions(Manifest.permission.POST_NOTIFICATIONS)
receiver.onSuccess(testUri)
shadowNotificationManager = ShadowNotificationManager.shadowOf(
shadowNotificationManager = Shadows.shadowOf(
context.getSystemService(Context.NOTIFICATION_SERVICE) as android.app.NotificationManager
)
assertEquals(1, shadowNotificationManager.allNotifications.size)
Expand Down Expand Up @@ -279,7 +280,7 @@ class NotifyFileReceiverTest {
receiver.onSuccess(testUri2)

// Then - only one notification because same ID is used
val shadowNotificationManager = ShadowNotificationManager.shadowOf(
val shadowNotificationManager = Shadows.shadowOf(
context.getSystemService(Context.NOTIFICATION_SERVICE) as android.app.NotificationManager
)
val notification = shadowNotificationManager.getNotification(43)
Expand Down
17 changes: 10 additions & 7 deletions SaidIt/src/test/kotlin/eu/mrogalski/saidit/SaidItFragmentTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import com.google.android.material.button.MaterialButtonToggleGroup
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.textview.MaterialTextView
import eu.mrogalski.android.TimeFormat
import eu.mrogalski.saidit.NotifyFileReceiver
import eu.mrogalski.saidit.PromptFileReceiver
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
Expand All @@ -26,6 +28,7 @@ import org.mockito.junit.MockitoJUnitRunner
import org.mockito.MockedStatic
import org.robolectric.RobolectricTestRunner
import org.robolectric.RuntimeEnvironment
import org.robolectric.Shadows.shadowOf
import org.robolectric.annotation.Config

/**
Expand Down Expand Up @@ -245,7 +248,7 @@ class SaidItFragmentTest {
val fileName = "test_recording.mp4"

// When
val notification = fragment.buildNotificationForFile(appContext, fileUri, fileName)
val notification = NotifyFileReceiver.buildNotificationForFile(appContext, fileUri, fileName)

// Then
assert(notification != null)
Expand All @@ -257,10 +260,10 @@ class SaidItFragmentTest {
// Given - Use Robolectric's application context
val appContext = RuntimeEnvironment.getApplication()
val mockUri = mock(Uri::class.java)
val receiver = fragment.NotifyFileReceiver(appContext)
val receiver = NotifyFileReceiver(appContext)

// Grant POST_NOTIFICATIONS permission so NotificationManagerCompat.notify() is reachable
org.robolectric.Shadows.shadowOf(appContext).grantPermissions(android.Manifest.permission.POST_NOTIFICATIONS)
shadowOf(appContext).grantPermissions(android.Manifest.permission.POST_NOTIFICATIONS)

// Mock static method using Mockito
mockStatic(NotificationManagerCompat::class.java).use { mockedStatic ->
Expand All @@ -278,7 +281,7 @@ class SaidItFragmentTest {
@Test
fun `NotifyFileReceiver onFailure does nothing`() {
// Given
val receiver = fragment.NotifyFileReceiver(mockContext)
val receiver = NotifyFileReceiver(mockContext)
val exception = Exception("Test failure")

// When
Expand All @@ -296,7 +299,7 @@ class SaidItFragmentTest {
`when`(mockActivity.isFinishing).thenReturn(false)
`when`(mockDialog.isShowing).thenReturn(true)

val receiver = fragment.PromptFileReceiver(mockActivity, mockDialog)
val receiver = PromptFileReceiver(mockActivity, mockDialog)

// Mock the dialog builder chain
val mockBuilder = mock(MaterialAlertDialogBuilder::class.java)
Expand All @@ -320,7 +323,7 @@ class SaidItFragmentTest {
val mockUri = mock(Uri::class.java)
`when`(mockActivity.isFinishing).thenReturn(true)

val receiver = fragment.PromptFileReceiver(mockActivity)
val receiver = PromptFileReceiver(mockActivity)

// When
receiver.onSuccess(mockUri)
Expand All @@ -335,7 +338,7 @@ class SaidItFragmentTest {
val exception = Exception("Test error")
`when`(mockActivity.isFinishing).thenReturn(false)

val receiver = fragment.PromptFileReceiver(mockActivity)
val receiver = PromptFileReceiver(mockActivity)

// Mock the dialog builder
val mockBuilder = mock(MaterialAlertDialogBuilder::class.java)
Expand Down
3 changes: 1 addition & 2 deletions audio/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ dependencies {
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.8.0")
testImplementation("junit:junit:4.13.2")
testImplementation("org.robolectric:robolectric:4.11.1")
testImplementation("androidx.test:core:1.5.0")
testImplementation("io.mockk:mockk:1.13.13")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@ package com.siya.epistemophile.audio
import android.media.MediaPlayer
import java.io.File

class AudioPlayer(private val inputFile: File) {
class AudioPlayer(
private val inputFile: File,
private val playerProvider: () -> MediaPlayer = { MediaPlayer() }
) {

private var player: MediaPlayer? = null

fun start() {
try {
player = MediaPlayer().apply {
val instance = playerProvider().apply {
setDataSource(inputFile.absolutePath)
prepare()
start()
}
player = instance
} catch (e: Exception) {
e.printStackTrace()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,23 @@ package com.siya.epistemophile.audio
import android.media.MediaRecorder
import java.io.File

class AudioRecorder(private val outputFile: File) {
class AudioRecorder(
private val outputFile: File,
private val recorderProvider: () -> MediaRecorder = { MediaRecorder() }
) {

private var recorder: MediaRecorder? = null

fun start() {
recorder = MediaRecorder().apply {
val instance = recorderProvider().apply {
setAudioSource(MediaRecorder.AudioSource.MIC)
setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
setOutputFile(outputFile.absolutePath)
prepare()
start()
}
recorder = instance
}

fun stop() {
Expand Down
Loading
Loading