Skip to content

Commit 8e5fc47

Browse files
committed
add test
1 parent 4e0e2e2 commit 8e5fc47

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2965
-2
lines changed

.github/workflows/run_tests.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: Run tests
2+
on:
3+
pull_request:
4+
5+
jobs:
6+
build:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- uses: actions/checkout@v4
10+
- uses: actions/setup-java@v4
11+
with:
12+
java-version: '17'
13+
distribution: 'temurin'
14+
15+
- name: Setup Gradle
16+
uses: gradle/actions/setup-gradle@v3
17+
18+
- name: Unit Tests
19+
run: |
20+
chmod +x gradlew
21+
./gradlew test --stacktrace

app/build.gradle.kts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,22 @@ android {
6161
}
6262
}
6363

64+
packaging {
65+
resources {
66+
excludes.add("/META-INF/{AL2.0,LGPL2.1}")
67+
}
68+
}
69+
testOptions {
70+
unitTests {
71+
isIncludeAndroidResources = true
72+
}
73+
kotlinOptions {
74+
freeCompilerArgs += listOf(
75+
"-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
76+
)
77+
}
78+
}
79+
6480
namespace = "com.nativeapptemplate.nativeapptemplatefree"
6581
}
6682

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"data": {
3+
"id": "5712F2DF-DFC7-A3AA-66BC-191203654A1A",
4+
"type": "shopkeeper_sign_in",
5+
"attributes": {
6+
"account_id": "2140BC6B-1830-45EE-96A4-B4ED5F53AC11",
7+
"personal_account_id": "2140BC6B-1830-45EE-96A4-B4ED5F53AC11",
8+
"account_owner_id": "5712F2DF-DFC7-A3AA-66BC-191203654A1A",
9+
"account_name": "Account1",
10+
"email": "[email protected]",
11+
"name": "John Smith",
12+
"time_zone": "Tokyo",
13+
14+
}
15+
}
16+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"data": [
3+
{
4+
"id": "5712F2DF-DFC7-A3AA-66BC-191203654A1A",
5+
"type": "permission",
6+
"attributes": {
7+
"name": "update shops",
8+
"tag": "update_shops",
9+
"created_at": "2024-07-01T15:30:35.000Z",
10+
"updated_at": "2024-07-01T15:30:35.000Z"
11+
}
12+
},
13+
{
14+
"id": "5712F2DF-DFC7-A3AA-66BC-191203654A1B",
15+
"type": "permission",
16+
"attributes": {
17+
"name": "update organizations",
18+
"tag": "update_organizations",
19+
"created_at": "2024-07-01T15:30:35.000Z",
20+
"updated_at": "2024-07-01T15:30:35.000Z"
21+
}
22+
},
23+
{
24+
"id": "5712F2DF-DFC7-A3AA-66BC-191203654A1C",
25+
"type": "permission",
26+
"attributes": {
27+
"name": "invitation",
28+
"tag": "invitation",
29+
"created_at": "2024-07-01T15:30:35.000Z",
30+
"updated_at": "2024-07-01T15:30:35.000Z"
31+
}
32+
}
33+
],
34+
"meta": {
35+
"android_app_version": 1,
36+
"should_update_privacy": false,
37+
"should_update_terms": false,
38+
"shop_limit_count": 99
39+
}
40+
}

app/src/main/assets/shop.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"data": {
3+
"id": "5712F2DF-DFC7-A3AA-66BC-191203654A1C",
4+
"type": "shop",
5+
"attributes": {
6+
"name": "Shop1",
7+
"description": "This is a Shop1",
8+
"time_zone": "Tokyo"
9+
},
10+
"meta": {
11+
"limit_count": 96,
12+
"created_shops_count": 3
13+
}
14+
}
15+
}

