Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
19 changes: 19 additions & 0 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,24 @@ jobs:
gradle-caches-${{ runner.os }}-
- name: Detekt
run: ./gradlew detekt
- name: Stop Gradle
run: ./gradlew --stop

test:
name: Unit Tests
needs: [ validation ]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Save Gradle Caches
uses: actions/cache@v4
with:
path: ~/.gradle/caches/
key: gradle-caches-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
gradle-caches-${{ runner.os }}-
Comment thread
KCeh marked this conversation as resolved.
- name: Run Unit Tests
run: ./gradlew clean testDebugUnitTest
- name: Stop Gradle
run: ./gradlew --stop
8 changes: 8 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ compose = "1.7.8"
coreKtx = "1.13.1"
detekt = "1.23.6"
dokka = "1.9.10"
junit = "4.13.2"
junitExt = "1.2.1"
kotlin = "2.0.20"
kotlinxCoroutinesTest = "1.8.0"
material3Android = "1.3.1"
mockk = "1.13.9"

[plugins]
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
Expand All @@ -20,10 +24,14 @@ kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activityCompose" }
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" }
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "coreKtx" }
androidx-junit-ext = { module = "androidx.test.ext:junit", version.ref = "junitExt" }
androidx-material3-android = { module = "androidx.compose.material3:material3-android", version.ref = "material3Android" }
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose" }
compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose" }
detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" }
dokka-plugin = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "dokka" }
junit = { module = "junit:junit", version.ref = "junit" }
kotlin-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinxCoroutinesTest" }
mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
tools-gradle = { module = "com.android.tools.build:gradle", version.ref = "androidGradlePlugin" }
34 changes: 34 additions & 0 deletions snacky/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,38 @@ dependencies {

implementation(libs.androidx.core.ktx)
implementation(libs.androidx.material3.android)

// Testing dependencies
testImplementation(libs.junit)
testImplementation(libs.kotlinx.coroutines.test)
testImplementation(libs.mockk)
androidTestImplementation(libs.androidx.junit.ext)
}

// Configure test tasks to show detailed output in console
tasks.withType<Test> {
testLogging {
// Show test events in console
events("passed", "skipped", "failed", "standardOut", "standardError")

// Show detailed information for failed tests
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
showExceptions = true
showCauses = true
showStackTraces = true

// Show standard output and error streams
showStandardStreams = false

// Display summary after test execution
afterSuite(KotlinClosure2({ desc: TestDescriptor, result: TestResult ->
Comment thread
KCeh marked this conversation as resolved.
Outdated
if (desc.parent == null) { // Only execute for the overall test suite
println("\nTest Results: ${result.resultType}")
println("Tests run: ${result.testCount}, " +
"Passed: ${result.successfulTestCount}, " +
"Failed: ${result.failedTestCount}, " +
"Skipped: ${result.skippedTestCount}")
}
}))
}
}
264 changes: 264 additions & 0 deletions snacky/src/test/java/com/infinum/snacky/DefaultSnackbarDataTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
package com.infinum.snacky

import com.infinum.snacky.default.DefaultSnackbarData
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
Comment thread
KCeh marked this conversation as resolved.
Outdated
import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertNull
import org.junit.Test

