This commit is contained in:
parent
6fb7c4a073
commit
6137ff3372
@ -19,6 +19,6 @@ jobs:
|
|||||||
- name: Setup Android SDK
|
- name: Setup Android SDK
|
||||||
uses: android-actions/setup-android@v3
|
uses: android-actions/setup-android@v3
|
||||||
- name: Configure gradle...
|
- name: Configure gradle...
|
||||||
run: mkdir -p ~/.gradle && echo "org.gradle.daemon=false\nignoreGitVersion=true\nsystemProp.org.gradle.internal.http.connectionTimeout=180000\nsystemProp.org.gradle.internal.http.socketTimeout=180000" >> ~/.gradle/gradle.properties
|
run: mkdir -p ~/.gradle && echo "org.gradle.daemon=false\nignoreGitVersion=true" >> ~/.gradle/gradle.properties
|
||||||
- name: Build and test
|
- name: Build and test
|
||||||
run: ./gradlew build --stacktrace
|
run: ./gradlew build --stacktrace
|
@ -10,10 +10,10 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Check out repository code
|
- name: Check out repository code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
# with:
|
with:
|
||||||
# fetch-depth: 0
|
fetch-depth: 0
|
||||||
# - name: Fetch tags
|
- name: Fetch tags
|
||||||
# run: git fetch --tags -p
|
run: git fetch --tags -p
|
||||||
- name: Init compose
|
- name: Init compose
|
||||||
uses: KengoTODA/actions-setup-docker-compose@v1
|
uses: KengoTODA/actions-setup-docker-compose@v1
|
||||||
with:
|
with:
|
||||||
@ -21,20 +21,35 @@ jobs:
|
|||||||
- name: run selfoss
|
- name: run selfoss
|
||||||
run: |
|
run: |
|
||||||
docker compose -f .gitea/workflows/assets/docker-compose.yml up -d
|
docker compose -f .gitea/workflows/assets/docker-compose.yml up -d
|
||||||
|
sleep 1m
|
||||||
response=$(curl 172.17.0.1:8888/api/about)
|
response=$(curl 172.17.0.1:8888/api/about)
|
||||||
echo $response
|
echo $response
|
||||||
# - uses: actions/setup-java@v4
|
- uses: actions/setup-java@v4
|
||||||
# with:
|
with:
|
||||||
# distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
# java-version: '17'
|
java-version: '17'
|
||||||
# - name: Setup Android SDK
|
- name: Setup Android SDK
|
||||||
# uses: android-actions/setup-android@v3
|
uses: android-actions/setup-android@v3
|
||||||
# - name: Configure gradle...
|
- name: Configure gradle...
|
||||||
# run: mkdir -p ~/.gradle && echo "org.gradle.daemon=false\nignoreGitVersion=true\nsystemProp.org.gradle.internal.http.connectionTimeout=180000\nsystemProp.org.gradle.internal.http.socketTimeout=180000" >> ~/.gradle/gradle.properties
|
run: mkdir -p ~/.gradle && echo "org.gradle.daemon=false\nignoreGitVersion=true" >> ~/.gradle/gradle.properties
|
||||||
# - name: Build and test
|
- name: ui tests
|
||||||
# run: ./gradlew build --stacktrace
|
uses: reactivecircus/android-emulator-runner@v2
|
||||||
|
with:
|
||||||
|
api-level: 25
|
||||||
|
force-avd-creation: false
|
||||||
|
disable-animations: true
|
||||||
|
profile: Nexus 6
|
||||||
|
script: adb shell am broadcast -a android.intent.action.CLOSE_SYSTEM_DIALOGS && ./gradlew connectedAndroidTest
|
||||||
|
- name: Artifacts
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
if: failure()
|
||||||
|
with:
|
||||||
|
name: ui-tests
|
||||||
|
path: androidApp/build/outputs/androidTest-results/connected/debug/flavors/githubConfig
|
||||||
|
retention-days: 1
|
||||||
|
overwrite: true
|
||||||
|
include-hidden-files: true
|
||||||
- name: Clean
|
- name: Clean
|
||||||
if: success() || failure()
|
if: always()
|
||||||
run: |
|
run: |
|
||||||
docker compose -f .gitea/workflows/assets/docker-compose.yml stop
|
docker compose -f .gitea/workflows/assets/docker-compose.yml stop
|
||||||
|
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -320,4 +320,7 @@ fabric.properties
|
|||||||
# End of https://www.toptal.com/developers/gitignore/api/gradle,kotlin,androidstudio,android,xcode,swift
|
# End of https://www.toptal.com/developers/gitignore/api/gradle,kotlin,androidstudio,android,xcode,swift
|
||||||
|
|
||||||
|
|
||||||
crowdin.properties
|
crowdin.properties
|
||||||
|
|
||||||
|
.kotlin/
|
||||||
|
build-cache/
|
1
androidApp/.gitignore
vendored
1
androidApp/.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
/build
|
/build
|
||||||
|
.kotlin/
|
@ -84,6 +84,7 @@ android {
|
|||||||
|
|
||||||
// tests
|
// tests
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
testInstrumentationRunnerArguments["clearPackageData"] = "true"
|
||||||
}
|
}
|
||||||
packaging {
|
packaging {
|
||||||
resources {
|
resources {
|
||||||
@ -107,6 +108,10 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
namespace = "bou.amine.apps.readerforselfossv2.android"
|
namespace = "bou.amine.apps.readerforselfossv2.android"
|
||||||
|
testOptions {
|
||||||
|
animationsDisabled = true
|
||||||
|
execution = "ANDROIDX_TEST_ORCHESTRATOR"
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,6 +189,13 @@ dependencies {
|
|||||||
testImplementation("io.mockk:mockk:1.12.0")
|
testImplementation("io.mockk:mockk:1.12.0")
|
||||||
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1")
|
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")
|
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")
|
||||||
|
androidTestImplementation("androidx.test:runner:1.6.2")
|
||||||
|
androidTestImplementation("androidx.test:rules:1.6.1")
|
||||||
|
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
|
||||||
|
implementation("androidx.test.espresso:espresso-idling-resource:3.6.1")
|
||||||
|
androidTestImplementation("androidx.test.ext:junit-ktx:1.2.1")
|
||||||
|
androidTestUtil("androidx.test:orchestrator:1.5.1")
|
||||||
|
|
||||||
|
|
||||||
implementation("ch.acra:acra-http:$acraVersion")
|
implementation("ch.acra:acra-http:$acraVersion")
|
||||||
implementation("ch.acra:acra-toast:$acraVersion")
|
implementation("ch.acra:acra-toast:$acraVersion")
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package bou.amine.apps.readerforselfossv2.android
|
||||||
|
|
||||||
|
import androidx.test.espresso.Espresso.onView
|
||||||
|
import androidx.test.espresso.action.ViewActions.click
|
||||||
|
import androidx.test.espresso.action.ViewActions.typeTextIntoFocusedView
|
||||||
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
|
|
||||||
|
fun performLogin(url: String) {
|
||||||
|
onView(withId(R.id.urlView)).perform(click()).perform(
|
||||||
|
typeTextIntoFocusedView(url)
|
||||||
|
)
|
||||||
|
onView(withId(R.id.signInButton)).perform(click())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loginAndInitHome() {
|
||||||
|
performLogin("http://10.0.2.2:8888")
|
||||||
|
onView(withText(R.string.gdpr_dialog_title)).check(matches(isDisplayed()))
|
||||||
|
onView(withText("OK")).perform(click())
|
||||||
|
}
|
@ -0,0 +1,151 @@
|
|||||||
|
package bou.amine.apps.readerforselfossv2.android
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.test.core.app.ApplicationProvider
|
||||||
|
import androidx.test.espresso.Espresso.onView
|
||||||
|
import androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu
|
||||||
|
import androidx.test.espresso.action.ViewActions
|
||||||
|
import androidx.test.espresso.action.ViewActions.click
|
||||||
|
import androidx.test.espresso.action.ViewActions.typeTextIntoFocusedView
|
||||||
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.isClickable
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.isFocused
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.isRoot
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.isSelected
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
|
import androidx.test.ext.junit.rules.ActivityScenarioRule
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import androidx.test.filters.LargeTest
|
||||||
|
import org.hamcrest.CoreMatchers.not
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@LargeTest
|
||||||
|
class HomeActivityTest {
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
val activityRule = ActivityScenarioRule(LoginActivity::class.java)
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun init() {
|
||||||
|
loginAndInitHome()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMenu() {
|
||||||
|
onView(withId(R.id.action_search)).check(matches(isDisplayed())).check(
|
||||||
|
matches(
|
||||||
|
isClickable()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
onView(withId(R.id.action_filter)).check(matches(isDisplayed())).check(
|
||||||
|
matches(
|
||||||
|
isClickable()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
openActionBarOverflowOrOptionsMenu(
|
||||||
|
ApplicationProvider.getApplicationContext<Context>()
|
||||||
|
)
|
||||||
|
onView(withText(R.string.readAll)).check(matches(isDisplayed()))
|
||||||
|
onView(withText(R.string.menu_home_sources)).check(matches(isDisplayed()))
|
||||||
|
onView(withText(R.string.title_activity_settings)).check(matches(isDisplayed()))
|
||||||
|
onView(withText(R.string.menu_home_refresh)).check(matches(isDisplayed()))
|
||||||
|
onView(withText(R.string.issue_tracker_link)).check(matches(isDisplayed()))
|
||||||
|
onView(withText(R.string.action_disconnect)).check(matches(isDisplayed()))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMenuActions() {
|
||||||
|
onView(withId(R.id.action_search)).perform(click())
|
||||||
|
onView(
|
||||||
|
withId(R.id.search_src_text)
|
||||||
|
).check(matches(isFocused()))
|
||||||
|
onView(isRoot()).perform(ViewActions.pressBack())
|
||||||
|
|
||||||
|
onView(withId(R.id.action_filter)).perform(click())
|
||||||
|
onView(
|
||||||
|
withText(R.string.filter_item_sources)
|
||||||
|
).check(matches(isDisplayed()))
|
||||||
|
onView(
|
||||||
|
withText(R.string.filter_item_tags)
|
||||||
|
).check(matches(isDisplayed()))
|
||||||
|
onView(
|
||||||
|
withId(R.id.floatingActionButton2)
|
||||||
|
).check(matches(isDisplayed()))
|
||||||
|
onView(isRoot()).perform(ViewActions.pressBack())
|
||||||
|
|
||||||
|
openActionBarOverflowOrOptionsMenu(
|
||||||
|
ApplicationProvider.getApplicationContext<Context>()
|
||||||
|
)
|
||||||
|
onView(withText(R.string.readAll)).perform(click())
|
||||||
|
onView(withText(R.string.markall_dialog_message)).check(matches(isDisplayed()))
|
||||||
|
onView(isRoot()).perform(ViewActions.pressBack())
|
||||||
|
openActionBarOverflowOrOptionsMenu(
|
||||||
|
ApplicationProvider.getApplicationContext<Context>()
|
||||||
|
)
|
||||||
|
|
||||||
|
onView(withText(R.string.menu_home_sources)).perform(click())
|
||||||
|
onView(withId(R.id.fab)).check(matches(isDisplayed()))
|
||||||
|
onView(isRoot()).perform(ViewActions.pressBack())
|
||||||
|
openActionBarOverflowOrOptionsMenu(
|
||||||
|
ApplicationProvider.getApplicationContext<Context>()
|
||||||
|
)
|
||||||
|
|
||||||
|
onView(withText(R.string.title_activity_settings)).perform(click())
|
||||||
|
onView(withText(R.string.pref_header_general)).check(matches(isDisplayed()))
|
||||||
|
onView(isRoot()).perform(ViewActions.pressBack())
|
||||||
|
openActionBarOverflowOrOptionsMenu(
|
||||||
|
ApplicationProvider.getApplicationContext<Context>()
|
||||||
|
)
|
||||||
|
|
||||||
|
onView(withText(R.string.menu_home_refresh)).perform(click())
|
||||||
|
onView(withText(R.string.refresh_dialog_message)).check(matches(isDisplayed()))
|
||||||
|
onView(isRoot()).perform(ViewActions.pressBack())
|
||||||
|
openActionBarOverflowOrOptionsMenu(
|
||||||
|
ApplicationProvider.getApplicationContext<Context>()
|
||||||
|
)
|
||||||
|
|
||||||
|
/*onView(withText(R.string.issue_tracker_link)).perform(click())
|
||||||
|
onView(withText(R.string.markall_dialog_message)).check(matches(isDisplayed()))
|
||||||
|
onView(isRoot()).perform(ViewActions.pressBack())
|
||||||
|
openActionBarOverflowOrOptionsMenu(
|
||||||
|
ApplicationProvider.getApplicationContext<Context>()
|
||||||
|
)*/
|
||||||
|
|
||||||
|
onView(withText(R.string.action_disconnect)).perform(click())
|
||||||
|
onView(withText(R.string.confirm_disconnect_title)).check(matches(isDisplayed()))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testEmptyView() {
|
||||||
|
onView(withId(R.id.emptyText)).check(matches(isDisplayed()))
|
||||||
|
onView(
|
||||||
|
hasBottombarItemText(R.string.tab_new)
|
||||||
|
).check(matches(isDisplayed())).check(matches(isSelected()))
|
||||||
|
onView(
|
||||||
|
hasBottombarItemText(R.string.tab_read)
|
||||||
|
).check(matches(isDisplayed())).check(matches(not(isSelected())))
|
||||||
|
onView(
|
||||||
|
hasBottombarItemText(R.string.tab_favs)
|
||||||
|
).check(matches(isDisplayed())).check(matches(not(isSelected())))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun addSource() {
|
||||||
|
openActionBarOverflowOrOptionsMenu(
|
||||||
|
ApplicationProvider.getApplicationContext<Context>()
|
||||||
|
)
|
||||||
|
onView(withText(R.string.menu_home_sources))
|
||||||
|
.perform(click())
|
||||||
|
onView(withId(R.id.fab))
|
||||||
|
.perform(click())
|
||||||
|
onView(withId(R.id.nameInput))
|
||||||
|
.perform(click()).perform(typeTextIntoFocusedView("Source"))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
package bou.amine.apps.readerforselfossv2.android
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import androidx.test.espresso.Espresso.onView
|
||||||
|
import androidx.test.espresso.IdlingRegistry
|
||||||
|
import androidx.test.espresso.action.ViewActions.click
|
||||||
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.isClickable
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.isNotChecked
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
|
import androidx.test.ext.junit.rules.ActivityScenarioRule
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import androidx.test.filters.LargeTest
|
||||||
|
import bou.amine.apps.readerforselfossv2.android.testing.CountingIdlingResourceSingleton
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@LargeTest
|
||||||
|
class LoginActivityTest {
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
val activityRule = ActivityScenarioRule(LoginActivity::class.java)
|
||||||
|
|
||||||
|
private fun getActivity(): Activity? {
|
||||||
|
var activity: Activity? = null
|
||||||
|
activityRule.scenario.onActivity {
|
||||||
|
activity = it
|
||||||
|
}
|
||||||
|
return activity
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun registerIdlingResource() {
|
||||||
|
IdlingRegistry.getInstance()
|
||||||
|
.register(CountingIdlingResourceSingleton.countingIdlingResource)
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun unregisterIdlingResource() {
|
||||||
|
IdlingRegistry.getInstance()
|
||||||
|
.unregister(CountingIdlingResourceSingleton.countingIdlingResource)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun viewIsInitialized() {
|
||||||
|
onView(withId(R.id.urlView)).check(matches(isDisplayed()))
|
||||||
|
onView(withId(R.id.selfSigned)).check(matches(isDisplayed())).check(matches(isNotChecked()))
|
||||||
|
.check(
|
||||||
|
matches(isClickable())
|
||||||
|
)
|
||||||
|
onView(withId(R.id.withLogin)).check(matches(isDisplayed()))
|
||||||
|
.check(matches(isNotChecked())).check(
|
||||||
|
matches(isClickable())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun urlError() {
|
||||||
|
performLogin("172.17.0.1:8888")
|
||||||
|
onView(withId(R.id.urlView)).perform(click())
|
||||||
|
onView(withId(R.id.urlView)).check(matches(withError(R.string.wrong_infos)))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun multiError() {
|
||||||
|
onView(withId(R.id.signInButton)).perform(click())
|
||||||
|
onView(withId(R.id.signInButton)).perform(click())
|
||||||
|
onView(withId(R.id.signInButton)).perform(click())
|
||||||
|
onView(withText(R.string.warning_wrong_url)).check(matches(isDisplayed()))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun connect() {
|
||||||
|
performLogin("http://10.0.2.2:8888")
|
||||||
|
onView(withText(R.string.gdpr_dialog_title)).check(matches(isDisplayed()))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
package bou.amine.apps.readerforselfossv2.android
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.EditText
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
|
import androidx.test.espresso.Root
|
||||||
|
import androidx.test.espresso.matcher.RootMatchers.isPlatformPopup
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.hasSibling
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withParent
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withResourceName
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
|
import org.hamcrest.CoreMatchers.allOf
|
||||||
|
import org.hamcrest.Description
|
||||||
|
import org.hamcrest.Matcher
|
||||||
|
import org.hamcrest.TypeSafeMatcher
|
||||||
|
|
||||||
|
|
||||||
|
fun withError(@StringRes id: Int): TypeSafeMatcher<View?> {
|
||||||
|
return object : TypeSafeMatcher<View?>() {
|
||||||
|
override fun matchesSafely(view: View?): Boolean {
|
||||||
|
if (view == null) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
val context = view.context
|
||||||
|
if (view !is EditText) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return view.error.toString() == context.getString(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun describeTo(description: Description?) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isPopupWindow(): Matcher<Root> {
|
||||||
|
return isPlatformPopup()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun withDrawable(@DrawableRes id: Int) = object : TypeSafeMatcher<View>() {
|
||||||
|
override fun describeTo(description: Description) {
|
||||||
|
description.appendText("ImageView with drawable same as drawable with id $id")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun matchesSafely(view: View): Boolean {
|
||||||
|
val context = view.context
|
||||||
|
val expectedBitmap = context.getDrawable(id)!!.toBitmap()
|
||||||
|
try {
|
||||||
|
return view is ImageView && view.drawable.toBitmap().sameAs(expectedBitmap)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hasBottombarItemText(@StringRes id: Int): Matcher<View>? {
|
||||||
|
return allOf(
|
||||||
|
withResourceName("fixed_bottom_navigation_icon"),
|
||||||
|
withParent(
|
||||||
|
allOf(
|
||||||
|
withResourceName("fixed_bottom_navigation_icon_container"),
|
||||||
|
hasSibling(withText(id))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
@ -29,6 +29,7 @@ import bou.amine.apps.readerforselfossv2.android.background.LoadingWorker
|
|||||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityHomeBinding
|
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityHomeBinding
|
||||||
import bou.amine.apps.readerforselfossv2.android.fragments.FilterSheetFragment
|
import bou.amine.apps.readerforselfossv2.android.fragments.FilterSheetFragment
|
||||||
import bou.amine.apps.readerforselfossv2.android.settings.SettingsActivity
|
import bou.amine.apps.readerforselfossv2.android.settings.SettingsActivity
|
||||||
|
import bou.amine.apps.readerforselfossv2.android.testing.CountingIdlingResourceSingleton
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.bottombar.maybeShow
|
import bou.amine.apps.readerforselfossv2.android.utils.bottombar.maybeShow
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.bottombar.removeBadge
|
import bou.amine.apps.readerforselfossv2.android.utils.bottombar.removeBadge
|
||||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||||
@ -84,7 +85,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
repository.offlineOverride = intent.getBooleanExtra("startOffline", false)
|
repository.offlineOverride = intent.getBooleanExtra("startOffline", false)
|
||||||
|
|
||||||
if (fromTabShortcut) {
|
if (fromTabShortcut) {
|
||||||
elementsShown = ItemType.fromInt(intent.getIntExtra("shortcutTab", ItemType.UNREAD.position))
|
elementsShown =
|
||||||
|
ItemType.fromInt(intent.getIntExtra("shortcutTab", ItemType.UNREAD.position))
|
||||||
}
|
}
|
||||||
|
|
||||||
setContentView(view)
|
setContentView(view)
|
||||||
@ -96,8 +98,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
handleSwipeRefreshLayout()
|
handleSwipeRefreshLayout()
|
||||||
|
|
||||||
if (appSettingsService.isItemCachingEnabled()) {
|
if (appSettingsService.isItemCachingEnabled()) {
|
||||||
|
CountingIdlingResourceSingleton.increment()
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
repository.tryToCacheItemsAndGetNewOnes()
|
repository.tryToCacheItemsAndGetNewOnes()
|
||||||
|
CountingIdlingResourceSingleton.decrement()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,9 +115,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
binding.swipeRefreshLayout.setOnRefreshListener {
|
binding.swipeRefreshLayout.setOnRefreshListener {
|
||||||
repository.offlineOverride = false
|
repository.offlineOverride = false
|
||||||
lastFetchDone = false
|
lastFetchDone = false
|
||||||
|
CountingIdlingResourceSingleton.increment()
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
getElementsAccordingToTab()
|
getElementsAccordingToTab()
|
||||||
binding.swipeRefreshLayout.isRefreshing = false
|
binding.swipeRefreshLayout.isRefreshing = false
|
||||||
|
CountingIdlingResourceSingleton.decrement()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,9 +280,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
handleGDPRDialog(appSettingsService.settings.getBoolean("GDPR_shown", false))
|
handleGDPRDialog(appSettingsService.settings.getBoolean("GDPR_shown", false))
|
||||||
|
|
||||||
handleRecurringTask()
|
handleRecurringTask()
|
||||||
|
CountingIdlingResourceSingleton.increment()
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
repository.handleDBActions()
|
repository.handleDBActions()
|
||||||
|
CountingIdlingResourceSingleton.decrement()
|
||||||
}
|
}
|
||||||
|
|
||||||
getElementsAccordingToTab()
|
getElementsAccordingToTab()
|
||||||
@ -315,6 +322,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
)
|
)
|
||||||
binding.recyclerView.layoutManager = layoutManager
|
binding.recyclerView.layoutManager = layoutManager
|
||||||
}
|
}
|
||||||
|
|
||||||
is GridLayoutManager ->
|
is GridLayoutManager ->
|
||||||
if (appSettingsService.isCardViewEnabled()) {
|
if (appSettingsService.isCardViewEnabled()) {
|
||||||
layoutManager =
|
layoutManager =
|
||||||
@ -326,6 +334,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
|
StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
|
||||||
binding.recyclerView.layoutManager = layoutManager
|
binding.recyclerView.layoutManager = layoutManager
|
||||||
}
|
}
|
||||||
|
|
||||||
else ->
|
else ->
|
||||||
if (currentManager == null) {
|
if (currentManager == null) {
|
||||||
if (!appSettingsService.isCardViewEnabled()) {
|
if (!appSettingsService.isCardViewEnabled()) {
|
||||||
@ -362,12 +371,14 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
} else {
|
} else {
|
||||||
layoutManager.scrollToPositionWithOffset(0, 0)
|
layoutManager.scrollToPositionWithOffset(0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
is GridLayoutManager ->
|
is GridLayoutManager ->
|
||||||
if (layoutManager.findFirstCompletelyVisibleItemPosition() == 0) {
|
if (layoutManager.findFirstCompletelyVisibleItemPosition() == 0) {
|
||||||
getElementsAccordingToTab()
|
getElementsAccordingToTab()
|
||||||
} else {
|
} else {
|
||||||
layoutManager.scrollToPositionWithOffset(0, 0)
|
layoutManager.scrollToPositionWithOffset(0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -420,6 +431,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
manager.findLastCompletelyVisibleItemPositions(
|
manager.findLastCompletelyVisibleItemPositions(
|
||||||
null,
|
null,
|
||||||
).last()
|
).last()
|
||||||
|
|
||||||
is GridLayoutManager -> manager.findLastCompletelyVisibleItemPosition()
|
is GridLayoutManager -> manager.findLastCompletelyVisibleItemPosition()
|
||||||
else -> 0
|
else -> 0
|
||||||
}
|
}
|
||||||
@ -448,6 +460,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
appendResults: Boolean,
|
appendResults: Boolean,
|
||||||
itemType: ItemType,
|
itemType: ItemType,
|
||||||
) {
|
) {
|
||||||
|
CountingIdlingResourceSingleton.increment()
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
binding.swipeRefreshLayout.isRefreshing = true
|
binding.swipeRefreshLayout.isRefreshing = true
|
||||||
repository.displayedItems = itemType
|
repository.displayedItems = itemType
|
||||||
@ -459,6 +472,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
}
|
}
|
||||||
binding.swipeRefreshLayout.isRefreshing = false
|
binding.swipeRefreshLayout.isRefreshing = false
|
||||||
handleListResult()
|
handleListResult()
|
||||||
|
CountingIdlingResourceSingleton.decrement()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -469,8 +483,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
when (oldManager) {
|
when (oldManager) {
|
||||||
is StaggeredGridLayoutManager ->
|
is StaggeredGridLayoutManager ->
|
||||||
oldManager.findFirstCompletelyVisibleItemPositions(null).last()
|
oldManager.findFirstCompletelyVisibleItemPositions(null).last()
|
||||||
|
|
||||||
is GridLayoutManager ->
|
is GridLayoutManager ->
|
||||||
oldManager.findFirstCompletelyVisibleItemPosition()
|
oldManager.findFirstCompletelyVisibleItemPosition()
|
||||||
|
|
||||||
else -> 0
|
else -> 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -511,8 +527,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
private fun reloadBadges() {
|
private fun reloadBadges() {
|
||||||
if (appSettingsService.isDisplayUnreadCountEnabled() || appSettingsService.isDisplayAllCountEnabled()) {
|
if (appSettingsService.isDisplayUnreadCountEnabled() || appSettingsService.isDisplayAllCountEnabled()) {
|
||||||
|
CountingIdlingResourceSingleton.increment()
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
repository.reloadBadges()
|
repository.reloadBadges()
|
||||||
|
CountingIdlingResourceSingleton.decrement()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -548,7 +566,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
}
|
}
|
||||||
|
|
||||||
val searchItem = menu.findItem(R.id.action_search)
|
val searchItem = menu.findItem(R.id.action_search)
|
||||||
val searchView = searchItem.getActionView() as SearchView
|
val searchView = searchItem.actionView as SearchView
|
||||||
searchView.setOnQueryTextListener(this)
|
searchView.setOnQueryTextListener(this)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@ -571,18 +589,22 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.issue_tracker -> {
|
R.id.issue_tracker -> {
|
||||||
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(AppSettingsService.trackerUrl))
|
val browserIntent =
|
||||||
|
Intent(Intent.ACTION_VIEW, Uri.parse(AppSettingsService.trackerUrl))
|
||||||
startActivity(browserIntent)
|
startActivity(browserIntent)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_filter -> {
|
R.id.action_filter -> {
|
||||||
val filterSheetFragment = FilterSheetFragment()
|
val filterSheetFragment = FilterSheetFragment()
|
||||||
filterSheetFragment.show(supportFragmentManager, FilterSheetFragment.TAG)
|
filterSheetFragment.show(supportFragmentManager, FilterSheetFragment.TAG)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.refresh -> {
|
R.id.refresh -> {
|
||||||
needsConfirmation(R.string.menu_home_refresh, R.string.refresh_dialog_message) {
|
needsConfirmation(R.string.menu_home_refresh, R.string.refresh_dialog_message) {
|
||||||
Toast.makeText(this, R.string.refresh_in_progress, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.refresh_in_progress, Toast.LENGTH_SHORT).show()
|
||||||
|
CountingIdlingResourceSingleton.increment()
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
val updatedRemote = repository.updateRemote()
|
val updatedRemote = repository.updateRemote()
|
||||||
if (updatedRemote) {
|
if (updatedRemote) {
|
||||||
@ -599,15 +621,17 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
Toast.LENGTH_SHORT,
|
Toast.LENGTH_SHORT,
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
|
CountingIdlingResourceSingleton.decrement()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.readAll -> {
|
R.id.readAll -> {
|
||||||
if (elementsShown == ItemType.UNREAD) {
|
if (elementsShown == ItemType.UNREAD) {
|
||||||
needsConfirmation(R.string.readAll, R.string.markall_dialog_message) {
|
needsConfirmation(R.string.readAll, R.string.markall_dialog_message) {
|
||||||
binding.swipeRefreshLayout.isRefreshing = true
|
binding.swipeRefreshLayout.isRefreshing = true
|
||||||
|
CountingIdlingResourceSingleton.increment()
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
val success = repository.markAllAsRead(items)
|
val success = repository.markAllAsRead(items)
|
||||||
if (success) {
|
if (success) {
|
||||||
@ -628,13 +652,19 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
}
|
}
|
||||||
handleListResult()
|
handleListResult()
|
||||||
binding.swipeRefreshLayout.isRefreshing = false
|
binding.swipeRefreshLayout.isRefreshing = false
|
||||||
|
CountingIdlingResourceSingleton.decrement()
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_disconnect -> {
|
R.id.action_disconnect -> {
|
||||||
needsConfirmation(R.string.confirm_disconnect_title, R.string.confirm_disconnect_description) {
|
needsConfirmation(
|
||||||
|
R.string.confirm_disconnect_title,
|
||||||
|
R.string.confirm_disconnect_description
|
||||||
|
) {
|
||||||
runBlocking {
|
runBlocking {
|
||||||
repository.logout()
|
repository.logout()
|
||||||
}
|
}
|
||||||
@ -644,14 +674,17 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_settings -> {
|
R.id.action_settings -> {
|
||||||
settingsLauncher.launch(Intent(this, SettingsActivity::class.java))
|
settingsLauncher.launch(Intent(this, SettingsActivity::class.java))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_sources -> {
|
R.id.action_sources -> {
|
||||||
startActivity(Intent(this, SourcesActivity::class.java))
|
startActivity(Intent(this, SourcesActivity::class.java))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> return super.onOptionsItemSelected(item)
|
else -> return super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -678,14 +711,21 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
.build()
|
.build()
|
||||||
|
|
||||||
val backgroundWork =
|
val backgroundWork =
|
||||||
PeriodicWorkRequestBuilder<LoadingWorker>(appSettingsService.getRefreshMinutes(), TimeUnit.MINUTES)
|
PeriodicWorkRequestBuilder<LoadingWorker>(
|
||||||
|
appSettingsService.getRefreshMinutes(),
|
||||||
|
TimeUnit.MINUTES
|
||||||
|
)
|
||||||
.setConstraints(myConstraints)
|
.setConstraints(myConstraints)
|
||||||
.addTag("selfoss-loading")
|
.addTag("selfoss-loading")
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
WorkManager.getInstance(
|
WorkManager.getInstance(
|
||||||
baseContext,
|
baseContext,
|
||||||
).enqueueUniquePeriodicWork("selfoss-loading", ExistingPeriodicWorkPolicy.KEEP, backgroundWork)
|
).enqueueUniquePeriodicWork(
|
||||||
|
"selfoss-loading",
|
||||||
|
ExistingPeriodicWorkPolicy.KEEP,
|
||||||
|
backgroundWork
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -17,6 +17,7 @@ import androidx.appcompat.app.AlertDialog
|
|||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityLoginBinding
|
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityLoginBinding
|
||||||
|
import bou.amine.apps.readerforselfossv2.android.testing.CountingIdlingResourceSingleton
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlInvalid
|
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlInvalid
|
||||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||||
@ -102,9 +103,14 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun goToMain() {
|
private fun goToMain() {
|
||||||
|
CountingIdlingResourceSingleton.increment()
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
repository.updateApiInformation()
|
repository.updateApiInformation()
|
||||||
ACRA.errorReporter.putCustomData("SELFOSS_API_VERSION", appSettingsService.getApiVersion().toString())
|
ACRA.errorReporter.putCustomData(
|
||||||
|
"SELFOSS_API_VERSION",
|
||||||
|
appSettingsService.getApiVersion().toString()
|
||||||
|
)
|
||||||
|
CountingIdlingResourceSingleton.decrement()
|
||||||
}
|
}
|
||||||
val intent = Intent(this, HomeActivity::class.java)
|
val intent = Intent(this, HomeActivity::class.java)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
@ -139,6 +145,7 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
|||||||
|
|
||||||
repository.refreshLoginInformation(url, login, password)
|
repository.refreshLoginInformation(url, login, password)
|
||||||
|
|
||||||
|
CountingIdlingResourceSingleton.increment()
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
try {
|
try {
|
||||||
repository.updateApiInformation()
|
repository.updateApiInformation()
|
||||||
@ -165,6 +172,7 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
|||||||
preferenceError()
|
preferenceError()
|
||||||
}
|
}
|
||||||
showProgress(false)
|
showProgress(false)
|
||||||
|
CountingIdlingResourceSingleton.decrement()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,20 +269,25 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
|||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
return when (item.itemId) {
|
return when (item.itemId) {
|
||||||
R.id.issue_tracker -> {
|
R.id.issue_tracker -> {
|
||||||
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(AppSettingsService.trackerUrl))
|
val browserIntent =
|
||||||
|
Intent(Intent.ACTION_VIEW, Uri.parse(AppSettingsService.trackerUrl))
|
||||||
startActivity(browserIntent)
|
startActivity(browserIntent)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.about -> {
|
R.id.about -> {
|
||||||
LibsBuilder()
|
LibsBuilder()
|
||||||
.withAboutIconShown(true)
|
.withAboutIconShown(true)
|
||||||
.withAboutVersionShown(true)
|
.withAboutVersionShown(true)
|
||||||
.withAboutSpecial2("Bug reports").withAboutSpecial2Description(AppSettingsService.trackerUrl)
|
.withAboutSpecial2("Bug reports")
|
||||||
.withAboutSpecial1("Project Page").withAboutSpecial1Description(AppSettingsService.sourceUrl)
|
.withAboutSpecial2Description(AppSettingsService.trackerUrl)
|
||||||
|
.withAboutSpecial1("Project Page")
|
||||||
|
.withAboutSpecial1Description(AppSettingsService.sourceUrl)
|
||||||
.start(this)
|
.start(this)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> super.onOptionsItemSelected(item)
|
else -> super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package bou.amine.apps.readerforselfossv2.android.testing
|
||||||
|
|
||||||
|
import androidx.test.espresso.idling.CountingIdlingResource
|
||||||
|
|
||||||
|
object CountingIdlingResourceSingleton {
|
||||||
|
|
||||||
|
private const val RESOURCE = "GLOBAL"
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val countingIdlingResource = CountingIdlingResource(RESOURCE)
|
||||||
|
|
||||||
|
fun increment() {
|
||||||
|
countingIdlingResource.increment()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun decrement() {
|
||||||
|
if (!countingIdlingResource.isIdleNow) {
|
||||||
|
countingIdlingResource.decrement()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,66 +0,0 @@
|
|||||||
package bou.amine.apps.readerforselfossv2.repository
|
|
||||||
|
|
||||||
import bou.amine.apps.readerforselfossv2.utils.DateUtils
|
|
||||||
import junit.framework.TestCase.assertEquals
|
|
||||||
import kotlinx.datetime.LocalDateTime
|
|
||||||
import kotlinx.datetime.TimeZone
|
|
||||||
import kotlinx.datetime.toInstant
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
class DatesTest {
|
|
||||||
private val newVersionDateVariant = "2022-12-24T17:00:08+00"
|
|
||||||
private val newVersionDate = "2013-04-07T13:43:00+01:00"
|
|
||||||
private val newVersionDate2 = "2013-04-07T13:43:00-01:00"
|
|
||||||
private val oldVersionDate = "2013-05-07 13:46:00"
|
|
||||||
private val oldVersionDateVariant = "2021-03-21 10:32:00.000000"
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun new_version_date_should_be_parsed() {
|
|
||||||
val date = DateUtils.parseDate(newVersionDate)
|
|
||||||
val expected =
|
|
||||||
LocalDateTime(2013, 4, 7, 13, 43, 0, 0).toInstant(TimeZone.currentSystemDefault())
|
|
||||||
.toEpochMilliseconds()
|
|
||||||
|
|
||||||
assertEquals(expected, date)
|
|
||||||
}
|
|
||||||
@Test
|
|
||||||
fun new_version_date2_should_be_parsed() {
|
|
||||||
val date = DateUtils.parseDate(newVersionDate2)
|
|
||||||
val expected =
|
|
||||||
LocalDateTime(2013, 4, 7, 13, 43, 0, 0).toInstant(TimeZone.currentSystemDefault())
|
|
||||||
.toEpochMilliseconds()
|
|
||||||
|
|
||||||
assertEquals(expected, date)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun old_version_date_should_be_parsed() {
|
|
||||||
val date = DateUtils.parseDate(oldVersionDate)
|
|
||||||
val expected =
|
|
||||||
LocalDateTime(2013, 5, 7, 13, 46, 0, 0).toInstant(TimeZone.currentSystemDefault())
|
|
||||||
.toEpochMilliseconds()
|
|
||||||
|
|
||||||
assertEquals(expected, date)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun old_version_variant_date_should_be_parsed() {
|
|
||||||
val date = DateUtils.parseDate(oldVersionDateVariant)
|
|
||||||
val expected =
|
|
||||||
LocalDateTime(2021, 3, 21, 10, 32, 0, 0).toInstant(TimeZone.currentSystemDefault())
|
|
||||||
.toEpochMilliseconds()
|
|
||||||
|
|
||||||
assertEquals(expected, date)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun new_version_variant_date_should_be_parsed() {
|
|
||||||
val date = DateUtils.parseDate(newVersionDateVariant)
|
|
||||||
val expected =
|
|
||||||
LocalDateTime(2022, 12, 24, 17, 0, 8, 0).toInstant(TimeZone.currentSystemDefault())
|
|
||||||
.toEpochMilliseconds()
|
|
||||||
|
|
||||||
assertEquals(expected, date)
|
|
||||||
}
|
|
||||||
}
|
|
@ -18,6 +18,7 @@ kotlin.code.style=official
|
|||||||
#Android
|
#Android
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
#android.nonTransitiveRClass=true
|
#android.nonTransitiveRClass=true
|
||||||
|
android.enableJetifier=true
|
||||||
android.nonTransitiveRClass=false
|
android.nonTransitiveRClass=false
|
||||||
#MPP
|
#MPP
|
||||||
kotlin.mpp.enableCInteropCommonization=true
|
kotlin.mpp.enableCInteropCommonization=true
|
||||||
@ -25,3 +26,4 @@ org.gradle.parallel=true
|
|||||||
org.gradle.caching=true
|
org.gradle.caching=true
|
||||||
ignoreGitVersion=false
|
ignoreGitVersion=false
|
||||||
kotlin.native.cacheKind.iosX64=none
|
kotlin.native.cacheKind.iosX64=none
|
||||||
|
org.gradle.configureondemand=true
|
Loading…
Reference in New Issue
Block a user