app/src/main/assets/shops.json

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
"data": [
3+
{
4+
"id": "5712F2DF-DFC7-A3AA-66BC-191203654A1C",
5+
"type": "shop",
6+
"attributes": {
7+
"name": "Shop1",
8+
"description": "This is a Shop1",
9+
"time_zone": "Tokyo"
10+
},
11+
"meta": {
12+
"limit_count": 96,
13+
"created_shops_count": 3
14+
}
15+
},
16+
{
17+
"id": "5712F2DF-DFC7-A3AA-66BC-191203654A1D",
18+
"type": "shop",
19+
"attributes": {
20+
"name": "Shop2",
21+
"description": "This is a Shop2",
22+
"time_zone": "Tokyo"
23+
},
24+
"meta": {
25+
"limit_count": 96,
26+
"created_shops_count": 3
27+
}
28+
},
29+
{
30+
"id": "5712F2DF-DFC7-A3AA-66BC-191203654A1E",
31+
"type": "shop",
32+
"attributes": {
33+
"name": "Shop3",
34+
"description": "This is a Shop3",
35+
"time_zone": "Tokyo"
36+
},
37+
"meta": {
38+
"limit_count": 96,
39+
"created_shops_count": 3
40+
}
41+
}
42+
]
43+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.nativeapptemplate.nativeapptemplatefree.datastore
2+
3+
import com.nativeapptemplate.nativeapptemplatefree.UserPreferences
4+
import com.nativeapptemplate.nativeapptemplatefree.datastoreTest.InMemoryDataStore
5+
import com.nativeapptemplate.nativeapptemplatefree.model.Attributes
6+
import com.nativeapptemplate.nativeapptemplatefree.model.Data
7+
import com.nativeapptemplate.nativeapptemplatefree.model.LoggedInShopkeeper
8+
import kotlinx.coroutines.flow.first
9+
import kotlinx.coroutines.test.TestScope
10+
import kotlinx.coroutines.test.UnconfinedTestDispatcher
11+
import kotlinx.coroutines.test.runTest
12+
import org.junit.Assert.*
13+
import org.junit.Before
14+
import org.junit.Test
15+
16+
class NatPreferencesDataSourceTest {
17+
private val testScope = TestScope(UnconfinedTestDispatcher())
18+
19+
private lateinit var subject: NatPreferencesDataSource
20+
21+
@Before
22+
fun setup() {
23+
subject = NatPreferencesDataSource(InMemoryDataStore(UserPreferences.getDefaultInstance()))
24+
}
25+
26+
@Test
27+
fun isLoggedIn_isFalseByDefault() = testScope.runTest {
28+
assertFalse(subject.userData.first().isLoggedIn)
29+
}
30+
31+
@Test
32+
fun isLoggedIn_whenSettingShopkeeper_becomesTrue() = testScope.runTest {
33+
assertFalse(subject.isLoggedIn().first())
34+
35+
subject.setShopkeeper(testInputLoggedInShopkeeper)
36+
37+
assertTrue(subject.isLoggedIn().first())
38+
}
39+
}
40+
41+
private const val LOGGED_IN_SHOPKEEPER_TYPE = "shopkeeper_sign_in"
42+
private const val LOGGED_IN_SHOPKEEPER_ID = "5712F2DF-DFC7-A3AA-66BC-191203654A1A"
43+
private const val LOGGED_IN_SHOPKEEPER_ACCOUNT_ID = "2140BC6B-1830-45EE-96A4-B4ED5F53AC11"
44+
private const val LOGGED_IN_SHOPKEEPER_PERSONAL_ACCOUNT_ID = "2140BC6B-1830-45EE-96A4-B4ED5F53AC11"
45+
private const val LOGGED_IN_SHOPKEEPER_ACCOUNT_OWNER_ID = "5712F2DF-DFC7-A3AA-66BC-191203654A1A"
46+
private const val LOGGED_IN_SHOPKEEPER_ACCOUNT_NAME = "Account1"
47+
private const val LOGGED_IN_SHOPKEEPER_EMAIL = "[email protected]"
48+
private const val LOGGED_IN_SHOPKEEPER_NAME = "John Smith"
49+
private const val LOGGED_IN_SHOPKEEPER_TIME_ZONE = "Tokyo"
50+
private const val LOGGED_IN_SHOPKEEPER_TOKEN = "[email protected]"
51+
private const val LOGGED_IN_SHOPKEEPER_CLIENT = "Vd6GFW-9DaZrU2pzFd-Asa"
52+
private const val LOGGED_IN_SHOPKEEPER_UID = "[email protected]"
53+
private const val LOGGED_IN_SHOPKEEPER_EXPIRY = "1713165114"
54+
55+
private val testInputLoggedInShopkeeperData =
56+
Data(
57+
id = LOGGED_IN_SHOPKEEPER_ID,
58+
type = LOGGED_IN_SHOPKEEPER_TYPE,
59+
attributes = Attributes(
60+
accountId = LOGGED_IN_SHOPKEEPER_ACCOUNT_ID,
61+
personalAccountId = LOGGED_IN_SHOPKEEPER_PERSONAL_ACCOUNT_ID,
62+
accountOwnerId = LOGGED_IN_SHOPKEEPER_ACCOUNT_OWNER_ID,
63+
accountName = LOGGED_IN_SHOPKEEPER_ACCOUNT_NAME,
64+
email = LOGGED_IN_SHOPKEEPER_EMAIL,
65+
name = LOGGED_IN_SHOPKEEPER_NAME,
66+
timeZone = LOGGED_IN_SHOPKEEPER_TIME_ZONE,
67+
token = LOGGED_IN_SHOPKEEPER_TOKEN,
68+
client = LOGGED_IN_SHOPKEEPER_CLIENT,
69+
uid = LOGGED_IN_SHOPKEEPER_UID,
70+
expiry = LOGGED_IN_SHOPKEEPER_EXPIRY,
71+
)
72+
)
73+
74+
private val testInputLoggedInShopkeeper = LoggedInShopkeeper(
75+
datum = testInputLoggedInShopkeeperData,
76+
)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.nativeapptemplate.nativeapptemplatefree.datastore
2+
3+
import androidx.datastore.core.CorruptionException
4+
import com.nativeapptemplate.nativeapptemplatefree.userPreferences
5+
import kotlinx.coroutines.test.runTest
6+
import org.junit.Test
7+
import java.io.ByteArrayInputStream
8+
import java.io.ByteArrayOutputStream
9+
10+
class UserPreferencesSerializerTest {
11+
private val userPreferencesSerializer = UserPreferencesSerializer()
12+
13+
@Test
14+
fun defaultUserPreferences_isEmpty() {
15+
kotlin.test.assertEquals(
16+
userPreferences {
17+
// Default value
18+
},
19+
userPreferencesSerializer.defaultValue,
20+
)
21+
}
22+
23+
@Test
24+
fun writingAndReadingUserPreferences_outputsCorrectValue() = runTest {
25+
val expectedUserPreferences = userPreferences {
26+
isLoggedIn = true
27+
}
28+
29+
val outputStream = ByteArrayOutputStream()
30+
31+
expectedUserPreferences.writeTo(outputStream)
32+
33+
val inputStream = ByteArrayInputStream(outputStream.toByteArray())
34+
35+
val actualUserPreferences = userPreferencesSerializer.readFrom(inputStream)
36+
37+
kotlin.test.assertEquals(
38+
expectedUserPreferences,
39+
actualUserPreferences,
40+
)
41+
}
42+
43+
@Test(expected = CorruptionException::class)
44+
fun readingInvalidUserPreferences_throwsCorruptionException() = runTest {
45+
userPreferencesSerializer.readFrom(ByteArrayInputStream(byteArrayOf(0)))
46+
}
47+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.nativeapptemplate.nativeapptemplatefree.datastoreTest
2+
3+
import androidx.datastore.core.DataStore
4+
import kotlinx.coroutines.flow.MutableStateFlow
5+
import kotlinx.coroutines.flow.updateAndGet
6+
7+
class InMemoryDataStore<T>(initialValue: T) : DataStore<T> {
8+
override val data = MutableStateFlow(initialValue)
9+
override suspend fun updateData(
10+
transform: suspend (it: T) -> T,
11+
) = data.updateAndGet { transform(it) }
12+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2022 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.nativeapptemplate.nativeapptemplatefree.datastoreTest
18+
19+
import androidx.datastore.core.DataStore
20+
import com.nativeapptemplate.nativeapptemplatefree.UserPreferences
21+
import com.nativeapptemplate.nativeapptemplatefree.datastore.UserPreferencesSerializer
22+
import com.nativeapptemplate.nativeapptemplatefree.di.modules.DataStoreModule
23+
import dagger.Module
24+
import dagger.Provides
25+
import dagger.hilt.components.SingletonComponent
26+
import dagger.hilt.testing.TestInstallIn
27+
import javax.inject.Singleton
28+
29+
@Module
30+
@TestInstallIn(
31+
components = [SingletonComponent::class],
32+
replaces = [DataStoreModule::class],
33+
)
34+
internal object TestDataStoreModule {
35+
@Provides
36+
@Singleton
37+
fun providesUserPreferencesDataStore(
38+
serializer: UserPreferencesSerializer,
39+
): DataStore<UserPreferences> = InMemoryDataStore(serializer.defaultValue)
40+
}

0 commit comments

Comments
 (0)