/**
* Unit tests for [DefaultSnackbarData].
* Tests the data model for default snackbars and their properties.
*/
class DefaultSnackbarDataTest {

@Test
fun `DefaultSnackbarData should store message correctly`() {
// Given
val message = "Test message"

// When
val data = DefaultSnackbarData(
message = message,
actionLabel = null,
withDismissAction = false,
dismissActionContentDescription = "",
duration = SnackyDuration.Short
)

// Then
assertEquals(message, data.message)
}

@Test
fun `DefaultSnackbarData should store action label correctly`() {
// Given
val actionLabel = "Action"

// When
val data = DefaultSnackbarData(
message = "Test",
actionLabel = actionLabel,
withDismissAction = false,
dismissActionContentDescription = "",
duration = SnackyDuration.Short
)

// Then
assertEquals(actionLabel, data.actionLabel)
}

@Test
fun `DefaultSnackbarData should handle null action label`() {
// When
val data = DefaultSnackbarData(
message = "Test",
actionLabel = null,
withDismissAction = false,
dismissActionContentDescription = "",
duration = SnackyDuration.Short
)

// Then
assertNull(data.actionLabel)
}

@Test
fun `DefaultSnackbarData should store dismiss action flag correctly`() {
// When
val dataWithDismiss = DefaultSnackbarData(
message = "Test",
actionLabel = null,
withDismissAction = true,
dismissActionContentDescription = "",
duration = SnackyDuration.Short
)

val dataWithoutDismiss = DefaultSnackbarData(
message = "Test",
actionLabel = null,
withDismissAction = false,
dismissActionContentDescription = "",
duration = SnackyDuration.Short
)

// Then
assertEquals(true, dataWithDismiss.withDismissAction)
assertEquals(false, dataWithoutDismiss.withDismissAction)
}

@Test
fun `DefaultSnackbarData should store dismiss action content description`() {
// Given
val contentDescription = "Close"

// When
val data = DefaultSnackbarData(
message = "Test",
actionLabel = null,
withDismissAction = true,
dismissActionContentDescription = contentDescription,
duration = SnackyDuration.Short
)

// Then
assertEquals(contentDescription, data.dismissActionContentDescription)
}

@Test
fun `DefaultSnackbarData should store duration correctly`() {
// Given
val duration = SnackyDuration.Long

// When
val data = DefaultSnackbarData(
message = "Test",
actionLabel = null,
withDismissAction = false,
dismissActionContentDescription = "",
duration = duration
)

// Then
assertEquals(duration, data.duration)
}

@Test
fun `DefaultSnackbarData should have default empty callbacks`() {
// When
val data = DefaultSnackbarData(
message = "Test",
actionLabel = null,
withDismissAction = false,
dismissActionContentDescription = "",
duration = SnackyDuration.Short
)

// Then - Should not throw when calling callbacks
data.onDismissCallback()
data.onMainActionCallback()
}

@Test
fun `DefaultSnackbarData should store custom callbacks`() {
// Given
var mainActionCalled = false
var dismissCalled = false

// When
val data = DefaultSnackbarData(
message = "Test",
actionLabel = "Action",
withDismissAction = true,
dismissActionContentDescription = "",
duration = SnackyDuration.Short,
onMainActionCallback = { mainActionCalled = true },
onDismissCallback = { dismissCalled = true }
)

data.onMainActionCallback()
data.onDismissCallback()

// Then
assertEquals(true, mainActionCalled)
assertEquals(true, dismissCalled)
Comment thread
KCeh marked this conversation as resolved.
}

@Test
fun `DefaultSnackbarData hasAction should be based on callback comparison`() {
// When
val data = DefaultSnackbarData(
message = "Test",
actionLabel = null,
withDismissAction = false,
dismissActionContentDescription = "",
duration = SnackyDuration.Short
)

// Then
// Note: hasAction checks if callbacks are not equal to empty lambda {}
// This is implementation-specific behavior
val hasAction = data.hasAction
// Just verify the property is accessible
assertEquals(hasAction, data.hasAction)
Comment thread
KCeh marked this conversation as resolved.
Outdated
}

@Test
fun `Two DefaultSnackbarData with same properties should have same core values`() {
// Given
val callback = { }
val data1 = DefaultSnackbarData(
message = "Test",
actionLabel = "Action",
withDismissAction = true,
dismissActionContentDescription = "Close",
duration = SnackyDuration.Short,
onDismissCallback = callback,
onMainActionCallback = callback
)

val data2 = DefaultSnackbarData(
message = "Test",
actionLabel = "Action",
withDismissAction = true,
dismissActionContentDescription = "Close",
duration = SnackyDuration.Short,
onDismissCallback = callback,
onMainActionCallback = callback
)

// Then - Check that core properties match
assertEquals(data1.message, data2.message)
assertEquals(data1.actionLabel, data2.actionLabel)
assertEquals(data1.withDismissAction, data2.withDismissAction)
assertEquals(data1.dismissActionContentDescription, data2.dismissActionContentDescription)
assertEquals(data1.duration, data2.duration)
}

@Test
fun `Two DefaultSnackbarData with different messages should not be equal`() {
// Given
val data1 = DefaultSnackbarData(
message = "Test 1",
actionLabel = null,
withDismissAction = false,
dismissActionContentDescription = "",
duration = SnackyDuration.Short
)

val data2 = DefaultSnackbarData(
message = "Test 2",
actionLabel = null,
withDismissAction = false,
dismissActionContentDescription = "",
duration = SnackyDuration.Short
)

// Then
assertNotEquals(data1, data2)
}

@Test
fun `Two DefaultSnackbarData with different durations should not be equal`() {
// Given
val data1 = DefaultSnackbarData(
message = "Test",
actionLabel = null,
withDismissAction = false,
dismissActionContentDescription = "",
duration = SnackyDuration.Short
)

val data2 = DefaultSnackbarData(
message = "Test",
actionLabel = null,
withDismissAction = false,
dismissActionContentDescription = "",
duration = SnackyDuration.Long
)

// Then
assertNotEquals(data1, data2)
}
}
Loading