├── .editorconfig ├── .gitattributes ├── .github ├── CODEOWNERS ├── release-drafter.yml └── workflows │ ├── ci.yml │ ├── publish-snapshot.yml │ ├── rebase.yml │ ├── release-drafter.yml │ └── website.yml ├── .gitignore ├── .idea ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── copyright │ ├── Apache.xml │ └── profiles_settings.xml ├── detekt.xml ├── inspectionProfiles │ └── Project_Default.xml ├── ktlint.xml ├── scopes │ └── Markdown.xml └── vcs.xml ├── .kodiak.toml ├── CHANGELOG.md ├── LICENSE.txt ├── README.md ├── _config.yml ├── api └── Dispatch.api ├── build.gradle.kts ├── buildSrc ├── build.gradle.kts ├── settings.gradle.kts └── src │ └── main │ └── kotlin │ ├── Common.kt │ ├── CommonAndroid.kt │ ├── androidLibrary.gradle.kts │ ├── catalogs.kt │ ├── dependency-guard.gradle.kts │ ├── detekt.gradle.kts │ ├── dokka.gradle.kts │ ├── javaLibrary.gradle.kts │ ├── knit.gradle.kts │ ├── published.gradle.kts │ └── website.gradle.kts ├── detekt ├── detekt-config.yml └── license.template ├── dispatch-android-espresso ├── README.md ├── api │ └── dispatch-android-espresso.api ├── build.gradle.kts ├── dependencies │ └── releaseRuntimeClasspath.txt ├── gradle.properties └── src │ ├── main │ └── java │ │ └── dispatch │ │ └── android │ │ └── espresso │ │ ├── IdlingCoroutineScope.kt │ │ ├── IdlingDispatcher.kt │ │ ├── IdlingDispatcherProvider.kt │ │ └── IdlingDispatcherProviderRule.kt │ └── test │ └── java │ └── dispatch │ └── android │ └── espresso │ ├── IdlingDispatcherProviderRuleTest.kt │ └── samples │ ├── DefaultIdlingCoroutineScope.kt │ ├── IOIdlingCoroutineScope.kt │ ├── IdlingCoroutineScope.kt │ ├── IdlingCoroutineScopeRuleSample.kt │ ├── IdlingCoroutineScopeRuleWithLifecycleSample.kt │ ├── MainIdlingCoroutineScope.kt │ ├── MainImmediateIdlingCoroutineScope.kt │ └── UnconfinedIdlingCoroutineScope.kt ├── dispatch-android-lifecycle-extensions ├── README.md ├── api │ └── dispatch-android-lifecycle-extensions.api ├── build.gradle.kts ├── dependencies │ └── releaseRuntimeClasspath.txt ├── gradle.properties └── src │ ├── main │ └── java │ │ └── dispatch │ │ └── android │ │ └── lifecycle │ │ ├── LifecycleScopeFactory.kt │ │ ├── internal │ │ ├── DispatchLifecycleScopeStore.kt │ │ └── atomic.kt │ │ ├── lifecycleOwner.kt │ │ └── withViewLifecycleScope.kt │ └── test │ └── java │ └── dispatch │ └── android │ └── lifecycle │ ├── LifecycleScopeExtensionTest.kt │ ├── LifecycleScopeFactoryTest.kt │ ├── ViewLifecycleScopeFlowCollectionTest.kt │ ├── WithViewLifecycleScopeExtensionTest.kt │ ├── internal │ └── AtomicGetOrPutTest.kt │ └── samples │ ├── Fragment.kt │ ├── LifecycleScopeExtensionSamples.kt │ ├── LifecycleScopeFactorySample.kt │ └── WithViewLifecycleScopeExtensionSample.kt ├── dispatch-android-lifecycle ├── README.md ├── api │ └── dispatch-android-lifecycle.api ├── build.gradle.kts ├── dependencies │ └── releaseRuntimeClasspath.txt ├── gradle.properties └── src │ ├── main │ └── java │ │ └── dispatch │ │ └── android │ │ └── lifecycle │ │ ├── DispatchLifecycleScope.kt │ │ ├── DispatchLifecycleScopeFactory.kt │ │ ├── ViewLifecycleCoroutineScope.kt │ │ ├── internal │ │ ├── DispatchLifecycleScopeBinding.kt │ │ ├── dispatchLifecycleScope.kt │ │ └── viewLifecycleCoroutineScope.kt │ │ └── suspend.kt │ └── test │ └── java │ └── dispatch │ └── android │ └── lifecycle │ ├── DispatchLifecycleScopeTest.kt │ ├── OnNextCreateTest.kt │ ├── OnNextResumeTest.kt │ ├── OnNextStartTest.kt │ ├── ViewLifecycleScopeFlowCollectionTest.kt │ ├── WithViewLifecycleTest.kt │ └── samples │ ├── DispatchLifecycleCoroutineScopeFactorySample.kt │ ├── DispatchLifecycleScope.kt │ ├── Fragment.kt │ ├── LifecycleSuspend.kt │ └── WithLifecycleScopeSample.kt ├── dispatch-android-viewmodel ├── README.md ├── api │ └── dispatch-android-viewmodel.api ├── build.gradle.kts ├── dependencies │ └── releaseRuntimeClasspath.txt ├── gradle.properties └── src │ ├── main │ └── java │ │ └── dispatch │ │ └── android │ │ └── viewmodel │ │ ├── DispatchViewModel.kt │ │ └── ViewModelScopeFactory.kt │ └── test │ └── java │ └── dispatch │ └── android │ └── viewmodel │ ├── DispatchViewModelTest.kt │ ├── ViewModelScopeFactoryTest.kt │ └── samples │ ├── Application.kt │ ├── ViewModelScopeFactorySample.kt │ └── ViewModelScopeSample.kt ├── dispatch-bom ├── build.gradle.kts └── gradle.properties ├── dispatch-core ├── README.md ├── api │ └── dispatch-core.api ├── build.gradle.kts ├── dependencies │ └── runtimeClasspath.txt ├── gradle.properties └── src │ ├── main │ └── java │ │ └── dispatch │ │ └── core │ │ ├── Async.kt │ │ ├── CoroutineScopeExt.kt │ │ ├── CoroutineScopes.kt │ │ ├── DefaultDispatcherProvider.kt │ │ ├── DispatcherProvider.kt │ │ ├── Flow.kt │ │ ├── Launch.kt │ │ └── Suspend.kt │ └── test │ └── java │ └── dispatch │ └── core │ ├── AsyncBuildersTest.kt │ ├── CoroutineScopeExtKtTest.kt │ ├── CoroutineScopesTest.kt │ ├── DispatcherProviderTest.kt │ ├── FlowTest.kt │ ├── LaunchBuildersTest.kt │ ├── SuspendBuildersTest.kt │ └── samples │ ├── AsyncSample.kt │ ├── DefaultDispatcherProviderSample.kt │ ├── DispatcherProviderCopySample.kt │ ├── FlowOnSample.kt │ ├── LaunchSample.kt │ └── WithContextSample.kt ├── dispatch-detekt ├── README.md ├── api │ └── dispatch-detekt.api ├── build.gradle.kts ├── dependencies │ └── runtimeClasspath.txt ├── gradle.properties └── src │ ├── main │ ├── java │ │ └── dispatch │ │ │ └── detekt │ │ │ ├── DispatchConfigValidator.kt │ │ │ ├── DispatchRuleSetProvider.kt │ │ │ └── rules │ │ │ ├── AndroidXLifecycleScope.kt │ │ │ └── HardCodedDispatcher.kt │ └── resources │ │ └── META-INF │ │ └── services │ │ ├── io.gitlab.arturbosch.detekt.api.ConfigValidator │ │ └── io.gitlab.arturbosch.detekt.api.RuleSetProvider │ └── test │ └── java │ └── dispatch │ └── detekt │ └── rules │ ├── AndroidxLifecycleScopeUsageTest.kt │ ├── HardCodedDispatcherUsageTest.kt │ └── util.kt ├── dispatch-internal-test-android ├── api │ └── dispatch-internal-test-android.api ├── build.gradle.kts └── src │ └── main │ └── java │ └── dispatch │ └── internal │ └── test │ └── android │ ├── FakeFragment.java │ ├── FakeLifecycle.kt │ ├── FakeLifecycleOwner.kt │ └── InstantTaskExecutorExtension.kt ├── dispatch-internal-test ├── build.gradle.kts └── src │ ├── main │ └── java │ │ └── dispatch │ │ └── internal │ │ └── test │ │ ├── AtomicCounterExtension.kt │ │ ├── BaseTest.kt │ │ ├── ExpectedFailureRule.kt │ │ ├── Fails.kt │ │ ├── assertions.kt │ │ ├── reflect.kt │ │ └── samples.kt │ └── test │ └── java │ └── dispatch │ └── internal │ └── test │ └── AssertionsTest.kt ├── dispatch-sample ├── build.gradle.kts └── src │ └── main │ ├── AndroidManifest.xml │ ├── ic_launcher-web.png │ ├── java │ └── dispatch │ │ └── sample │ │ ├── MainActivity.kt │ │ ├── MainFragment.kt │ │ ├── MainViewModel.kt │ │ └── SomeRepository.kt │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ └── ic_launcher_background.xml │ ├── layout │ ├── activity_main.xml │ └── fragment_main.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── ic_launcher_background.xml │ ├── strings.xml │ └── styles.xml ├── dispatch-test-junit4 ├── README.md ├── api │ └── dispatch-test-junit4.api ├── build.gradle.kts ├── dependencies │ └── runtimeClasspath.txt ├── gradle.properties └── src │ ├── main │ └── java │ │ └── dispatch │ │ └── test │ │ └── TestCoroutineRule.kt │ └── test │ └── kotlin │ └── dispatch │ └── core │ └── test │ ├── TestCoroutineRuleTest.kt │ └── samples │ ├── TestCoroutineRuleSample.kt │ └── TestCoroutineRuleWithFactorySample.kt ├── dispatch-test-junit5 ├── README.md ├── api │ └── dispatch-test-junit5.api ├── build.gradle.kts ├── dependencies │ └── runtimeClasspath.txt ├── gradle.properties └── src │ ├── main │ └── java │ │ └── dispatch │ │ └── test │ │ ├── CoroutineTest.kt │ │ ├── CoroutineTestExtension.kt │ │ └── internal │ │ ├── ResetManager.kt │ │ ├── reflect.kt │ │ └── resolutionException.kt │ └── test │ └── kotlin │ └── dispatch │ └── test │ ├── CoroutineTestCustomFactoryTest.kt │ ├── CoroutineTestDefaultFactoryTest.kt │ ├── CoroutineTestExtensionInjectionTest.kt │ ├── CoroutineTestExtensionRegisteredTest.kt │ ├── SetMainTest.kt │ └── samples │ ├── CoroutineTestDefaultFactorySample.kt │ ├── CoroutineTestExtensionExtendWithSample.kt │ ├── CoroutineTestNamedFactorySample.kt │ ├── RegisterSample.kt │ ├── RegisterWithFactorySample.kt │ └── utils.kt ├── dispatch-test ├── .gitignore ├── README.md ├── api │ └── dispatch-test.api ├── build.gradle.kts ├── dependencies │ └── runtimeClasspath.txt ├── gradle.properties └── src │ ├── main │ └── java │ │ └── dispatch │ │ └── test │ │ ├── TestDispatcherProvider.kt │ │ ├── TestProvidedCoroutineScope.kt │ │ ├── builders.kt │ │ └── defaultDispatcherProvider.kt │ └── test │ └── kotlin │ └── dispatch │ └── test │ ├── BuildersTest.kt │ ├── TestDispatcherProviderTest.kt │ ├── TestProvidedCoroutineScopeTest.kt │ └── samples │ ├── BuildersSample.kt │ ├── DefaultDispatcherProviderExtensionSample.kt │ └── SomeClass.kt ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── knit.properties ├── release.sh ├── renovate.json ├── settings.gradle.kts └── website ├── .gitignore ├── README.md ├── babel.config.js ├── docs ├── intro.mdx ├── modules │ ├── dispatch-android-espresso.md │ ├── dispatch-android-lifecycle-extensions.md │ ├── dispatch-android-lifecycle.md │ ├── dispatch-android-viewmodel.md │ ├── dispatch-core.md │ ├── dispatch-detekt.md │ ├── dispatch-test-junit4.md │ ├── dispatch-test-junit5.md │ └── dispatch-test.md └── quickstart.mdx ├── docusaurus.config.js ├── package.json ├── sidebars.js ├── src ├── css │ └── custom.css └── pages │ ├── CHANGELOG.md │ ├── index.js │ └── styles.module.css ├── static ├── .nojekyll └── img │ ├── coffee-solid.svg │ ├── power-off-solid.svg │ ├── syringe-solid.svg │ ├── undraw_docusaurus_mountain.svg │ ├── undraw_docusaurus_react.svg │ └── undraw_docusaurus_tree.svg ├── versioned_docs └── version-1.0.0-beta10 │ ├── intro.mdx │ ├── modules │ ├── dispatch-android-espresso.md │ ├── dispatch-android-lifecycle-extensions.md │ ├── dispatch-android-lifecycle.md │ ├── dispatch-android-viewmodel.md │ ├── dispatch-core.md │ ├── dispatch-detekt.md │ ├── dispatch-test-junit4.md │ ├── dispatch-test-junit5.md │ └── dispatch-test.md │ └── quickstart.mdx ├── versioned_sidebars └── version-1.0.0-beta10-sidebars.json ├── versions.json └── yarn.lock /.gitattributes: -------------------------------------------------------------------------------- 1 | *.html linguist-detectable=false 2 | *.css linguist-detectable=false 3 | *.js linguist-detectable=false 4 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # This is a comment. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # These owners will be the default owners for everything in 5 | # the repo. Unless a later match takes precedence, 6 | # @owner1 and @owner2 will be requested for 7 | # review when someone opens a pull request. 8 | 9 | * @rbusarow 10 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name-template: '$RESOLVED_VERSION' 2 | tag-template: '$RESOLVED_VERSION' 3 | 4 | categories: 5 | - title: '🚀 Features' 6 | labels: 7 | - 'feature' 8 | - 'enhancement' 9 | - title: '💥 Breaking Changes' 10 | labels: 11 | - 'api-breaking change' 12 | - title: '🐛 Bug Fixes' 13 | labels: 14 | - 'fix' 15 | - 'bugfix' 16 | - 'bug' 17 | - title: '🧰 Maintenance' 18 | labels: 19 | - 'chore' 20 | - 'dependencies' 21 | - title: 'ℹ️ Website' 22 | labels: 23 | - 'documentation' 24 | 25 | #change-template: '- $TITLE [@$AUTHOR](https://github.com/$AUTHOR) ([#$NUMBER](https://github.com/rbusarow/Dispatch/pull/$NUMBER))' 26 | change-template: '- $TITLE ([#$NUMBER](https://github.com/rbusarow/Dispatch/pull/$NUMBER))' 27 | 28 | change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks. 29 | 30 | version-resolver: 31 | major: 32 | labels: 33 | - 'major' 34 | minor: 35 | labels: 36 | - 'minor' 37 | - 'feature' 38 | - 'enhancement' 39 | patch: 40 | labels: 41 | - 'patch' 42 | - 'fix' 43 | - 'bugfix' 44 | - 'bug' 45 | default: patch 46 | 47 | template: | 48 | ## Changes 49 | 50 | $CHANGES 51 | 52 | exclude-contributors: 53 | - 'dependabot' 54 | - 'dependabot[bot]' 55 | - 'renovate' 56 | - 'renovate[bot]' 57 | - 'renovate-bot' 58 | - 'kodiakhq' 59 | - 'kodiakhq[bot]' 60 | 61 | autolabeler: 62 | - label: 'documentation' 63 | files: 64 | - '*.md' 65 | - label: 'dependencies' 66 | branch: 67 | - '/dependabot\/.+/' 68 | - '/renovate\/.+/' 69 | 70 | include-labels: 71 | - 'api-breaking change' 72 | - 'bug' 73 | - 'bugfix' 74 | - 'chore' 75 | - 'dependencies' 76 | - 'documentation' 77 | - 'enhancement' 78 | - 'feature' 79 | - 'fix' 80 | - 'major' 81 | - 'minor' 82 | - 'patch' 83 | -------------------------------------------------------------------------------- /.github/workflows/publish-snapshot.yml: -------------------------------------------------------------------------------- 1 | name: Publish snapshot 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - main 8 | 9 | env: 10 | gradleArgs: '-Dorg.gradle.jvmargs=-Xmx10g -Dfile.encoding=UTF-8 -XX:+UseParallelGC' 11 | 12 | jobs: 13 | publish-snapshot: 14 | runs-on: macos-latest 15 | if: github.repository == 'RBusarow/Dispatch' 16 | timeout-minutes: 30 17 | 18 | steps: 19 | - uses: actions/checkout@v3 20 | - uses: actions/setup-java@v3 21 | with: 22 | distribution: 'zulu' 23 | java-version: '11' 24 | 25 | # break the publishing builds down a little into smaller steps 26 | # because gradle-build-action's caching is all-or-nothing. If the full publish task 27 | # takes too long and times out, no cache is retained. 28 | 29 | - name: Compile Kotlin 30 | uses: gradle/gradle-build-action@v2 31 | with: 32 | arguments: compileKotlin "${{ env.gradleArgs }}" 33 | 34 | - name: Dokka & JavadocJar 35 | uses: gradle/gradle-build-action@v2 36 | with: 37 | arguments: dokkaJavadocJar "${{ env.gradleArgs }}" 38 | 39 | - name: Publish Snapshots 40 | uses: gradle/gradle-build-action@v2 41 | with: 42 | arguments: publish --no-parallel "${{ env.gradleArgs }}" 43 | env: 44 | ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_NEXUS_USERNAME }} 45 | ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_NEXUS_PASSWORD }} 46 | -------------------------------------------------------------------------------- /.github/workflows/rebase.yml: -------------------------------------------------------------------------------- 1 | on: 2 | issue_comment: 3 | types: [created] 4 | name: Automatic Rebase 5 | jobs: 6 | rebase: 7 | name: Rebase 8 | if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase') 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@master 12 | with: 13 | fetch-depth: 0 14 | - name: Automatic Rebase 15 | uses: cirrus-actions/rebase@1.7 16 | env: 17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 18 | # https://github.community/t5/GitHub-Actions/Workflow-is-failing-if-no-job-can-be-ran-due-to-condition/m-p/38186#M3250 19 | always_job: 20 | name: Always run job 21 | runs-on: ubuntu-latest 22 | steps: 23 | - name: Always run 24 | run: echo "This job is used to prevent the workflow to fail when all other jobs are skipped." 25 | -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name: Release Drafter 2 | 3 | on: 4 | push: 5 | # branches to consider in the event; optional, defaults to all 6 | branches: 7 | - main 8 | # pull_request event is required only for autolabeler 9 | pull_request: 10 | # Only following types are handled by the action, but one can default to all as well 11 | types: [opened, reopened, synchronize] 12 | 13 | jobs: 14 | update_release_draft: 15 | runs-on: ubuntu-latest 16 | steps: 17 | # (Optional) GitHub Enterprise requires GHE_HOST variable set 18 | #- name: Set GHE_HOST 19 | # run: | 20 | # echo "GHE_HOST=${GITHUB_SERVER_URL##https:\/\/}" >> $GITHUB_ENV 21 | 22 | # Drafts your next Release notes as Pull Requests are merged into "master" 23 | - uses: release-drafter/release-drafter@v5 24 | # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml 25 | # with: 26 | # config-name: my-config.yml 27 | # disable-autolabeler: true 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | -------------------------------------------------------------------------------- /.github/workflows/website.yml: -------------------------------------------------------------------------------- 1 | name: deploy-website 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | 7 | # Allows you to run this workflow manually from the Actions tab 8 | workflow_dispatch: 9 | 10 | env: 11 | gradleArgs: '-Dorg.gradle.jvmargs=-Xmx6g -Dfile.encoding=UTF-8 -XX:+UseParallelGC' 12 | 13 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 14 | jobs: 15 | publish: 16 | runs-on: ubuntu-latest 17 | steps: 18 | 19 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 20 | - name: Check out repo 21 | uses: actions/checkout@v3 22 | 23 | # Node is required for npm 24 | - name: Set up Node 25 | uses: actions/setup-node@v3 26 | with: 27 | node-version: 18.x 28 | cache: yarn 29 | cache-dependency-path: website/yarn.lock 30 | 31 | - name: Install Yarn 32 | working-directory: website 33 | run: yarn install --frozen-lockfile 34 | 35 | - name: Set up JDK 36 | uses: actions/setup-java@v3 37 | with: 38 | distribution: 'zulu' 39 | java-version: '11' 40 | 41 | - name: compileKotlin 42 | uses: gradle/gradle-build-action@v2 43 | with: 44 | arguments: compileKotlin "${{ env.gradleArgs }}" 45 | cache-read-only: false 46 | 47 | - name: dokkaHtmlMultiModule 48 | uses: gradle/gradle-build-action@v2 49 | with: 50 | arguments: dokkaHtmlMultiModule "${{ env.gradleArgs }}" 51 | cache-read-only: false 52 | 53 | - name: build website 54 | uses: gradle/gradle-build-action@v2 55 | with: 56 | arguments: buildSite "${{ env.gradleArgs }}" 57 | cache-read-only: false 58 | 59 | - name: Deploy to GitHub Pages 60 | if: success() 61 | uses: crazy-max/ghaction-github-pages@v3 62 | with: 63 | target_branch: gh-pages 64 | build_dir: website/build 65 | env: 66 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # generated files 12 | bin/ 13 | gen/ 14 | 15 | # Local configuration file (sdk path, etc) 16 | local.properties 17 | 18 | # Windows thumbnail db 19 | Thumbs.db 20 | 21 | # OSX files 22 | .DS_Store 23 | 24 | # Eclipse project files 25 | .classpath 26 | .project 27 | 28 | ## IDEA/Android Studio ignores 29 | *.iml 30 | *.ipr 31 | *.iws 32 | /.idea/* 33 | /.gradle/* 34 | 35 | # IDEA/Android Studio Ignore exceptions 36 | !/.idea/vcs.xml 37 | !/.idea/fileTemplates/ 38 | !/.idea/inspectionProfiles/ 39 | !/.idea/scopes/ 40 | !/.idea/codeStyleSettings.xml 41 | !/.idea/encodings.xml 42 | !/.idea/copyright/ 43 | !/.idea/compiler.xml 44 | # required plugins 45 | !/.idea/externalDependencies.xml 46 | # ktlint plugin settings 47 | !/.idea/ktlint.xml 48 | # detekt plugin settings 49 | !/.idea/detekt.xml 50 | !/.idea/icon.png 51 | !/.idea/runConfigurations/all_tests.xml 52 | 53 | /.idea/vcs.xml 54 | **/.idea/workspace.xml 55 | 56 | #NDK 57 | obj/ 58 | **/.gradle/ 59 | 60 | captures/ 61 | /.idea/copyright/profiles_settings.xml 62 | /.idea/compiler.xml 63 | !/.idea/codeStyles/ 64 | !/gradle/wrapper/gradle-wrapper.properties 65 | true/ 66 | 67 | # all build dirs at any level 68 | **/build 69 | /gradle/profiler/gradle-user-home/ 70 | !/gradle/profiler/bin/ 71 | 72 | checksum.txt 73 | 74 | # copy of API docs for website. Save the /styles dir before the CSS is slightly customized 75 | /website/static/api 76 | !/website/static/api/styles 77 | 78 | local.settings.gradle.kts 79 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/copyright/Apache.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/detekt.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | detekt/detekt-config.yml 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | -------------------------------------------------------------------------------- /.idea/ktlint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | true 5 | true 6 | false 7 | 8 | 9 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/scopes/Markdown.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.kodiak.toml: -------------------------------------------------------------------------------- 1 | # Configuration for Kodiak's auto-merge tool 2 | # see full options: https://kodiakhq.com/docs/config-reference 3 | 4 | version = 1 # this is required but 1 is currently the only option 5 | 6 | [update] 7 | always = false # default: false 8 | require_automerge_label = true # default: true 9 | automerge_label = "automerge" # default: automerge 10 | # if using `update.always`, add dependabot to `update.ignore_usernames` to allow 11 | # dependabot to update and close stale dependency upgrades. 12 | # ignored_usernames = ["dependabot"] 13 | 14 | [merge] 15 | # if a PR is ready, merge it, don't place it in the merge queue. 16 | prioritize_ready_to_merge = true # default: false 17 | # will not do anything if a matching label is applied 18 | blocking_labels = ["DO NOT MERGE"] 19 | method = "squash" 20 | 21 | [merge.automerge_dependencies] 22 | # auto merge all PRs opened by "dependabot" that are "minor" or "patch" version upgrades. "major" version upgrades will be ignored. 23 | #versions = ["minor", "patch"] 24 | #usernames = ["dependabot"] 25 | 26 | [approve] 27 | # note: remove the "[bot]" suffix from GitHub Bot usernames. 28 | # Instead of "dependabot[bot]" use "dependabot". 29 | 30 | # auto_approve_usernames = ["dependabot"] 31 | auto_approve_usernames = ["RBusarow"] 32 | 33 | [merge.message] 34 | # use title of PR for merge commit. 35 | title = "pull_request_title" # default: "github_default" 36 | 37 | # use body of PR for merge commit. 38 | body = "pull_request_body" # default: "github_default" 39 | 40 | # add the PR number to the merge commit title, like GitHub. 41 | include_pr_number = true # default: true 42 | 43 | # use the default markdown content of the PR for the merge commit. 44 | body_type = "markdown" # default: "markdown" 45 | 46 | # remove html comments to auto remove PR templates. 47 | strip_html_comments = true # default: false 48 | 49 | include_pull_request_url = true # default: false 50 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-tactile -------------------------------------------------------------------------------- /api/Dispatch.api: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RBusarow/Dispatch/4b231ef18802c064375eee7a58326f8283794dcd/api/Dispatch.api -------------------------------------------------------------------------------- /buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | plugins { 17 | `kotlin-dsl` 18 | } 19 | 20 | repositories { 21 | mavenCentral() 22 | google() 23 | maven("https://plugins.gradle.org/m2/") 24 | } 25 | 26 | val kotlinVersion = libs.versions.kotlin.get() 27 | 28 | dependencies { 29 | 30 | compileOnly(gradleApi()) 31 | 32 | implementation(kotlin("gradle-plugin", version = kotlinVersion)) 33 | implementation(kotlin("reflect", version = kotlinVersion)) 34 | implementation(libs.android.gradle) 35 | implementation(libs.detekt.gradle) 36 | implementation(libs.dokka.gradle) 37 | implementation(libs.dropbox.dependencyGuard) 38 | implementation(libs.kotlin.annotation.processing) 39 | implementation(libs.kotlin.compiler) 40 | implementation(libs.kotlin.gradle.pluginApi) 41 | implementation(libs.kotlin.reflect) 42 | implementation(libs.kotlin.stdlib.jdk8) 43 | implementation(libs.kotlinx.atomicfu) 44 | implementation(libs.kotlinx.knit.gradle) 45 | implementation(libs.kotlinx.metadata.jvm) 46 | implementation(libs.ktlint.gradle) 47 | implementation(libs.vanniktech.publish) 48 | } 49 | -------------------------------------------------------------------------------- /buildSrc/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | pluginManagement { 17 | repositories { 18 | gradlePluginPortal() 19 | mavenCentral() 20 | google() 21 | } 22 | } 23 | 24 | dependencyResolutionManagement { 25 | @Suppress("UnstableApiUsage") 26 | repositories { 27 | google() 28 | mavenCentral() 29 | } 30 | } 31 | 32 | enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") 33 | 34 | @Suppress("UnstableApiUsage") 35 | dependencyResolutionManagement { 36 | versionCatalogs { 37 | create("libs") { 38 | from(files("../gradle/libs.versions.toml")) 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/Common.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | import org.gradle.api.Project 17 | import org.gradle.api.tasks.testing.Test 18 | import org.gradle.kotlin.dsl.systemProperties 19 | import org.gradle.kotlin.dsl.withType 20 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 21 | 22 | fun Project.common() { 23 | 24 | tasks.withType { 25 | 26 | useJUnitPlatform { 27 | includeEngines("junit-vintage", "junit-jupiter") 28 | } 29 | 30 | systemProperties( 31 | // auto-discover and apply any Junit5 extensions in the classpath 32 | // "junit.jupiter.extensions.autodetection.enabled" to true, 33 | 34 | // remove parentheses from test display names 35 | "junit.jupiter.displayname.generator.default" to "org.junit.jupiter.api.DisplayNameGenerator\$Simple", 36 | 37 | // single class instance for all tests 38 | "junit.jupiter.testinstance.lifecycle.default" to "per_class", 39 | 40 | // https://junit.org/junit5/docs/snapshot/user-guide/#writing-tests-parallel-execution-config-properties 41 | // run all tests concurrently 42 | // this might wind up creating flakes thanks to Dispatchers.setMain 43 | "junit.jupiter.execution.parallel.enabled" to true, 44 | "junit.jupiter.execution.parallel.mode.default" to "concurrent", 45 | "junit.jupiter.execution.parallel.mode.classes.default" to "concurrent", 46 | 47 | "junit.jupiter.execution.parallel.config.strategy" to "dynamic", 48 | "junit.jupiter.execution.parallel.config.dynamic.factor" to 1.0 49 | ) 50 | 51 | // Allow Junit 4 tests to run in parallel 52 | maxParallelForks = Runtime.getRuntime().availableProcessors() 53 | } 54 | 55 | tasks.withType() 56 | .configureEach { 57 | 58 | kotlinOptions { 59 | 60 | allWarningsAsErrors = true 61 | 62 | jvmTarget = "1.8" 63 | 64 | freeCompilerArgs = freeCompilerArgs + listOf( 65 | "-opt-in=kotlin.RequiresOptIn" 66 | ) 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/androidLibrary.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | plugins { 17 | id("com.android.library") 18 | kotlin("android") 19 | id("detekt") 20 | id("dokka") 21 | } 22 | 23 | android { 24 | 25 | commonAndroid(project) 26 | common() 27 | 28 | // don't generate BuildConfig 29 | @Suppress("UnstableApiUsage") 30 | buildFeatures.buildConfig = false 31 | } 32 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/catalogs.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | import org.gradle.api.Project 17 | import org.gradle.api.artifacts.MinimalExternalModuleDependency 18 | import org.gradle.api.artifacts.VersionCatalog 19 | import org.gradle.api.artifacts.VersionCatalogsExtension 20 | import org.gradle.api.artifacts.VersionConstraint 21 | import org.gradle.api.provider.Provider 22 | import org.gradle.kotlin.dsl.getByType 23 | 24 | val Project.catalogs: VersionCatalogsExtension 25 | get() = extensions.getByType(VersionCatalogsExtension::class) 26 | 27 | val Project.libsCatalog: VersionCatalog 28 | get() = catalogs.named("libs") 29 | 30 | fun VersionCatalog.dependency(alias: String): Provider { 31 | return findLibrary(alias).get() 32 | } 33 | 34 | fun VersionCatalog.version(alias: String): VersionConstraint { 35 | return findVersion(alias).get() 36 | } 37 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/dependency-guard.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | pluginManager.withPlugin("org.jetbrains.kotlin.jvm") { 17 | 18 | apply(plugin = "com.dropbox.dependency-guard") 19 | 20 | // If we got here, we're either in an empty "parent" module without a build plugin 21 | // (and no configurations), or we're in a vanilla Kotlin module. In this case, we can just look 22 | // at configuration names. 23 | configurations 24 | .matching { 25 | it.name.endsWith("runtimeClasspath", ignoreCase = true) && 26 | !it.name.endsWith("testRuntimeClasspath", ignoreCase = true) 27 | } 28 | .all { configureClasspath(name) } 29 | } 30 | 31 | pluginManager.withPlugin("com.android.library") { 32 | 33 | apply(plugin = "com.dropbox.dependency-guard") 34 | 35 | // For Android modules, just hard-code `releaseRuntimeClasspath` for the release variant. 36 | // This is actually pretty robust, since if this configuration ever changes, dependency-guard 37 | // will fail when trying to look it up. 38 | extensions.configure { 39 | configureClasspath("releaseRuntimeClasspath") 40 | } 41 | } 42 | 43 | fun configureClasspath(classpathName: String) { 44 | configure { 45 | // Tell dependency-guard to check the `$classpathName` configuration's dependencies. 46 | configuration(classpathName) 47 | } 48 | } 49 | 50 | // Delete any existing dependency files/directories before recreating with a new baseline task. 51 | val dependencyGuardDeleteBaselines by tasks.registering(Delete::class) { 52 | delete("dependencies") 53 | } 54 | tasks.matching { it.name == "dependencyGuardBaseline" } 55 | .configureEach { dependsOn(dependencyGuardDeleteBaselines) } 56 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/detekt.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | import io.gitlab.arturbosch.detekt.Detekt 17 | import io.gitlab.arturbosch.detekt.report.ReportMergeTask 18 | import org.gradle.internal.impldep.org.junit.experimental.categories.Categories.CategoryFilter.exclude 19 | 20 | plugins { 21 | id("io.gitlab.arturbosch.detekt") 22 | } 23 | 24 | val reportMerge by tasks.registering(ReportMergeTask::class) { 25 | output.set(rootProject.buildDir.resolve("reports/detekt/merged.sarif")) 26 | } 27 | 28 | val detektExcludes = listOf( 29 | "**/resources/**", 30 | "**/buildSrc/**", 31 | "**/build/**" 32 | ) 33 | 34 | tasks.withType { 35 | 36 | parallel = true 37 | config.from(files("$rootDir/detekt/detekt-config.yml")) 38 | buildUponDefaultConfig = true 39 | 40 | // If in CI, merge sarif reports. Skip this locally because it's not worth looking at 41 | // and the task is unnecessarily chatty. 42 | if (!System.getenv("CI").isNullOrBlank()) { 43 | finalizedBy(reportMerge) 44 | reportMerge.configure { 45 | input.from(sarifReportFile) 46 | } 47 | } 48 | 49 | reports { 50 | xml.required.set(true) 51 | html.required.set(true) 52 | txt.required.set(false) 53 | sarif.required.set(true) 54 | } 55 | 56 | setSource(files(projectDir)) 57 | 58 | include("**/*.kt", "**/*.kts") 59 | exclude(detektExcludes) 60 | subprojects.forEach { sub -> 61 | exclude("**/${sub.projectDir.relativeTo(rootDir)}/**") 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/javaLibrary.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | import org.jetbrains.kotlin.gradle.dsl.* 17 | 18 | plugins { 19 | kotlin("jvm") 20 | id("com.android.lint") 21 | id("detekt") 22 | id("dokka") 23 | } 24 | 25 | common() 26 | 27 | kotlin { 28 | if (!path.endsWith("samples")) { 29 | explicitApi = ExplicitApiMode.Strict 30 | } 31 | } 32 | 33 | java { 34 | // force Java 8 source when building java-only artifacts. 35 | // This is different than the Kotlin jvm target. 36 | sourceCompatibility = JavaVersion.VERSION_1_8 37 | targetCompatibility = JavaVersion.VERSION_1_8 38 | } 39 | 40 | val testJvm by tasks.registering { 41 | dependsOn("test") 42 | } 43 | 44 | val buildTests by tasks.registering { 45 | dependsOn("testClasses") 46 | } 47 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/knit.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | apply(plugin = "kotlinx-knit") 17 | 18 | extensions.configure { 19 | 20 | rootDir = rootProject.rootDir 21 | 22 | files = fileTree(project.rootDir) { 23 | include( 24 | "**/*.md", 25 | "**/*.kt", 26 | "**/*.kts" 27 | ) 28 | exclude( 29 | "**/node_modules/**", 30 | "**/build/**", 31 | "**/sample/**", 32 | "**/.gradle/**" 33 | ) 34 | } 35 | 36 | moduleRoots = listOf(".") 37 | 38 | moduleDocs = "build/dokka" 39 | moduleMarkers = listOf("build.gradle", "build.gradle.kts") 40 | siteRoot = "https://rbusarow.github.io/Dispatch/api/" 41 | } 42 | 43 | // Build API docs for all modules with dokka before running Knit 44 | tasks.withType() 45 | .configureEach { 46 | dependsOn("dokkaHtmlMultiModule") 47 | } 48 | -------------------------------------------------------------------------------- /detekt/license.template: -------------------------------------------------------------------------------- 1 | \/\*\n \* Copyright \(C\) 20[0-9]{2}(-20[0-9]{2})?.*\n \* Licensed under the Apache License\, Version 2\.0 \(the \"License\"\)\;\n \* you may not use this file except in compliance with the License\.\n \* You may obtain a copy of the License at\n \*\n \* http\:\/\/www\.apache\.org\/licenses\/LICENSE\-2\.0\n \*\n \* Unless required by applicable law or agreed to in writing\, software\n \* distributed under the License is distributed on an \"AS IS\" BASIS\,\n \* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND\, either express or implied\.\n \* See the License for the specific language governing permissions and\n \* limitations under the License\.\n \*\/ 2 | -------------------------------------------------------------------------------- /dispatch-android-espresso/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | plugins { 17 | androidLibrary 18 | published 19 | } 20 | 21 | android { 22 | namespace = "dispatch.android.espresso" 23 | } 24 | 25 | dependencies { 26 | 27 | api(libs.androidx.test.espresso.idlingResource) 28 | api(libs.junit.junit4) 29 | api(libs.kotlinx.coroutines.core) 30 | api(libs.kotlinx.coroutines.jvm) 31 | 32 | api(projects.dispatchCore) 33 | 34 | implementation(libs.kotlinx.coroutines.android) 35 | 36 | testImplementation(libs.kotest.assertions) 37 | testImplementation(libs.kotest.runner) 38 | testImplementation(libs.mockk) 39 | testImplementation(libs.robolectric) 40 | 41 | testImplementation(projects.dispatchAndroidLifecycleExtensions) 42 | testImplementation(projects.dispatchAndroidViewmodel) 43 | testImplementation(projects.dispatchInternalTest) 44 | } 45 | -------------------------------------------------------------------------------- /dispatch-android-espresso/dependencies/releaseRuntimeClasspath.txt: -------------------------------------------------------------------------------- 1 | androidx.test.espresso:espresso-idling-resource:3.4.0 2 | junit:junit:4.13.2 3 | org.hamcrest:hamcrest-core:1.3 4 | org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10 5 | org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.10 6 | org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10 7 | org.jetbrains.kotlin:kotlin-stdlib:1.7.10 8 | org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2 9 | org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2 10 | org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2 11 | org.jetbrains:annotations:13.0 12 | -------------------------------------------------------------------------------- /dispatch-android-espresso/gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2021 Rick Busarow 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | POM_ARTIFACT_ID=dispatch-android-espresso 16 | POM_NAME=dispatch-android-espresso 17 | POM_PACKAGING=aar 18 | -------------------------------------------------------------------------------- /dispatch-android-espresso/src/main/java/dispatch/android/espresso/IdlingDispatcher.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.android.espresso 17 | 18 | import androidx.test.espresso.IdlingResource 19 | import androidx.test.espresso.idling.CountingIdlingResource 20 | import kotlinx.coroutines.CoroutineDispatcher 21 | import kotlinx.coroutines.Runnable 22 | import kotlin.coroutines.CoroutineContext 23 | 24 | /** 25 | * [IdlingResource] helper for coroutines. This class simply wraps a delegate [CoroutineDispatcher] 26 | * and keeps a running count of all coroutines it creates, decrementing the count when they 27 | * complete. 28 | * 29 | * @property delegate The [CoroutineDispatcher] which will be used for actual dispatch. 30 | * @see IdlingResource 31 | * @see CoroutineDispatcher 32 | */ 33 | public class IdlingDispatcher( 34 | private val delegate: CoroutineDispatcher 35 | ) : CoroutineDispatcher() { 36 | 37 | /** The [CountingIdlingResource] which is responsible for Espresso functionality. */ 38 | public val counter: CountingIdlingResource = CountingIdlingResource("IdlingResource for $this") 39 | 40 | /** 41 | * * true if the [counter]'s count is zero 42 | * * false if the [counter]'s count is non-zero 43 | * 44 | * @return 45 | */ 46 | @Suppress("UNUSED") 47 | public fun isIdle(): Boolean = counter.isIdleNow 48 | 49 | /** 50 | * Counting implementation of the [dispatch][CoroutineDispatcher.dispatch] function. 51 | * 52 | * The count is incremented for every dispatch, and decremented for every completion, including 53 | * suspension. 54 | */ 55 | override fun dispatch(context: CoroutineContext, block: Runnable) { 56 | 57 | val runnable = Runnable { 58 | counter.increment() 59 | try { 60 | block.run() 61 | } finally { 62 | counter.decrement() 63 | } 64 | } 65 | delegate.dispatch(context, runnable) 66 | } 67 | 68 | /** @suppress */ 69 | override fun toString(): String = "CountingDispatcher delegating to $delegate" 70 | } 71 | -------------------------------------------------------------------------------- /dispatch-android-espresso/src/test/java/dispatch/android/espresso/samples/DefaultIdlingCoroutineScope.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.android.espresso.samples 17 | 18 | import dispatch.android.espresso.DefaultIdlingCoroutineScope 19 | import dispatch.android.espresso.registerAllIdlingResources 20 | import dispatch.internal.test.Sample4 21 | import kotlinx.coroutines.Job 22 | import org.junit.runner.RunWith 23 | import org.robolectric.RobolectricTestRunner 24 | 25 | @RunWith(RobolectricTestRunner::class) 26 | class DefaultIdlingCoroutineScope { 27 | 28 | @Sample4 29 | fun createNoArgDefault() { 30 | 31 | val scope = DefaultIdlingCoroutineScope() 32 | 33 | scope.idlingDispatcherProvider.registerAllIdlingResources() 34 | } 35 | 36 | @Sample4 37 | fun createCustomDefault() { 38 | 39 | val scope = DefaultIdlingCoroutineScope( 40 | job = Job(), 41 | dispatcherProvider = SomeCustomIdlingDispatcherProvider() 42 | ) 43 | 44 | scope.idlingDispatcherProvider.registerAllIdlingResources() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /dispatch-android-espresso/src/test/java/dispatch/android/espresso/samples/IOIdlingCoroutineScope.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package dispatch.android.espresso.samples 16 | 17 | import dispatch.android.espresso.IOIdlingCoroutineScope 18 | import dispatch.android.espresso.registerAllIdlingResources 19 | import dispatch.internal.test.Sample4 20 | import kotlinx.coroutines.Job 21 | import org.junit.runner.RunWith 22 | import org.robolectric.RobolectricTestRunner 23 | 24 | @RunWith(RobolectricTestRunner::class) 25 | class IOIdlingCoroutineScope { 26 | 27 | @Sample4 28 | fun createNoArgIO() { 29 | 30 | val scope = IOIdlingCoroutineScope() 31 | 32 | scope.idlingDispatcherProvider.registerAllIdlingResources() 33 | } 34 | 35 | @Sample4 36 | fun createCustomIO() { 37 | 38 | val scope = IOIdlingCoroutineScope( 39 | job = Job(), 40 | dispatcherProvider = SomeCustomIdlingDispatcherProvider() 41 | ) 42 | 43 | scope.idlingDispatcherProvider.registerAllIdlingResources() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /dispatch-android-espresso/src/test/java/dispatch/android/espresso/samples/IdlingCoroutineScope.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.android.espresso.samples 17 | 18 | import dispatch.android.espresso.IdlingCoroutineScope 19 | import dispatch.android.espresso.IdlingDispatcherProvider 20 | import dispatch.android.espresso.registerAllIdlingResources 21 | import dispatch.internal.test.Sample4 22 | import kotlinx.coroutines.Job 23 | import org.junit.runner.RunWith 24 | import org.robolectric.RobolectricTestRunner 25 | 26 | @RunWith(RobolectricTestRunner::class) 27 | class IdlingCoroutineScope { 28 | 29 | @Sample4 30 | fun createNoArg() { 31 | 32 | val scope = IdlingCoroutineScope() 33 | 34 | scope.idlingDispatcherProvider.registerAllIdlingResources() 35 | } 36 | 37 | @Sample4 38 | fun createCustom() { 39 | 40 | val scope = IdlingCoroutineScope( 41 | job = Job(), 42 | dispatcherProvider = SomeCustomIdlingDispatcherProvider() 43 | ) 44 | 45 | scope.idlingDispatcherProvider.registerAllIdlingResources() 46 | } 47 | } 48 | 49 | fun SomeCustomIdlingDispatcherProvider() = IdlingDispatcherProvider() 50 | 51 | class TestAppComponent { 52 | val customDispatcherProvider = IdlingDispatcherProvider() 53 | } 54 | 55 | val testAppComponent get() = TestAppComponent() 56 | -------------------------------------------------------------------------------- /dispatch-android-espresso/src/test/java/dispatch/android/espresso/samples/IdlingCoroutineScopeRuleSample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.android.espresso.samples 17 | 18 | import dispatch.android.espresso.IdlingDispatcherProvider 19 | import dispatch.android.espresso.IdlingDispatcherProviderRule 20 | import kotlinx.coroutines.runBlocking 21 | import org.junit.Rule 22 | import org.junit.Test 23 | import org.junit.runner.RunWith 24 | import org.robolectric.RobolectricTestRunner 25 | 26 | @RunWith(RobolectricTestRunner::class) 27 | class IdlingCoroutineScopeRuleSample { 28 | 29 | // Retrieve the DispatcherProvider from a dependency graph, 30 | // so that the same one is used throughout the codebase. 31 | val customDispatcherProvider = testAppComponent.customDispatcherProvider 32 | 33 | @JvmField 34 | @Rule 35 | val idlingRule = IdlingDispatcherProviderRule { 36 | IdlingDispatcherProvider(customDispatcherProvider) 37 | } 38 | 39 | @Test 40 | fun testThings() = runBlocking { 41 | 42 | // Now any CoroutineScope which uses the DispatcherProvider 43 | // in TestAppComponent will sync its "idle" state with Espresso 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /dispatch-android-espresso/src/test/java/dispatch/android/espresso/samples/IdlingCoroutineScopeRuleWithLifecycleSample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package dispatch.android.espresso.samples 16 | 17 | import dispatch.android.espresso.IdlingDispatcherProvider 18 | import dispatch.android.espresso.IdlingDispatcherProviderRule 19 | import dispatch.android.lifecycle.LifecycleScopeFactory 20 | import dispatch.android.viewmodel.ViewModelScopeFactory 21 | import dispatch.core.MainImmediateCoroutineScope 22 | import kotlinx.coroutines.runBlocking 23 | import org.junit.Before 24 | import org.junit.Rule 25 | import org.junit.Test 26 | import org.junit.runner.RunWith 27 | import org.robolectric.RobolectricTestRunner 28 | 29 | @RunWith(RobolectricTestRunner::class) 30 | class IdlingCoroutineScopeRuleWithLifecycleSample { 31 | 32 | // Retrieve the DispatcherProvider from a dependency graph, 33 | // so that the same one is used throughout the codebase. 34 | val customDispatcherProvider = testAppComponent.customDispatcherProvider 35 | 36 | @JvmField 37 | @Rule 38 | val idlingRule = IdlingDispatcherProviderRule { 39 | IdlingDispatcherProvider(customDispatcherProvider) 40 | } 41 | 42 | @Before 43 | fun setUp() { 44 | LifecycleScopeFactory.set { customDispatcherProvider } 45 | ViewModelScopeFactory.set { 46 | MainImmediateCoroutineScope(customDispatcherProvider) 47 | } 48 | // now all scopes use the same IdlingDispatcherProvider 49 | } 50 | 51 | @Test 52 | fun testThings() = runBlocking { 53 | 54 | // Now any CoroutineScope which uses the DispatcherProvider 55 | // in TestAppComponent will sync its "idle" state with Espresso 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /dispatch-android-espresso/src/test/java/dispatch/android/espresso/samples/MainIdlingCoroutineScope.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package dispatch.android.espresso.samples 16 | 17 | import dispatch.android.espresso.MainIdlingCoroutineScope 18 | import dispatch.android.espresso.registerAllIdlingResources 19 | import dispatch.internal.test.Sample4 20 | import kotlinx.coroutines.Job 21 | import org.junit.runner.RunWith 22 | import org.robolectric.RobolectricTestRunner 23 | 24 | @RunWith(RobolectricTestRunner::class) 25 | class MainIdlingCoroutineScope { 26 | 27 | @Sample4 28 | fun createNoArgMain() { 29 | 30 | val scope = MainIdlingCoroutineScope() 31 | 32 | scope.idlingDispatcherProvider.registerAllIdlingResources() 33 | } 34 | 35 | @Sample4 36 | fun createCustomMain() { 37 | 38 | val scope = MainIdlingCoroutineScope( 39 | job = Job(), 40 | dispatcherProvider = SomeCustomIdlingDispatcherProvider() 41 | ) 42 | 43 | scope.idlingDispatcherProvider.registerAllIdlingResources() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /dispatch-android-espresso/src/test/java/dispatch/android/espresso/samples/MainImmediateIdlingCoroutineScope.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.android.espresso.samples 17 | 18 | import dispatch.android.espresso.MainImmediateIdlingCoroutineScope 19 | import dispatch.android.espresso.registerAllIdlingResources 20 | import dispatch.internal.test.Sample4 21 | import kotlinx.coroutines.Job 22 | import org.junit.runner.RunWith 23 | import org.robolectric.RobolectricTestRunner 24 | 25 | @RunWith(RobolectricTestRunner::class) 26 | class MainImmediateIdlingCoroutineScope { 27 | 28 | @Sample4 29 | fun createNoArg() { 30 | 31 | val scope = MainImmediateIdlingCoroutineScope() 32 | 33 | scope.idlingDispatcherProvider.registerAllIdlingResources() 34 | } 35 | 36 | @Sample4 37 | fun createCustom() { 38 | 39 | val scope = MainImmediateIdlingCoroutineScope( 40 | job = Job(), 41 | dispatcherProvider = SomeCustomIdlingDispatcherProvider() 42 | ) 43 | 44 | scope.idlingDispatcherProvider.registerAllIdlingResources() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /dispatch-android-espresso/src/test/java/dispatch/android/espresso/samples/UnconfinedIdlingCoroutineScope.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.android.espresso.samples 17 | 18 | import dispatch.android.espresso.UnconfinedIdlingCoroutineScope 19 | import dispatch.android.espresso.registerAllIdlingResources 20 | import dispatch.internal.test.Sample4 21 | import kotlinx.coroutines.Job 22 | import org.junit.runner.RunWith 23 | import org.robolectric.RobolectricTestRunner 24 | 25 | @RunWith(RobolectricTestRunner::class) 26 | class UnconfinedIdlingCoroutineScope { 27 | 28 | @Sample4 29 | fun createNoArgUnconfined() { 30 | 31 | val scope = UnconfinedIdlingCoroutineScope() 32 | 33 | scope.idlingDispatcherProvider.registerAllIdlingResources() 34 | } 35 | 36 | @Sample4 37 | fun createCustomUnconfined() { 38 | 39 | val scope = UnconfinedIdlingCoroutineScope( 40 | job = Job(), 41 | dispatcherProvider = SomeCustomIdlingDispatcherProvider() 42 | ) 43 | 44 | scope.idlingDispatcherProvider.registerAllIdlingResources() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /dispatch-android-lifecycle-extensions/api/dispatch-android-lifecycle-extensions.api: -------------------------------------------------------------------------------- 1 | public final class dispatch/android/lifecycle/LifecycleOwnerKt { 2 | public static final fun getDispatchLifecycleScope (Landroidx/lifecycle/LifecycleOwner;)Ldispatch/android/lifecycle/DispatchLifecycleScope; 3 | public static final fun getLifecycleScope (Landroidx/lifecycle/LifecycleOwner;)Ldispatch/android/lifecycle/DispatchLifecycleScope; 4 | } 5 | 6 | public final class dispatch/android/lifecycle/LifecycleScopeFactory { 7 | public static final field INSTANCE Ldispatch/android/lifecycle/LifecycleScopeFactory; 8 | public final fun reset ()V 9 | public final fun set (Ldispatch/android/lifecycle/DispatchLifecycleScopeFactory;)V 10 | public final fun set (Lkotlin/jvm/functions/Function0;)V 11 | } 12 | 13 | public final class dispatch/android/lifecycle/WithViewLifecycleScopeKt { 14 | public static final fun withViewLifecycleScope (Landroidx/fragment/app/Fragment;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/Job; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /dispatch-android-lifecycle-extensions/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | plugins { 17 | androidLibrary 18 | published 19 | } 20 | 21 | android { 22 | namespace = "dispatch.android.lifecycle.extensions" 23 | } 24 | 25 | dependencies { 26 | 27 | api(libs.androidx.fragment.core) 28 | api(libs.androidx.lifecycle.common) 29 | api(libs.kotlinx.coroutines.core) 30 | api(libs.kotlinx.coroutines.jvm) 31 | 32 | api(projects.dispatchAndroidLifecycle) 33 | 34 | implementation(libs.kotlinx.coroutines.android) 35 | 36 | implementation(projects.dispatchCore) 37 | 38 | testImplementation(libs.androidx.arch.test.core) 39 | testImplementation(libs.androidx.lifecycle.runtime) 40 | testImplementation(libs.androidx.test.espresso.core) 41 | testImplementation(libs.androidx.test.runner) 42 | testImplementation(libs.hermit.jUnit5) 43 | testImplementation(libs.junit.jupiter) 44 | testImplementation(libs.kotest.assertions) 45 | testImplementation(libs.kotest.properties) 46 | testImplementation(libs.kotest.runner) 47 | testImplementation(libs.kotlinx.coroutines.test) 48 | testImplementation(libs.robolectric) 49 | 50 | testImplementation(projects.dispatchAndroidEspresso) 51 | testImplementation(projects.dispatchInternalTest) 52 | testImplementation(projects.dispatchInternalTestAndroid) 53 | testImplementation(projects.dispatchTest) 54 | testImplementation(projects.dispatchTestJunit4) 55 | } 56 | -------------------------------------------------------------------------------- /dispatch-android-lifecycle-extensions/dependencies/releaseRuntimeClasspath.txt: -------------------------------------------------------------------------------- 1 | androidx.activity:activity:1.5.1 2 | androidx.annotation:annotation-experimental:1.1.0 3 | androidx.annotation:annotation:1.2.0 4 | androidx.arch.core:core-common:2.1.0 5 | androidx.arch.core:core-runtime:2.1.0 6 | androidx.collection:collection:1.1.0 7 | androidx.concurrent:concurrent-futures:1.0.0 8 | androidx.core:core-ktx:1.2.0 9 | androidx.core:core:1.8.0 10 | androidx.customview:customview:1.0.0 11 | androidx.fragment:fragment:1.5.2 12 | androidx.lifecycle:lifecycle-common:2.5.1 13 | androidx.lifecycle:lifecycle-livedata-core-ktx:2.5.1 14 | androidx.lifecycle:lifecycle-livedata-core:2.5.1 15 | androidx.lifecycle:lifecycle-livedata-ktx:2.5.1 16 | androidx.lifecycle:lifecycle-livedata:2.5.1 17 | androidx.lifecycle:lifecycle-runtime:2.5.1 18 | androidx.lifecycle:lifecycle-viewmodel-savedstate:2.5.1 19 | androidx.lifecycle:lifecycle-viewmodel:2.5.1 20 | androidx.loader:loader:1.0.0 21 | androidx.savedstate:savedstate:1.2.0 22 | androidx.tracing:tracing:1.0.0 23 | androidx.versionedparcelable:versionedparcelable:1.1.1 24 | androidx.viewpager:viewpager:1.0.0 25 | com.google.guava:listenablefuture:1.0 26 | org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10 27 | org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.10 28 | org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10 29 | org.jetbrains.kotlin:kotlin-stdlib:1.7.10 30 | org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2 31 | org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2 32 | org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2 33 | org.jetbrains:annotations:13.0 34 | -------------------------------------------------------------------------------- /dispatch-android-lifecycle-extensions/gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2021 Rick Busarow 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | POM_ARTIFACT_ID=dispatch-android-lifecycle-extensions 16 | POM_NAME=dispatch-android-lifecycle-extensions 17 | POM_PACKAGING=aar 18 | -------------------------------------------------------------------------------- /dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/internal/atomic.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.android.lifecycle.internal 17 | 18 | import androidx.lifecycle.Lifecycle 19 | import dispatch.android.lifecycle.DispatchLifecycleScope 20 | import dispatch.core.launchMainImmediate 21 | import kotlinx.coroutines.Job 22 | import java.util.concurrent.ConcurrentMap 23 | 24 | /** 25 | * Normal [getOrPut] is guaranteed to only return a single instance for a given key, but the 26 | * [defaultValue] lambda may be invoked unnecessarily. This would create a new instance of 27 | * [DispatchLifecycleScope] without actually returning it. 28 | * 29 | * This extra [DispatchLifecycleScope] would still be active and observing the [lifecycle][key]. 30 | * 31 | * This function compares the result of the lambda to the result of [getOrPut], and cancels the 32 | * lambda's result if it's different. 33 | * 34 | * @see getOrPut 35 | */ 36 | internal inline fun ConcurrentMap.atomicGetOrPut( 37 | key: Lifecycle, 38 | defaultValue: () -> DispatchLifecycleScope 39 | ): DispatchLifecycleScope { 40 | 41 | var newInstance: DispatchLifecycleScope? = null 42 | 43 | val existingOrNew = getOrPut(key) { 44 | newInstance = defaultValue.invoke() 45 | newInstance!! 46 | } 47 | 48 | // If the second value is different, that means the first was never inserted into the map. 49 | // Cancel the observer for `newInstance` and cancel the coroutineContext. 50 | newInstance?.let { new -> 51 | if (new != existingOrNew) { 52 | existingOrNew.launchMainImmediate { 53 | 54 | new.coroutineContext[Job]?.cancel() 55 | } 56 | } 57 | } 58 | 59 | return existingOrNew 60 | } 61 | -------------------------------------------------------------------------------- /dispatch-android-lifecycle-extensions/src/main/java/dispatch/android/lifecycle/withViewLifecycleScope.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.android.lifecycle 17 | 18 | import androidx.fragment.app.Fragment 19 | import kotlinx.coroutines.CoroutineScope 20 | import kotlinx.coroutines.ExperimentalCoroutinesApi 21 | import kotlinx.coroutines.Job 22 | 23 | /** 24 | * [CoroutineScope] helper for a [Fragment]'s 25 | * [ViewLifecycleOwner][androidx.fragment.app.FragmentViewLifecycleOwner]. 26 | * 27 | * This function observes a `Fragment`'s 28 | * [viewLifecycleOwnerLiveData][androidx.fragment.app.Fragment.getViewLifecycleOwnerLiveData], 29 | * and invokes [block]. 30 | * 31 | * @sample dispatch.android.lifecycle.samples.WithViewLifecycleScopeExtensionSample.sample 32 | */ 33 | @ExperimentalCoroutinesApi 34 | public fun Fragment.withViewLifecycleScope( 35 | block: ViewLifecycleCoroutineScope.() -> Unit 36 | ): Job = dispatchLifecycleScope.withViewLifecycle(this, block) 37 | -------------------------------------------------------------------------------- /dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/samples/Fragment.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.android.lifecycle.samples 17 | 18 | import androidx.lifecycle.Lifecycle 19 | import dispatch.internal.test.android.FakeLifecycleOwner 20 | 21 | @Suppress("UnnecessaryAbstractClass") 22 | abstract class Fragment( 23 | initialState: Lifecycle.State = Lifecycle.State.INITIALIZED 24 | ) : FakeLifecycleOwner(initialState = initialState) 25 | -------------------------------------------------------------------------------- /dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/samples/LifecycleScopeExtensionSamples.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.android.lifecycle.samples 17 | 18 | import dispatch.android.lifecycle.dispatchLifecycleScope 19 | import dispatch.core.launchMain 20 | import dispatch.internal.test.Sample5 21 | 22 | class LifecycleScopeExtensionSamples { 23 | 24 | @Sample5 25 | fun sample() { 26 | 27 | // This could be any LifecycleOwner -- Fragments, Activities, Services... 28 | class SomeFragment : Fragment() { 29 | 30 | init { 31 | 32 | // auto-created MainImmediateCoroutineScope which is lifecycle-aware 33 | dispatchLifecycleScope // ... 34 | 35 | // active only when "resumed". starts a fresh coroutine each time 36 | // this is a rough proxy for LiveData behavior 37 | dispatchLifecycleScope.launchOnResume { } 38 | 39 | // active only when "started". starts a fresh coroutine each time 40 | dispatchLifecycleScope.launchOnStart { } 41 | 42 | // launch when created, automatically stop on destroy 43 | dispatchLifecycleScope.launchOnCreate { } 44 | 45 | // it works as a normal CoroutineScope as well (because it is) 46 | dispatchLifecycleScope.launchMain { } 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/samples/LifecycleScopeFactorySample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | @file:Suppress("EXPERIMENTAL_API_USAGE") 17 | 18 | package dispatch.android.lifecycle.samples 19 | 20 | import dispatch.android.espresso.IdlingDispatcherProvider 21 | import dispatch.android.lifecycle.LifecycleScopeFactory 22 | import dispatch.android.lifecycle.MainImmediateContext 23 | import dispatch.core.DispatcherProvider 24 | import dispatch.internal.test.Application 25 | import dispatch.internal.test.MyCustomElement 26 | import dispatch.internal.test.Sample5 27 | import kotlinx.coroutines.SupervisorJob 28 | 29 | class LifecycleScopeFactorySample { 30 | 31 | @Sample5 32 | fun productionSample() { 33 | 34 | class MyApplication : Application { 35 | 36 | override fun onCreate() { 37 | 38 | LifecycleScopeFactory.set { MyCustomElement() + MainImmediateContext() } 39 | } 40 | } 41 | } 42 | 43 | @Sample5 44 | fun espressoSample() { 45 | 46 | class MyEspressoTest { 47 | 48 | @Before 49 | fun setUp() { 50 | 51 | val dispatcherProvider = IdlingDispatcherProvider() 52 | 53 | LifecycleScopeFactory.set { 54 | SupervisorJob() + dispatcherProvider + dispatcherProvider.mainImmediate 55 | } 56 | } 57 | } 58 | } 59 | 60 | @Sample5 61 | fun resetSample() { 62 | 63 | class MyEspressoTest { 64 | 65 | @Before 66 | fun setUp() { 67 | 68 | val dispatcherProvider = DispatcherProvider() 69 | 70 | LifecycleScopeFactory.set { 71 | SupervisorJob() + dispatcherProvider + dispatcherProvider.mainImmediate 72 | } 73 | } 74 | 75 | @After 76 | fun tearDown() { 77 | LifecycleScopeFactory.reset() 78 | } 79 | } 80 | } 81 | 82 | private annotation class Before 83 | private annotation class After 84 | } 85 | -------------------------------------------------------------------------------- /dispatch-android-lifecycle-extensions/src/test/java/dispatch/android/lifecycle/samples/WithViewLifecycleScopeExtensionSample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | @file:OptIn(ExperimentalCoroutinesApi::class) 17 | @file:Suppress("UNUSED_ANONYMOUS_PARAMETER") 18 | 19 | package dispatch.android.lifecycle.samples 20 | 21 | import androidx.fragment.app.Fragment 22 | import dispatch.android.lifecycle.withViewLifecycleScope 23 | import dispatch.internal.test.Sample4 24 | import kotlinx.coroutines.ExperimentalCoroutinesApi 25 | import kotlinx.coroutines.flow.flow 26 | import kotlinx.coroutines.flow.onEach 27 | import org.junit.runner.RunWith 28 | import org.robolectric.RobolectricTestRunner 29 | import org.robolectric.annotation.Config 30 | 31 | @RunWith(RobolectricTestRunner::class) 32 | @Config(manifest = Config.NONE) 33 | class WithViewLifecycleScopeExtensionSample { 34 | 35 | @Sample4 36 | fun sample() { 37 | 38 | class MyViewModel { 39 | 40 | val dataFlow = flow { 41 | // ... 42 | } 43 | } 44 | 45 | class MyFragment : Fragment() { 46 | 47 | val myViewModel = MyViewModel() 48 | 49 | val observerJob = withViewLifecycleScope { 50 | myViewModel.dataFlow.onEach { data -> 51 | // ... 52 | }.launchOnCreate() 53 | } 54 | } 55 | } 56 | } 57 | 58 | interface Data 59 | -------------------------------------------------------------------------------- /dispatch-android-lifecycle/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | plugins { 17 | androidLibrary 18 | published 19 | } 20 | 21 | android { 22 | namespace = "dispatch.android.lifecycle" 23 | } 24 | 25 | dependencies { 26 | 27 | api(libs.androidx.lifecycle.common) 28 | api(libs.kotlinx.coroutines.core) 29 | api(libs.kotlinx.coroutines.jvm) 30 | 31 | api(projects.dispatchCore) 32 | 33 | implementation(libs.androidx.fragment.core) 34 | implementation(libs.androidx.lifecycle.liveData) 35 | implementation(libs.androidx.lifecycle.liveDataKtx) 36 | implementation(libs.androidx.lifecycle.runtime) 37 | implementation(libs.kotlinx.coroutines.android) 38 | 39 | testImplementation(libs.androidx.arch.test.core) 40 | testImplementation(libs.androidx.fragment.ktx) 41 | testImplementation(libs.androidx.lifecycle.runtime) 42 | testImplementation(libs.androidx.lifecycle.viewModel.ktx) 43 | testImplementation(libs.androidx.test.espresso.core) 44 | testImplementation(libs.androidx.test.runner) 45 | testImplementation(libs.hermit.coroutines) 46 | testImplementation(libs.hermit.jUnit5) 47 | testImplementation(libs.junit.jupiter) 48 | testImplementation(libs.kotest.assertions) 49 | testImplementation(libs.kotest.properties) 50 | testImplementation(libs.kotest.runner) 51 | testImplementation(libs.kotlinx.coroutines.test) 52 | testImplementation(libs.robolectric) 53 | 54 | testImplementation(projects.dispatchAndroidLifecycleExtensions) 55 | testImplementation(projects.dispatchInternalTest) 56 | testImplementation(projects.dispatchInternalTestAndroid) 57 | testImplementation(projects.dispatchTest) 58 | testImplementation(projects.dispatchTestJunit4) 59 | testImplementation(projects.dispatchTestJunit5) 60 | } 61 | -------------------------------------------------------------------------------- /dispatch-android-lifecycle/dependencies/releaseRuntimeClasspath.txt: -------------------------------------------------------------------------------- 1 | androidx.activity:activity:1.5.1 2 | androidx.annotation:annotation-experimental:1.1.0 3 | androidx.annotation:annotation:1.2.0 4 | androidx.arch.core:core-common:2.1.0 5 | androidx.arch.core:core-runtime:2.1.0 6 | androidx.collection:collection:1.1.0 7 | androidx.concurrent:concurrent-futures:1.0.0 8 | androidx.core:core-ktx:1.2.0 9 | androidx.core:core:1.8.0 10 | androidx.customview:customview:1.0.0 11 | androidx.fragment:fragment:1.5.2 12 | androidx.lifecycle:lifecycle-common:2.5.1 13 | androidx.lifecycle:lifecycle-livedata-core-ktx:2.5.1 14 | androidx.lifecycle:lifecycle-livedata-core:2.5.1 15 | androidx.lifecycle:lifecycle-livedata-ktx:2.5.1 16 | androidx.lifecycle:lifecycle-livedata:2.5.1 17 | androidx.lifecycle:lifecycle-runtime:2.5.1 18 | androidx.lifecycle:lifecycle-viewmodel-savedstate:2.5.1 19 | androidx.lifecycle:lifecycle-viewmodel:2.5.1 20 | androidx.loader:loader:1.0.0 21 | androidx.savedstate:savedstate:1.2.0 22 | androidx.tracing:tracing:1.0.0 23 | androidx.versionedparcelable:versionedparcelable:1.1.1 24 | androidx.viewpager:viewpager:1.0.0 25 | com.google.guava:listenablefuture:1.0 26 | org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10 27 | org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.10 28 | org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10 29 | org.jetbrains.kotlin:kotlin-stdlib:1.7.10 30 | org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2 31 | org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2 32 | org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2 33 | org.jetbrains:annotations:13.0 34 | -------------------------------------------------------------------------------- /dispatch-android-lifecycle/gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2021 Rick Busarow 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | POM_ARTIFACT_ID=dispatch-android-lifecycle 16 | POM_NAME=dispatch-android-lifecycle 17 | POM_PACKAGING=aar 18 | -------------------------------------------------------------------------------- /dispatch-android-lifecycle/src/main/java/dispatch/android/lifecycle/DispatchLifecycleScopeFactory.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.android.lifecycle 17 | 18 | import androidx.lifecycle.Lifecycle 19 | import kotlin.coroutines.CoroutineContext 20 | 21 | /** 22 | * Factory for [DispatchLifecycleScope]s. This may be injected into a lifecycle-aware class to 23 | * provide custom [CoroutineContexts][CoroutineContext]. 24 | * 25 | * @property coroutineContextFactory the lambda defining the creating of a [CoroutineContext] 26 | * @sample dispatch.android.lifecycle.samples.DispatchLifecycleScopeFactorySample.factorySample 27 | */ 28 | public class DispatchLifecycleScopeFactory( 29 | private val coroutineContextFactory: () -> CoroutineContext 30 | ) { 31 | 32 | /** 33 | * Creates a new [DispatchLifecycleScope] using `coroutineContextFactory` 34 | * 35 | * @param lifecycle the lifecycle which will be bound to the [DispatchLifecycleScope] 36 | */ 37 | public fun create( 38 | lifecycle: Lifecycle 39 | ): DispatchLifecycleScope = DispatchLifecycleScope(lifecycle, coroutineContextFactory.invoke()) 40 | } 41 | -------------------------------------------------------------------------------- /dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/samples/DispatchLifecycleCoroutineScopeFactorySample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.android.lifecycle.samples 17 | 18 | import dispatch.android.lifecycle.DispatchLifecycleScopeFactory 19 | import dispatch.internal.test.MyCustomElement 20 | import dispatch.internal.test.Sample5 21 | import dispatch.internal.test.android.LiveDataTest 22 | 23 | class DispatchLifecycleScopeFactorySample : LiveDataTest { 24 | 25 | @Sample5 26 | fun factorySample() { 27 | 28 | @Provides 29 | fun provideFactory(): DispatchLifecycleScopeFactory = DispatchLifecycleScopeFactory { 30 | // other elements are added automatically 31 | MyCustomElement() 32 | } 33 | 34 | class MyFragment @Inject constructor( 35 | factory: DispatchLifecycleScopeFactory 36 | ) : Fragment() { 37 | 38 | val lifecycleScope = factory.create(lifecycle) 39 | 40 | init { 41 | lifecycleScope.launchOnStart { 42 | // ... 43 | } 44 | } 45 | } 46 | } 47 | } 48 | 49 | internal annotation class Before 50 | internal annotation class After 51 | internal annotation class Module 52 | internal annotation class Provides 53 | internal annotation class Inject 54 | -------------------------------------------------------------------------------- /dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/samples/Fragment.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.android.lifecycle.samples 17 | 18 | import androidx.lifecycle.Lifecycle 19 | import dispatch.internal.test.android.FakeLifecycleOwner 20 | 21 | @Suppress("UnnecessaryAbstractClass") 22 | abstract class Fragment( 23 | initialState: Lifecycle.State = Lifecycle.State.INITIALIZED 24 | ) : FakeLifecycleOwner(initialState = initialState) 25 | -------------------------------------------------------------------------------- /dispatch-android-lifecycle/src/test/java/dispatch/android/lifecycle/samples/WithLifecycleScopeSample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | @file:OptIn(ExperimentalCoroutinesApi::class) 17 | @file:Suppress("UNUSED_ANONYMOUS_PARAMETER") 18 | 19 | package dispatch.android.lifecycle.samples 20 | 21 | import androidx.fragment.app.Fragment 22 | import androidx.fragment.app.viewModels 23 | import androidx.lifecycle.ViewModel 24 | import dispatch.android.lifecycle.withViewLifecycle 25 | import dispatch.core.MainImmediateCoroutineScope 26 | import dispatch.internal.test.android.LiveDataTest 27 | import kotlinx.coroutines.ExperimentalCoroutinesApi 28 | import kotlinx.coroutines.flow.flow 29 | import kotlinx.coroutines.flow.onEach 30 | import org.junit.Test 31 | import org.junit.runner.RunWith 32 | import org.robolectric.RobolectricTestRunner 33 | import org.robolectric.annotation.Config 34 | 35 | @Suppress("MemberNameEqualsClassName") 36 | @RunWith(RobolectricTestRunner::class) 37 | @ExperimentalCoroutinesApi 38 | @Config(manifest = Config.NONE) 39 | class WithViewLifecycleScopeSample : LiveDataTest { 40 | 41 | @Test 42 | fun sample() { 43 | 44 | class MyFragment @Inject constructor( 45 | scope: MainImmediateCoroutineScope 46 | ) : Fragment() { 47 | 48 | val myViewModel by viewModels() 49 | 50 | val observerJob = scope.withViewLifecycle(this) { 51 | // this lambda is invoked every time the View lifecycle is set 52 | myViewModel.dataFlow.onEach { data -> 53 | // ... 54 | }.launchOnCreate() 55 | } 56 | } 57 | } 58 | } 59 | 60 | interface Data 61 | 62 | class MyViewModel : ViewModel() { 63 | 64 | val dataFlow = flow { 65 | // ... 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /dispatch-android-viewmodel/api/dispatch-android-viewmodel.api: -------------------------------------------------------------------------------- 1 | public abstract class dispatch/android/viewmodel/DispatchViewModel : androidx/lifecycle/ViewModel { 2 | public fun ()V 3 | public final fun getViewModelScope ()Lkotlinx/coroutines/CoroutineScope; 4 | protected fun onClear ()V 5 | protected final fun onCleared ()V 6 | } 7 | 8 | public final class dispatch/android/viewmodel/ViewModelScopeFactory { 9 | public static final field INSTANCE Ldispatch/android/viewmodel/ViewModelScopeFactory; 10 | public final fun reset ()V 11 | public final fun set (Lkotlin/jvm/functions/Function0;)V 12 | } 13 | 14 | -------------------------------------------------------------------------------- /dispatch-android-viewmodel/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | plugins { 17 | androidLibrary 18 | published 19 | } 20 | 21 | android { 22 | namespace = "dispatch.android.viewmodel" 23 | } 24 | 25 | dependencies { 26 | api(libs.androidx.lifecycle.viewModel.core) 27 | api(libs.kotlinx.coroutines.core) 28 | api(libs.kotlinx.coroutines.jvm) 29 | 30 | api(projects.dispatchCore) 31 | 32 | implementation(libs.androidx.lifecycle.viewModel.ktx) 33 | implementation(libs.kotlinx.coroutines.android) 34 | 35 | testImplementation(libs.androidx.test.espresso.core) 36 | testImplementation(libs.androidx.test.runner) 37 | testImplementation(libs.junit.jupiter) 38 | testImplementation(libs.kotest.assertions) 39 | testImplementation(libs.kotest.properties) 40 | testImplementation(libs.kotest.runner) 41 | testImplementation(libs.kotlinx.coroutines.test) 42 | 43 | testImplementation(projects.dispatchAndroidEspresso) 44 | testImplementation(projects.dispatchAndroidViewmodel) 45 | testImplementation(projects.dispatchInternalTest) 46 | testImplementation(projects.dispatchTest) 47 | } 48 | -------------------------------------------------------------------------------- /dispatch-android-viewmodel/dependencies/releaseRuntimeClasspath.txt: -------------------------------------------------------------------------------- 1 | androidx.annotation:annotation:1.1.0 2 | androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1 3 | androidx.lifecycle:lifecycle-viewmodel:2.5.1 4 | org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10 5 | org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.10 6 | org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10 7 | org.jetbrains.kotlin:kotlin-stdlib:1.7.10 8 | org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2 9 | org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2 10 | org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2 11 | org.jetbrains:annotations:13.0 12 | -------------------------------------------------------------------------------- /dispatch-android-viewmodel/gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2021 Rick Busarow 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | POM_ARTIFACT_ID=dispatch-android-viewmodel 16 | POM_NAME=dispatch-android-viewmodel 17 | POM_PACKAGING=aar 18 | -------------------------------------------------------------------------------- /dispatch-android-viewmodel/src/test/java/dispatch/android/viewmodel/samples/Application.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.android.viewmodel.samples 17 | 18 | interface Application { 19 | fun onCreate() 20 | } 21 | -------------------------------------------------------------------------------- /dispatch-android-viewmodel/src/test/java/dispatch/android/viewmodel/samples/ViewModelScopeFactorySample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.android.viewmodel.samples 17 | 18 | import dispatch.android.espresso.MainImmediateIdlingCoroutineScope 19 | import dispatch.android.viewmodel.ViewModelScopeFactory 20 | import dispatch.core.MainImmediateCoroutineScope 21 | import dispatch.internal.test.Sample5 22 | import dispatch.test.TestProvidedCoroutineScope 23 | import kotlinx.coroutines.ExperimentalCoroutinesApi 24 | 25 | @ExperimentalCoroutinesApi 26 | class ViewModelScopeFactorySample { 27 | 28 | @Sample5 29 | fun productionSample() { 30 | 31 | class MyApplication : Application { 32 | 33 | override fun onCreate() { 34 | ViewModelScopeFactory.set { MainImmediateCoroutineScope() } 35 | } 36 | } 37 | } 38 | 39 | @Sample5 40 | fun espressoSample() { 41 | 42 | class MyEspressoTest { 43 | 44 | @Before 45 | fun setUp() { 46 | ViewModelScopeFactory.set { MainImmediateIdlingCoroutineScope() } 47 | } 48 | } 49 | } 50 | 51 | @Sample5 52 | fun resetSample() { 53 | 54 | class MyEspressoTest { 55 | 56 | @Before 57 | fun setUp() { 58 | ViewModelScopeFactory.set { MainImmediateIdlingCoroutineScope() } 59 | } 60 | 61 | @After 62 | fun tearDown() { 63 | ViewModelScopeFactory.reset() 64 | } 65 | } 66 | } 67 | 68 | @Sample5 69 | fun jvmSample() { 70 | 71 | class MyJvmTest { 72 | 73 | @Before 74 | fun setUp() { 75 | ViewModelScopeFactory.set { TestProvidedCoroutineScope() } 76 | } 77 | } 78 | } 79 | 80 | private annotation class Before 81 | private annotation class After 82 | } 83 | -------------------------------------------------------------------------------- /dispatch-android-viewmodel/src/test/java/dispatch/android/viewmodel/samples/ViewModelScopeSample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.android.viewmodel.samples 17 | 18 | import dispatch.android.viewmodel.DispatchViewModel 19 | import dispatch.core.launchMain 20 | import dispatch.internal.test.Sample5 21 | import io.kotest.matchers.shouldBe 22 | import kotlinx.coroutines.ExperimentalCoroutinesApi 23 | import kotlinx.coroutines.isActive 24 | 25 | @Suppress("MemberNameEqualsClassName") 26 | @ExperimentalCoroutinesApi 27 | class ViewModelScopeSample { 28 | 29 | @Sample5 30 | fun viewModelScopeSample() { 31 | 32 | class SomeViewModel : DispatchViewModel() { 33 | 34 | init { 35 | 36 | // auto-created MainImmediateCoroutineScope which is auto-cancelled in onClear() 37 | viewModelScope // ... 38 | 39 | // it works as a normal CoroutineScope (because it is) 40 | viewModelScope.launchMain { } 41 | 42 | // this is the same CoroutineScope instance each time 43 | viewModelScope.launchMain { } 44 | } 45 | 46 | override fun onClear() { 47 | viewModelScope.isActive shouldBe false 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /dispatch-bom/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | plugins { 17 | `java-platform` 18 | published 19 | } 20 | 21 | version = project.extra.properties["VERSION_NAME"] as String 22 | 23 | val bomProject = project 24 | 25 | rootProject 26 | .subprojects 27 | .filter { it.includeInBom() } 28 | .forEach { bomProject.evaluationDependsOn(it.path) } 29 | 30 | dependencies { 31 | constraints { 32 | rootProject 33 | .subprojects 34 | .filter { it.includeInBom() } 35 | .forEach { api(project(it.path)) } 36 | } 37 | } 38 | 39 | publishing { 40 | publications { 41 | create("DispatchBom") { 42 | from(components["javaPlatform"]) 43 | } 44 | } 45 | } 46 | 47 | fun Project.includeInBom() = !path.contains("sample") && 48 | !path.contains("internal") && 49 | this != bomProject 50 | -------------------------------------------------------------------------------- /dispatch-bom/gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2021 Rick Busarow 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | POM_ARTIFACT_ID=dispatch-bom 16 | POM_NAME=dispatch-bom 17 | POM_PACKAGING=jar 18 | -------------------------------------------------------------------------------- /dispatch-core/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | plugins { 17 | javaLibrary 18 | published 19 | id("kotlinx-atomicfu") 20 | } 21 | 22 | dependencies { 23 | 24 | api(libs.kotlinx.coroutines.core) 25 | api(libs.kotlinx.coroutines.jvm) 26 | 27 | testImplementation(libs.hermit.jUnit5) 28 | testImplementation(libs.junit.jupiter) 29 | testImplementation(libs.kotest.assertions) 30 | testImplementation(libs.kotest.properties) 31 | testImplementation(libs.kotlin.test.common) 32 | testImplementation(libs.kotlin.test.core) 33 | testImplementation(libs.kotlinx.coroutines.test) 34 | testImplementation(libs.mockk) 35 | 36 | testImplementation(projects.dispatchInternalTest) 37 | } 38 | -------------------------------------------------------------------------------- /dispatch-core/dependencies/runtimeClasspath.txt: -------------------------------------------------------------------------------- 1 | org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10 2 | org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.10 3 | org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10 4 | org.jetbrains.kotlin:kotlin-stdlib:1.7.10 5 | org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2 6 | org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2 7 | org.jetbrains:annotations:13.0 8 | -------------------------------------------------------------------------------- /dispatch-core/gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2021 Rick Busarow 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | POM_ARTIFACT_ID=dispatch-core 16 | POM_NAME=dispatch-core 17 | POM_PACKAGING=jar 18 | -------------------------------------------------------------------------------- /dispatch-core/src/test/java/dispatch/core/samples/AsyncSample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.core.samples 17 | 18 | import dispatch.core.asyncDefault 19 | import dispatch.core.asyncIO 20 | import dispatch.core.asyncMain 21 | import dispatch.core.asyncMainImmediate 22 | import dispatch.core.asyncUnconfined 23 | import dispatch.internal.test.Sample5 24 | import dispatch.internal.test.dispatcherName 25 | import dispatch.internal.test.someDispatcherProvider 26 | import io.kotest.matchers.shouldBe 27 | import kotlinx.coroutines.runBlocking 28 | 29 | class AsyncSample { 30 | 31 | @Sample5 32 | fun asyncDefaultSample() = runBlocking(someDispatcherProvider) { 33 | 34 | dispatcherName() shouldBe "runBlocking thread" 35 | 36 | asyncDefault { 37 | 38 | dispatcherName() shouldBe "default" 39 | }.join() 40 | } 41 | 42 | @Sample5 43 | fun asyncIOSample() = runBlocking(someDispatcherProvider) { 44 | 45 | dispatcherName() shouldBe "runBlocking thread" 46 | 47 | asyncIO { 48 | 49 | dispatcherName() shouldBe "io" 50 | }.join() 51 | } 52 | 53 | @Sample5 54 | fun asyncMainSample() = runBlocking(someDispatcherProvider) { 55 | 56 | dispatcherName() shouldBe "runBlocking thread" 57 | 58 | asyncMain { 59 | 60 | dispatcherName() shouldBe "main" 61 | }.join() 62 | } 63 | 64 | @Sample5 65 | fun asyncMainImmediateSample() = runBlocking(someDispatcherProvider) { 66 | 67 | dispatcherName() shouldBe "runBlocking thread" 68 | 69 | asyncMainImmediate { 70 | 71 | dispatcherName() shouldBe "main immediate" 72 | }.join() 73 | } 74 | 75 | @Sample5 76 | fun asyncUnconfinedSample() = runBlocking(someDispatcherProvider) { 77 | 78 | dispatcherName() shouldBe "runBlocking thread" 79 | 80 | asyncUnconfined { 81 | 82 | dispatcherName() shouldBe "unconfined" 83 | }.join() 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /dispatch-core/src/test/java/dispatch/core/samples/DispatcherProviderCopySample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.core.samples 17 | 18 | import dispatch.core.dispatcherProvider 19 | import dispatch.internal.test.Sample5 20 | import io.kotest.matchers.shouldBe 21 | import kotlinx.coroutines.CoroutineDispatcher 22 | import kotlinx.coroutines.Dispatchers 23 | import kotlinx.coroutines.ExperimentalCoroutinesApi 24 | import kotlinx.coroutines.Runnable 25 | import kotlinx.coroutines.currentCoroutineContext 26 | import kotlinx.coroutines.runBlocking 27 | import kotlinx.coroutines.test.resetMain 28 | import kotlinx.coroutines.test.setMain 29 | import kotlinx.coroutines.withContext 30 | import kotlin.coroutines.CoroutineContext 31 | 32 | @Suppress("HardCodedDispatcher") 33 | @OptIn( 34 | ExperimentalStdlibApi::class, 35 | ExperimentalCoroutinesApi::class 36 | ) 37 | class DispatcherProviderCopySample { 38 | 39 | @Sample5 40 | fun testCopySample() = runBlocking { 41 | 42 | Dispatchers.setMain(coroutineContext[CoroutineDispatcher.Key]!!) 43 | 44 | copySample() 45 | 46 | Dispatchers.resetMain() 47 | } 48 | 49 | suspend fun copySample() { 50 | val originalDispatcherProvider = currentCoroutineContext().dispatcherProvider 51 | originalDispatcherProvider.main shouldBe Dispatchers.Main 52 | 53 | val newMain = MyCustomBlockingQueueDispatcher() 54 | // create a copy of the existing DispatcherProvider, except the new main dispatcher 55 | val bleDispatchers = originalDispatcherProvider.copy(main = newMain) 56 | 57 | withContext(bleDispatchers) { 58 | // any coroutine downstream of this `withContext { }` will use the redefined main dispatcher 59 | dispatcherProvider.main shouldBe newMain 60 | } 61 | } 62 | 63 | private class MyCustomBlockingQueueDispatcher : CoroutineDispatcher() { 64 | override fun dispatch(context: CoroutineContext, block: Runnable) { 65 | block.run() 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /dispatch-core/src/test/java/dispatch/core/samples/LaunchSample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.core.samples 17 | 18 | import dispatch.core.launchDefault 19 | import dispatch.core.launchIO 20 | import dispatch.core.launchMain 21 | import dispatch.core.launchMainImmediate 22 | import dispatch.core.launchUnconfined 23 | import dispatch.internal.test.Sample5 24 | import dispatch.internal.test.dispatcherName 25 | import dispatch.internal.test.someDispatcherProvider 26 | import io.kotest.matchers.shouldBe 27 | import kotlinx.coroutines.runBlocking 28 | 29 | class LaunchSample { 30 | 31 | @Sample5 32 | fun launchDefaultSample() = runBlocking(someDispatcherProvider) { 33 | 34 | dispatcherName() shouldBe "runBlocking thread" 35 | 36 | launchDefault { 37 | 38 | dispatcherName() shouldBe "default" 39 | }.join() 40 | } 41 | 42 | @Sample5 43 | fun launchIOSample() = runBlocking(someDispatcherProvider) { 44 | 45 | dispatcherName() shouldBe "runBlocking thread" 46 | 47 | launchIO { 48 | 49 | dispatcherName() shouldBe "io" 50 | }.join() 51 | } 52 | 53 | @Sample5 54 | fun launchMainSample() = runBlocking(someDispatcherProvider) { 55 | 56 | dispatcherName() shouldBe "runBlocking thread" 57 | 58 | launchMain { 59 | 60 | dispatcherName() shouldBe "main" 61 | }.join() 62 | } 63 | 64 | @Sample5 65 | fun launchMainImmediateSample() = runBlocking(someDispatcherProvider) { 66 | 67 | dispatcherName() shouldBe "runBlocking thread" 68 | 69 | launchMainImmediate { 70 | 71 | dispatcherName() shouldBe "main immediate" 72 | }.join() 73 | } 74 | 75 | @Sample5 76 | fun launchUnconfinedSample() = runBlocking(someDispatcherProvider) { 77 | 78 | dispatcherName() shouldBe "runBlocking thread" 79 | 80 | launchUnconfined { 81 | 82 | dispatcherName() shouldBe "unconfined" 83 | }.join() 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /dispatch-core/src/test/java/dispatch/core/samples/WithContextSample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.core.samples 17 | 18 | import dispatch.core.withDefault 19 | import dispatch.core.withIO 20 | import dispatch.core.withMain 21 | import dispatch.core.withMainImmediate 22 | import dispatch.core.withUnconfined 23 | import dispatch.internal.test.Sample5 24 | import dispatch.internal.test.dispatcherName 25 | import dispatch.internal.test.someDispatcherProvider 26 | import io.kotest.matchers.shouldBe 27 | import kotlinx.coroutines.runBlocking 28 | 29 | class WithContextSample { 30 | 31 | @Sample5 32 | fun withDefaultSample() = runBlocking(someDispatcherProvider) { 33 | 34 | dispatcherName() shouldBe "runBlocking thread" 35 | 36 | withDefault { 37 | 38 | dispatcherName() shouldBe "default" 39 | } 40 | } 41 | 42 | @Sample5 43 | fun withIOSample() = runBlocking(someDispatcherProvider) { 44 | 45 | dispatcherName() shouldBe "runBlocking thread" 46 | 47 | withIO { 48 | 49 | dispatcherName() shouldBe "io" 50 | } 51 | } 52 | 53 | @Sample5 54 | fun withMainSample() = runBlocking(someDispatcherProvider) { 55 | 56 | dispatcherName() shouldBe "runBlocking thread" 57 | 58 | withMain { 59 | 60 | dispatcherName() shouldBe "main" 61 | } 62 | } 63 | 64 | @Sample5 65 | fun withMainImmediateSample() = runBlocking(someDispatcherProvider) { 66 | 67 | dispatcherName() shouldBe "runBlocking thread" 68 | 69 | withMainImmediate { 70 | 71 | dispatcherName() shouldBe "main immediate" 72 | } 73 | } 74 | 75 | @Sample5 76 | fun withUnconfinedSample() = runBlocking(someDispatcherProvider) { 77 | 78 | dispatcherName() shouldBe "runBlocking thread" 79 | 80 | withUnconfined { 81 | 82 | dispatcherName() shouldBe "unconfined" 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /dispatch-detekt/api/dispatch-detekt.api: -------------------------------------------------------------------------------- 1 | public final class dispatch/detekt/ConfigError : io/gitlab/arturbosch/detekt/api/Notification { 2 | public fun (Ljava/lang/String;Lio/gitlab/arturbosch/detekt/api/Notification$Level;)V 3 | public synthetic fun (Ljava/lang/String;Lio/gitlab/arturbosch/detekt/api/Notification$Level;ILkotlin/jvm/internal/DefaultConstructorMarker;)V 4 | public fun getLevel ()Lio/gitlab/arturbosch/detekt/api/Notification$Level; 5 | public fun getMessage ()Ljava/lang/String; 6 | public fun isError ()Z 7 | } 8 | 9 | public final class dispatch/detekt/DispatchConfigValidator : io/gitlab/arturbosch/detekt/api/ConfigValidator { 10 | public fun ()V 11 | public fun getId ()Ljava/lang/String; 12 | public fun getPriority ()I 13 | public fun init (Lio/gitlab/arturbosch/detekt/api/Config;)V 14 | public fun init (Lio/gitlab/arturbosch/detekt/api/SetupContext;)V 15 | public fun validate (Lio/gitlab/arturbosch/detekt/api/Config;)Ljava/util/Collection; 16 | } 17 | 18 | public final class dispatch/detekt/DispatchRuleSetProvider : io/gitlab/arturbosch/detekt/api/RuleSetProvider { 19 | public fun ()V 20 | public fun getRuleSetId ()Ljava/lang/String; 21 | public fun instance (Lio/gitlab/arturbosch/detekt/api/Config;)Lio/gitlab/arturbosch/detekt/api/RuleSet; 22 | } 23 | 24 | public final class dispatch/detekt/rules/AndroidXLifecycleScope : io/gitlab/arturbosch/detekt/api/Rule { 25 | public fun ()V 26 | public fun (Lio/gitlab/arturbosch/detekt/api/Config;)V 27 | public synthetic fun (Lio/gitlab/arturbosch/detekt/api/Config;ILkotlin/jvm/internal/DefaultConstructorMarker;)V 28 | public fun getIssue ()Lio/gitlab/arturbosch/detekt/api/Issue; 29 | public fun visitImportDirective (Lorg/jetbrains/kotlin/psi/KtImportDirective;)V 30 | public fun visitReferenceExpression (Lorg/jetbrains/kotlin/psi/KtReferenceExpression;)V 31 | } 32 | 33 | public final class dispatch/detekt/rules/HardCodedDispatcher : io/gitlab/arturbosch/detekt/api/Rule { 34 | public fun ()V 35 | public fun (Lio/gitlab/arturbosch/detekt/api/Config;)V 36 | public synthetic fun (Lio/gitlab/arturbosch/detekt/api/Config;ILkotlin/jvm/internal/DefaultConstructorMarker;)V 37 | public fun getIssue ()Lio/gitlab/arturbosch/detekt/api/Issue; 38 | public fun visitDotQualifiedExpression (Lorg/jetbrains/kotlin/psi/KtDotQualifiedExpression;)V 39 | public fun visitImportDirective (Lorg/jetbrains/kotlin/psi/KtImportDirective;)V 40 | public fun visitReferenceExpression (Lorg/jetbrains/kotlin/psi/KtReferenceExpression;)V 41 | } 42 | 43 | -------------------------------------------------------------------------------- /dispatch-detekt/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | plugins { 17 | javaLibrary 18 | published 19 | } 20 | 21 | dependencies { 22 | 23 | api(libs.detekt.api) 24 | api(libs.kotlin.compiler) 25 | 26 | testImplementation(libs.detekt.test) 27 | testImplementation(libs.junit.api) 28 | testImplementation(libs.kotest.assertions) 29 | testImplementation(libs.kotest.properties) 30 | testImplementation(libs.kotest.runner) 31 | 32 | testRuntimeOnly(libs.junit.engine) 33 | testRuntimeOnly(libs.junit.vintage) 34 | } 35 | -------------------------------------------------------------------------------- /dispatch-detekt/dependencies/runtimeClasspath.txt: -------------------------------------------------------------------------------- 1 | io.gitlab.arturbosch.detekt:detekt-api:1.21.0 2 | io.gitlab.arturbosch.detekt:detekt-psi-utils:1.21.0 3 | io.gitlab.arturbosch.detekt:detekt-utils:1.21.0 4 | net.java.dev.jna:jna:5.6.0 5 | org.jetbrains.intellij.deps:trove4j:1.0.20200330 6 | org.jetbrains.kotlin:kotlin-compiler-embeddable:1.7.10 7 | org.jetbrains.kotlin:kotlin-daemon-embeddable:1.7.10 8 | org.jetbrains.kotlin:kotlin-reflect:1.7.10 9 | org.jetbrains.kotlin:kotlin-script-runtime:1.7.10 10 | org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10 11 | org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.10 12 | org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10 13 | org.jetbrains.kotlin:kotlin-stdlib:1.7.10 14 | org.jetbrains:annotations:13.0 15 | -------------------------------------------------------------------------------- /dispatch-detekt/gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2021 Rick Busarow 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | POM_ARTIFACT_ID=dispatch-detekt 16 | POM_NAME=dispatch-detekt 17 | POM_PACKAGING=jar 18 | -------------------------------------------------------------------------------- /dispatch-detekt/src/main/java/dispatch/detekt/DispatchRuleSetProvider.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.detekt 17 | 18 | import dispatch.detekt.rules.AndroidXLifecycleScope 19 | import dispatch.detekt.rules.HardCodedDispatcher 20 | import io.gitlab.arturbosch.detekt.api.Config 21 | import io.gitlab.arturbosch.detekt.api.RuleSet 22 | import io.gitlab.arturbosch.detekt.api.RuleSetProvider 23 | 24 | /** @suppress */ 25 | public class DispatchRuleSetProvider : RuleSetProvider { 26 | 27 | override val ruleSetId: String = "dispatch" 28 | 29 | override fun instance(config: Config): RuleSet = RuleSet( 30 | id = ruleSetId, 31 | rules = listOf( 32 | AndroidXLifecycleScope(config), 33 | HardCodedDispatcher(config) 34 | ) 35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /dispatch-detekt/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.ConfigValidator: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2021 Rick Busarow 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | 16 | # 17 | # Copyright (C) 2020 Rick Busarow 18 | # Licensed under the Apache License, Version 2.0 (the "License"); 19 | # you may not use this file except in compliance with the License. 20 | # You may obtain a copy of the License at 21 | # 22 | # http://www.apache.org/licenses/LICENSE-2.0 23 | # 24 | # Unless required by applicable law or agreed to in writing, software 25 | # distributed under the License is distributed on an "AS IS" BASIS, 26 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 27 | # See the License for the specific language governing permissions and 28 | # limitations under the License. 29 | # 30 | 31 | # 32 | # Copyright (C) 2020 Rick Busarow 33 | # Licensed under the Apache License, Version 2.0 (the "License"); 34 | # you may not use this file except in compliance with the License. 35 | # You may obtain a copy of the License at 36 | # 37 | # http://www.apache.org/licenses/LICENSE-2.0 38 | # 39 | # Unless required by applicable law or agreed to in writing, software 40 | # distributed under the License is distributed on an "AS IS" BASIS, 41 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 42 | # See the License for the specific language governing permissions and 43 | # limitations under the License. 44 | # 45 | 46 | dispatch.detekt.DispatchConfigValidator 47 | -------------------------------------------------------------------------------- /dispatch-detekt/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.RuleSetProvider: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2021 Rick Busarow 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | 16 | dispatch.detekt.DispatchRuleSetProvider 17 | -------------------------------------------------------------------------------- /dispatch-detekt/src/test/java/dispatch/detekt/rules/util.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.detekt.rules 17 | 18 | import io.gitlab.arturbosch.detekt.api.Finding 19 | 20 | val List.messages: List 21 | get() = map { it.message } 22 | -------------------------------------------------------------------------------- /dispatch-internal-test-android/api/dispatch-internal-test-android.api: -------------------------------------------------------------------------------- 1 | public final class dispatch/internal/test/android/BuildConfig { 2 | public static final field BUILD_TYPE Ljava/lang/String; 3 | public static final field DEBUG Z 4 | public static final field LIBRARY_PACKAGE_NAME Ljava/lang/String; 5 | public static final field VERSION_CODE I 6 | public static final field VERSION_NAME Ljava/lang/String; 7 | public fun ()V 8 | } 9 | 10 | public class dispatch/internal/test/android/FakeFragment : androidx/fragment/app/Fragment { 11 | public fun (Landroidx/lifecycle/LifecycleOwner;)V 12 | public fun getLifecycle ()Landroidx/lifecycle/Lifecycle; 13 | public fun getViewLifecycleOwner ()Landroidx/lifecycle/LifecycleOwner; 14 | public fun getViewLifecycleOwnerLiveData ()Landroidx/lifecycle/LiveData; 15 | public fun setFakeViewLifecycleOwner (Landroidx/lifecycle/LifecycleOwner;)V 16 | } 17 | 18 | public class dispatch/internal/test/android/FakeLifecycleOwner : androidx/lifecycle/LifecycleOwner { 19 | public fun ()V 20 | public fun (Lkotlinx/coroutines/CoroutineDispatcher;Landroidx/lifecycle/Lifecycle$State;)V 21 | public synthetic fun (Lkotlinx/coroutines/CoroutineDispatcher;Landroidx/lifecycle/Lifecycle$State;ILkotlin/jvm/internal/DefaultConstructorMarker;)V 22 | public final fun create ()V 23 | public final fun destroy ()V 24 | public synthetic fun getLifecycle ()Landroidx/lifecycle/Lifecycle; 25 | public fun getLifecycle ()Landroidx/lifecycle/LifecycleRegistry; 26 | public final fun getObserverCount ()I 27 | public final fun initialize ()V 28 | public final fun pause ()V 29 | public final fun resume ()V 30 | public final fun start ()V 31 | public final fun stop ()V 32 | } 33 | 34 | -------------------------------------------------------------------------------- /dispatch-internal-test-android/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | plugins { 17 | androidLibrary 18 | } 19 | 20 | android { 21 | namespace = "dispatch.internal.test.android" 22 | } 23 | 24 | dependencies { 25 | 26 | api(libs.androidx.fragment.core) 27 | api(libs.androidx.lifecycle.common) 28 | api(libs.androidx.lifecycle.liveData) 29 | api(libs.androidx.lifecycle.runtime) 30 | api(libs.junit.api) 31 | api(libs.kotlinx.coroutines.core) 32 | api(libs.kotlinx.coroutines.jvm) 33 | 34 | implementation(libs.androidx.lifecycle.runtimeKtx) 35 | implementation(libs.kotlin.reflect) 36 | implementation(libs.kotlinx.coroutines.android) 37 | } 38 | -------------------------------------------------------------------------------- /dispatch-internal-test-android/src/main/java/dispatch/internal/test/android/FakeFragment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.internal.test.android; 17 | 18 | import androidx.annotation.NonNull; 19 | import androidx.fragment.app.Fragment; 20 | import androidx.lifecycle.Lifecycle; 21 | import androidx.lifecycle.LifecycleOwner; 22 | import androidx.lifecycle.LiveData; 23 | import androidx.lifecycle.MutableLiveData; 24 | 25 | import org.jetbrains.annotations.Nullable; 26 | 27 | public class FakeFragment extends Fragment { 28 | 29 | LifecycleOwner fragmentLifecycleOwner; 30 | MutableLiveData fakeViewLifecycleOwnerLiveData = new MutableLiveData<>(null); 31 | private LifecycleOwner fakeViewLifecycleOwner = null; 32 | 33 | public FakeFragment(@Nullable LifecycleOwner fragmentLifecycleOwner) { 34 | this.fragmentLifecycleOwner = fragmentLifecycleOwner; 35 | } 36 | 37 | public void setFakeViewLifecycleOwner(@Nullable LifecycleOwner lifecycleOwner) { 38 | fakeViewLifecycleOwner = lifecycleOwner; 39 | fakeViewLifecycleOwnerLiveData.postValue(lifecycleOwner); 40 | } 41 | 42 | @NonNull 43 | @Override 44 | public LifecycleOwner getViewLifecycleOwner() { 45 | return fakeViewLifecycleOwner; 46 | } 47 | 48 | @NonNull 49 | @Override 50 | public LiveData getViewLifecycleOwnerLiveData() { 51 | return fakeViewLifecycleOwnerLiveData; 52 | } 53 | 54 | @NonNull 55 | @Override 56 | public Lifecycle getLifecycle() { 57 | return fragmentLifecycleOwner.getLifecycle(); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /dispatch-internal-test-android/src/main/java/dispatch/internal/test/android/FakeLifecycle.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.internal.test.android 17 | 18 | import androidx.lifecycle.Lifecycle 19 | import androidx.lifecycle.LifecycleObserver 20 | import androidx.lifecycle.LifecycleRegistry 21 | import kotlinx.coroutines.channels.BufferOverflow 22 | import kotlinx.coroutines.flow.MutableSharedFlow 23 | 24 | class FakeLifecycle(lifecycleOwner: FakeLifecycleOwner) : Lifecycle() { 25 | 26 | val delegate = LifecycleRegistry(lifecycleOwner) 27 | 28 | val observerEvents = MutableSharedFlow( 29 | replay = 1, 30 | onBufferOverflow = BufferOverflow.DROP_OLDEST 31 | ) 32 | 33 | val observerCount: Int get() = delegate.observerCount 34 | 35 | sealed class ObserverEvent { 36 | abstract val observer: LifecycleObserver 37 | 38 | data class Add(override val observer: LifecycleObserver) : ObserverEvent() 39 | data class Remove(override val observer: LifecycleObserver) : ObserverEvent() 40 | } 41 | 42 | override fun addObserver(observer: LifecycleObserver) { 43 | delegate.addObserver(observer) 44 | observerEvents.tryEmit(ObserverEvent.Add(observer)) 45 | } 46 | 47 | override fun removeObserver(observer: LifecycleObserver) { 48 | delegate.removeObserver(observer) 49 | observerEvents.tryEmit(ObserverEvent.Remove(observer)) 50 | } 51 | 52 | override fun getCurrentState(): State = delegate.currentState 53 | fun setCurrentState(state: State) { 54 | delegate.currentState = state 55 | } 56 | 57 | fun handleLifecycleEvent(event: Event) { 58 | delegate.handleLifecycleEvent(event) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /dispatch-internal-test-android/src/main/java/dispatch/internal/test/android/InstantTaskExecutorExtension.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.internal.test.android 17 | 18 | import androidx.arch.core.executor.ArchTaskExecutor 19 | import androidx.arch.core.executor.TaskExecutor 20 | import org.junit.jupiter.api.extension.BeforeAllCallback 21 | import org.junit.jupiter.api.extension.ExtendWith 22 | import org.junit.jupiter.api.extension.ExtensionContext 23 | 24 | @ExtendWith(InstantTaskExecutorExtension::class) 25 | interface LiveDataTest 26 | 27 | @Suppress("RestrictedApi") 28 | class InstantTaskExecutorExtension : BeforeAllCallback { 29 | 30 | override fun beforeAll(context: ExtensionContext?) { 31 | ArchTaskExecutor.getInstance() 32 | .setDelegate(object : TaskExecutor() { 33 | override fun executeOnDiskIO(runnable: Runnable) { 34 | runnable.run() 35 | } 36 | 37 | override fun postToMainThread(runnable: Runnable) { 38 | runnable.run() 39 | } 40 | 41 | override fun isMainThread(): Boolean = true 42 | }) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /dispatch-internal-test/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | plugins { 17 | id("kotlinx-atomicfu") 18 | javaLibrary 19 | } 20 | 21 | dependencies { 22 | 23 | api(libs.junit.api) 24 | api(libs.junit.junit4) 25 | api(libs.junit.jupiter) 26 | api(libs.junit.vintage) 27 | api(libs.kotest.assertions) 28 | api(libs.kotest.assertionsShared) 29 | api(libs.kotest.common.jvm) 30 | api(libs.kotest.runner) 31 | api(libs.kotlin.reflect) 32 | api(libs.kotlin.test.common) 33 | api(libs.kotlin.test.core) 34 | api(libs.kotlinx.coroutines.core) 35 | api(libs.kotlinx.coroutines.jvm) 36 | api(libs.kotlinx.coroutines.test) 37 | api(libs.kotlinx.knit.test) 38 | 39 | api(projects.dispatchCore) 40 | } 41 | -------------------------------------------------------------------------------- /dispatch-internal-test/src/main/java/dispatch/internal/test/AtomicCounterExtension.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.internal.test 17 | 18 | import kotlinx.atomicfu.atomic 19 | import org.junit.jupiter.api.extension.AfterEachCallback 20 | import org.junit.jupiter.api.extension.ExtensionContext 21 | 22 | public class AtomicCounterExtension : AfterEachCallback { 23 | 24 | private val index = atomic(0) 25 | private val finished = atomic(false) 26 | 27 | public fun expect(expectedIndex: Int) { 28 | 29 | val actualIndex = index.incrementAndGet() 30 | 31 | assert(expectedIndex == actualIndex) { 32 | "Expecting action index $expectedIndex but it is actually $actualIndex" 33 | } 34 | } 35 | 36 | public fun finish(expectedIndex: Int) { 37 | expect(expectedIndex) 38 | assert(!finished.getAndSet(true)) { "Should call 'finish(...)' at most once" } 39 | } 40 | 41 | override fun afterEach(context: ExtensionContext?) { 42 | resetIndex() 43 | } 44 | 45 | public fun resetIndex() { 46 | assert(index.value == 0) { "Expecting that 'finish(...)' was invoked, but it was not" } 47 | index.value = 0 48 | finished.value = false 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /dispatch-internal-test/src/main/java/dispatch/internal/test/BaseTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.internal.test 17 | 18 | import io.kotest.matchers.shouldBe 19 | import kotlinx.atomicfu.atomic 20 | import org.junit.jupiter.api.AfterEach 21 | 22 | @Suppress("UnnecessaryAbstractClass") 23 | public abstract class BaseTest { 24 | 25 | private val index = atomic(0) 26 | private val finished = atomic(false) 27 | 28 | @AfterEach 29 | internal fun _afterEach() { 30 | resetIndex() 31 | } 32 | 33 | public fun expect(expectedIndex: Int) { 34 | 35 | val actualIndex = index.incrementAndGet() 36 | 37 | actualIndex shouldBe expectedIndex 38 | } 39 | 40 | public fun finish(expectedIndex: Int) { 41 | expect(expectedIndex) 42 | require(!finished.getAndSet(true)) { "Should call 'finish(...)' at most once" } 43 | } 44 | 45 | public fun resetIndex() { 46 | try { 47 | require(index.value == 0 || finished.value) { "Expecting that 'finish(...)' was invoked, but it was not" } 48 | } finally { 49 | index.value = 0 50 | finished.value = false 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /dispatch-internal-test/src/main/java/dispatch/internal/test/ExpectedFailureRule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.internal.test 17 | 18 | import io.kotest.matchers.shouldBe 19 | import org.junit.rules.TestRule 20 | import org.junit.runner.Description 21 | import org.junit.runners.model.Statement 22 | 23 | public class ExpectedFailureRule : TestRule { 24 | 25 | override fun apply( 26 | base: Statement, 27 | description: Description 28 | ): Statement = object : Statement() { 29 | 30 | override fun evaluate() { 31 | try { 32 | 33 | base.evaluate() 34 | } catch (e: Error) { 35 | 36 | val failsAnnotation = description.getAnnotation(Fails::class.java) 37 | 38 | if (failsAnnotation != null) { 39 | failsAnnotation.expected shouldBe e::class 40 | } else { 41 | throw e 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /dispatch-internal-test/src/main/java/dispatch/internal/test/Fails.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.internal.test 17 | 18 | import kotlin.reflect.KClass 19 | 20 | /** Indicates that a test **function** is expected to fail with the given exception type. */ 21 | @Target(AnnotationTarget.FUNCTION) 22 | public annotation class Fails( 23 | /** The KClass of the expected Throwable. */ 24 | val expected: KClass<*> 25 | ) 26 | -------------------------------------------------------------------------------- /dispatch-internal-test/src/main/java/dispatch/internal/test/reflect.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.internal.test 17 | 18 | import kotlin.reflect.full.memberProperties 19 | import kotlin.reflect.jvm.isAccessible 20 | 21 | public inline fun T.getPrivateObjectFieldByName( 22 | name: String 23 | ): R { 24 | 25 | val kClass = T::class 26 | 27 | val property = kClass.members.find { it.name == name } 28 | 29 | require(property != null) { "Cannot find a property named `$name` in ${kClass::qualifiedName}." } 30 | 31 | property.isAccessible = true 32 | 33 | return property.call() as R 34 | } 35 | 36 | public inline fun T.getPrivateFieldByName(name: String): R { 37 | 38 | val kClass = T::class 39 | 40 | val property = kClass.memberProperties.find { it.name == name } 41 | 42 | require(property != null) { "Cannot find a property named `$name` in ${kClass::qualifiedName}." } 43 | 44 | property.isAccessible = true 45 | 46 | return property.get(this) as R 47 | } 48 | -------------------------------------------------------------------------------- /dispatch-internal-test/src/test/java/dispatch/internal/test/AssertionsTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.internal.test 17 | 18 | import kotlinx.coroutines.Job 19 | import kotlinx.coroutines.SupervisorJob 20 | import kotlinx.coroutines.launch 21 | import kotlinx.coroutines.runBlocking 22 | import org.junit.jupiter.api.Nested 23 | import org.junit.jupiter.api.Test 24 | import kotlin.test.assertFails 25 | 26 | internal class AssertionsTest { 27 | 28 | @Nested 29 | inner class `should be SupervisorJob` { 30 | 31 | @Test 32 | fun `normal Job should fail`() { 33 | 34 | assertFails { Job().shouldBeSupervisorJob() } 35 | } 36 | 37 | @Test 38 | fun `SupervisorJob should pass`() { 39 | 40 | SupervisorJob().shouldBeSupervisorJob() 41 | } 42 | } 43 | 44 | @Nested 45 | inner class `should be or child of` { 46 | 47 | @Test 48 | fun `referential equality should pass`() { 49 | 50 | val job = Job() 51 | 52 | job shouldBeOrChildOf job 53 | } 54 | 55 | @Test 56 | fun `receiver job as child of parameter should pass`() = runBlocking a@{ 57 | 58 | launch b@{ 59 | this@b.coroutineContext[Job]!! shouldBeOrChildOf this@a.coroutineContext[Job]!! 60 | }.join() 61 | } 62 | 63 | @Test 64 | fun `parameter job as child of receiver should fail`() = runBlocking a@{ 65 | 66 | launch b@{ 67 | assertFails { 68 | this@a.coroutineContext[Job]!! shouldBeOrChildOf this@b.coroutineContext[Job]!! 69 | } 70 | } 71 | } 72 | 73 | @Test 74 | fun `unrelated jobs should fail`() { 75 | 76 | val a = Job() 77 | val b = Job() 78 | 79 | assertFails { a shouldBeOrChildOf b } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /dispatch-sample/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | plugins { 17 | id("com.android.application") 18 | kotlin("android") 19 | id("kotlin-parcelize") 20 | } 21 | 22 | android { 23 | commonAndroid(project) 24 | 25 | @Suppress("UnstableApiUsage") 26 | buildFeatures.viewBinding = true 27 | } 28 | 29 | dependencies { 30 | 31 | androidTestImplementation(libs.androidx.test.espresso.core) 32 | androidTestImplementation(libs.androidx.test.runner) 33 | 34 | api(projects.dispatchCore) 35 | 36 | implementation(libs.androidx.activity.ktx) 37 | implementation(libs.androidx.appcompat) 38 | implementation(libs.androidx.constraintLayout) 39 | implementation(libs.androidx.coreKtx) 40 | implementation(libs.androidx.fragment.ktx) 41 | implementation(libs.androidx.lifecycle.common) 42 | implementation(libs.kotlinx.coroutines.android) 43 | implementation(libs.kotlinx.coroutines.core) 44 | implementation(libs.timber) 45 | 46 | implementation(projects.dispatchAndroidLifecycle) 47 | 48 | testImplementation(libs.junit.junit4) 49 | testImplementation(libs.junit.jupiter) 50 | testImplementation(libs.kotest.assertions) 51 | testImplementation(libs.kotest.properties) 52 | testImplementation(libs.kotest.runner) 53 | testImplementation(libs.kotlinx.coroutines.test) 54 | } 55 | -------------------------------------------------------------------------------- /dispatch-sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 18 | 19 | 26 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /dispatch-sample/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RBusarow/Dispatch/4b231ef18802c064375eee7a58326f8283794dcd/dispatch-sample/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /dispatch-sample/src/main/java/dispatch/sample/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.sample 17 | 18 | import android.os.Bundle 19 | import androidx.appcompat.app.AppCompatActivity 20 | import dispatch.sample.databinding.ActivityMainBinding 21 | import kotlinx.coroutines.ExperimentalCoroutinesApi 22 | import timber.log.Timber 23 | 24 | @ExperimentalCoroutinesApi 25 | class MainActivity : AppCompatActivity() { 26 | 27 | override fun onCreate(savedInstanceState: Bundle?) { 28 | super.onCreate(savedInstanceState) 29 | setContentView(ActivityMainBinding.inflate(layoutInflater).root) 30 | 31 | Timber.plant(Timber.DebugTree()) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /dispatch-sample/src/main/java/dispatch/sample/MainViewModel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.sample 17 | 18 | import androidx.lifecycle.ViewModel 19 | import dispatch.core.DefaultCoroutineScope 20 | import dispatch.core.defaultDispatcher 21 | import kotlinx.coroutines.CompletableDeferred 22 | import kotlinx.coroutines.Deferred 23 | import kotlinx.coroutines.ExperimentalCoroutinesApi 24 | import kotlinx.coroutines.cancel 25 | import kotlinx.coroutines.delay 26 | import kotlinx.coroutines.flow.flow 27 | import kotlinx.coroutines.flow.flowOn 28 | import kotlinx.coroutines.launch 29 | 30 | @ExperimentalCoroutinesApi 31 | class MainViewModel( 32 | val coroutineScope: DefaultCoroutineScope, 33 | val repository: SomeRepository 34 | ) : ViewModel() { 35 | 36 | val expensiveDeferred: Deferred = repository.getSomethingExpensiveUnstructured() 37 | 38 | val alsoExpensiveDeferred: Deferred by lazy { 39 | CompletableDeferred().also { completable -> 40 | 41 | // this no-arg launch will use the default CoroutineDispatcher in the CoroutineScope, 42 | // which in this case is dispatcherProvider.default 43 | coroutineScope.launch { 44 | val expensive = repository.getSomethingExpensive() 45 | completable.complete(expensive) 46 | } 47 | } 48 | } 49 | 50 | val message = flow { 51 | 52 | emit("Get ready for some coroutine stuff...") 53 | 54 | emit(expensiveDeferred.await()) 55 | 56 | emit(alsoExpensiveDeferred.await()) 57 | 58 | @Suppress("MagicNumber") 59 | delay(5000) 60 | 61 | // explicitly specify the default dispatcher (which is redundant here, but it's an example) 62 | }.flowOn(coroutineScope.defaultDispatcher) 63 | 64 | override fun onCleared() { 65 | super.onCleared() 66 | 67 | coroutineScope.cancel() 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /dispatch-sample/src/main/java/dispatch/sample/SomeRepository.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.sample 17 | 18 | import dispatch.core.IOCoroutineScope 19 | import dispatch.core.asyncIO 20 | import dispatch.core.withIO 21 | import kotlinx.coroutines.delay 22 | 23 | /** 24 | * This would normally be a singleton, but we don't have a DI framework here, so we'll just 25 | * _suspend_ disbelief. 26 | */ 27 | class SomeRepository(private val coroutineScope: IOCoroutineScope) { 28 | 29 | @Suppress("MagicNumber") 30 | suspend fun getSomethingExpensive() = withIO { 31 | delay(5000) 32 | "suspend function is complete!" 33 | } 34 | 35 | @Suppress("MagicNumber") 36 | fun getSomethingExpensiveUnstructured() = coroutineScope.asyncIO { 37 | delay(5000) 38 | "deferred function is complete!" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /dispatch-sample/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 15 | 16 | 21 | 22 | 32 | 33 | -------------------------------------------------------------------------------- /dispatch-sample/src/main/res/layout/fragment_main.xml: -------------------------------------------------------------------------------- 1 | 15 | 16 | 21 | 22 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /dispatch-sample/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /dispatch-sample/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /dispatch-sample/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RBusarow/Dispatch/4b231ef18802c064375eee7a58326f8283794dcd/dispatch-sample/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /dispatch-sample/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RBusarow/Dispatch/4b231ef18802c064375eee7a58326f8283794dcd/dispatch-sample/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /dispatch-sample/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RBusarow/Dispatch/4b231ef18802c064375eee7a58326f8283794dcd/dispatch-sample/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /dispatch-sample/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RBusarow/Dispatch/4b231ef18802c064375eee7a58326f8283794dcd/dispatch-sample/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /dispatch-sample/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RBusarow/Dispatch/4b231ef18802c064375eee7a58326f8283794dcd/dispatch-sample/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /dispatch-sample/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RBusarow/Dispatch/4b231ef18802c064375eee7a58326f8283794dcd/dispatch-sample/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /dispatch-sample/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RBusarow/Dispatch/4b231ef18802c064375eee7a58326f8283794dcd/dispatch-sample/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /dispatch-sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RBusarow/Dispatch/4b231ef18802c064375eee7a58326f8283794dcd/dispatch-sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /dispatch-sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RBusarow/Dispatch/4b231ef18802c064375eee7a58326f8283794dcd/dispatch-sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /dispatch-sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RBusarow/Dispatch/4b231ef18802c064375eee7a58326f8283794dcd/dispatch-sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /dispatch-sample/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | #3D92FC 19 | #102572 20 | #0151DB 21 | 22 | -------------------------------------------------------------------------------- /dispatch-sample/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | #38DA00 19 | 20 | -------------------------------------------------------------------------------- /dispatch-sample/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 | Dispatch Sample 18 | 19 | -------------------------------------------------------------------------------- /dispatch-sample/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 | 18 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /dispatch-test-junit4/api/dispatch-test-junit4.api: -------------------------------------------------------------------------------- 1 | public final class dispatch/test/TestCoroutineRule : org/junit/rules/TestWatcher, dispatch/test/TestProvidedCoroutineScope { 2 | public fun ()V 3 | public fun (Lkotlin/jvm/functions/Function0;)V 4 | public synthetic fun (Lkotlin/jvm/functions/Function0;ILkotlin/jvm/internal/DefaultConstructorMarker;)V 5 | public fun advanceTimeBy (J)J 6 | public fun advanceUntilIdle ()J 7 | public fun cleanupTestCoroutines ()V 8 | public fun getCoroutineContext ()Lkotlin/coroutines/CoroutineContext; 9 | public fun getCurrentTime ()J 10 | public final fun getDispatcher ()Lkotlinx/coroutines/test/TestCoroutineDispatcher; 11 | public fun getDispatcherProvider ()Ldispatch/core/DispatcherProvider; 12 | public fun getUncaughtExceptions ()Ljava/util/List; 13 | public fun pauseDispatcher ()V 14 | public fun pauseDispatcher (Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; 15 | public fun resumeDispatcher ()V 16 | public fun runCurrent ()V 17 | } 18 | 19 | -------------------------------------------------------------------------------- /dispatch-test-junit4/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | plugins { 17 | id("kotlinx-atomicfu") 18 | javaLibrary 19 | published 20 | } 21 | 22 | dependencies { 23 | 24 | api(libs.junit.junit4) 25 | api(libs.kotlinx.coroutines.test) 26 | 27 | api(projects.dispatchTest) 28 | 29 | implementation(libs.kotlinx.coroutines.core) 30 | implementation(libs.kotlinx.coroutines.jvm) 31 | 32 | testImplementation(libs.kotest.assertions) 33 | testImplementation(libs.kotest.properties) 34 | testImplementation(libs.kotest.runner) 35 | testImplementation(libs.kotlin.test.common) 36 | testImplementation(libs.kotlin.test.core) 37 | testImplementation(libs.mockk) 38 | 39 | testImplementation(projects.dispatchCore) 40 | testImplementation(projects.dispatchInternalTest) 41 | } 42 | -------------------------------------------------------------------------------- /dispatch-test-junit4/dependencies/runtimeClasspath.txt: -------------------------------------------------------------------------------- 1 | junit:junit:4.13.2 2 | net.java.dev.jna:jna-platform:5.5.0 3 | net.java.dev.jna:jna:5.5.0 4 | org.hamcrest:hamcrest-core:1.3 5 | org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10 6 | org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.10 7 | org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10 8 | org.jetbrains.kotlin:kotlin-stdlib:1.7.10 9 | org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2 10 | org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2 11 | org.jetbrains.kotlinx:kotlinx-coroutines-debug:1.5.2 12 | org.jetbrains.kotlinx:kotlinx-coroutines-test:1.5.2 13 | org.jetbrains:annotations:13.0 14 | -------------------------------------------------------------------------------- /dispatch-test-junit4/gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2021 Rick Busarow 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | POM_ARTIFACT_ID=dispatch-test-junit4 16 | POM_NAME=dispatch-test-junit4 17 | POM_PACKAGING=jar 18 | -------------------------------------------------------------------------------- /dispatch-test-junit4/src/test/kotlin/dispatch/core/test/samples/TestCoroutineRuleSample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.core.test.samples 17 | 18 | import dispatch.test.TestCoroutineRule 19 | import dispatch.test.TestProvidedCoroutineScope 20 | import io.kotest.matchers.types.shouldBeInstanceOf 21 | import kotlinx.coroutines.ExperimentalCoroutinesApi 22 | import kotlinx.coroutines.launch 23 | import kotlinx.coroutines.runBlocking 24 | import org.junit.Rule 25 | import org.junit.Test 26 | 27 | @ExperimentalCoroutinesApi 28 | class TestCoroutineRuleSample { 29 | 30 | @JvmField 31 | @Rule 32 | val rule = TestCoroutineRule() 33 | 34 | @Test 35 | fun `rule should be a TestProvidedCoroutineScope`() = runBlocking { 36 | 37 | rule.shouldBeInstanceOf() 38 | 39 | rule.launch { 40 | // use the rule like any other CoroutineScope 41 | } 42 | .join() 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /dispatch-test-junit4/src/test/kotlin/dispatch/core/test/samples/TestCoroutineRuleWithFactorySample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.core.test.samples 17 | 18 | import dispatch.test.TestCoroutineRule 19 | import dispatch.test.TestProvidedCoroutineScope 20 | import io.kotest.matchers.shouldBe 21 | import io.kotest.matchers.types.shouldBeInstanceOf 22 | import kotlinx.coroutines.CoroutineName 23 | import kotlinx.coroutines.ExperimentalCoroutinesApi 24 | import kotlinx.coroutines.launch 25 | import kotlinx.coroutines.runBlocking 26 | import org.junit.Rule 27 | import org.junit.jupiter.api.Test 28 | 29 | @ExperimentalCoroutinesApi 30 | class TestCoroutineRuleWithFactorySample { 31 | 32 | val customScope = TestProvidedCoroutineScope( 33 | context = CoroutineName("custom name") 34 | ) 35 | 36 | @JvmField 37 | @Rule 38 | val rule = TestCoroutineRule { customScope } 39 | 40 | @Test 41 | fun `rule should be a TestProvidedCoroutineScope`() = runBlocking { 42 | 43 | rule.shouldBeInstanceOf() 44 | 45 | rule.launch { 46 | // use the rule like any other CoroutineScope 47 | } 48 | .join() 49 | } 50 | 51 | @Test 52 | fun `rule should be the provided custom scope`() = runBlocking { 53 | 54 | val context = rule.coroutineContext 55 | 56 | context shouldBe customScope.coroutineContext 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /dispatch-test-junit5/api/dispatch-test-junit5.api: -------------------------------------------------------------------------------- 1 | public abstract interface annotation class dispatch/test/CoroutineTest : java/lang/annotation/Annotation { 2 | public abstract fun scopeFactory ()Ljava/lang/Class; 3 | } 4 | 5 | public final class dispatch/test/CoroutineTestExtension : org/junit/jupiter/api/extension/support/TypeBasedParameterResolver, org/junit/jupiter/api/extension/AfterEachCallback, org/junit/jupiter/api/extension/BeforeEachCallback { 6 | public fun ()V 7 | public fun (Ldispatch/test/CoroutineTestExtension$ScopeFactory;)V 8 | public synthetic fun (Ldispatch/test/CoroutineTestExtension$ScopeFactory;ILkotlin/jvm/internal/DefaultConstructorMarker;)V 9 | public fun afterEach (Lorg/junit/jupiter/api/extension/ExtensionContext;)V 10 | public fun beforeEach (Lorg/junit/jupiter/api/extension/ExtensionContext;)V 11 | public final fun getScope ()Ldispatch/test/TestProvidedCoroutineScope; 12 | public fun resolveParameter (Lorg/junit/jupiter/api/extension/ParameterContext;Lorg/junit/jupiter/api/extension/ExtensionContext;)Ldispatch/test/TestProvidedCoroutineScope; 13 | public synthetic fun resolveParameter (Lorg/junit/jupiter/api/extension/ParameterContext;Lorg/junit/jupiter/api/extension/ExtensionContext;)Ljava/lang/Object; 14 | } 15 | 16 | public class dispatch/test/CoroutineTestExtension$ScopeFactory { 17 | public fun ()V 18 | public fun create ()Ldispatch/test/TestProvidedCoroutineScope; 19 | } 20 | 21 | public final class dispatch/test/CoroutineTestExtensionKt { 22 | public static final fun coroutineTestExtension (Lkotlin/jvm/functions/Function0;)Ldispatch/test/CoroutineTestExtension; 23 | public static synthetic fun coroutineTestExtension$default (Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Ldispatch/test/CoroutineTestExtension; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /dispatch-test-junit5/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | plugins { 17 | id("kotlinx-atomicfu") 18 | javaLibrary 19 | published 20 | } 21 | 22 | dependencies { 23 | 24 | api(libs.junit.api) 25 | 26 | api(projects.dispatchTest) 27 | 28 | implementation(libs.junit.jupiter) 29 | implementation(libs.kotlin.reflect) 30 | implementation(libs.kotlinx.coroutines.core) 31 | implementation(libs.kotlinx.coroutines.jvm) 32 | implementation(libs.kotlinx.coroutines.test) 33 | 34 | testImplementation(libs.kotest.assertions) 35 | testImplementation(libs.kotest.properties) 36 | testImplementation(libs.kotest.runner) 37 | testImplementation(libs.kotlin.test.common) 38 | testImplementation(libs.kotlin.test.core) 39 | testImplementation(libs.mockk) 40 | 41 | testImplementation(projects.dispatchCore) 42 | testImplementation(projects.dispatchInternalTest) 43 | } 44 | -------------------------------------------------------------------------------- /dispatch-test-junit5/dependencies/runtimeClasspath.txt: -------------------------------------------------------------------------------- 1 | net.java.dev.jna:jna-platform:5.5.0 2 | net.java.dev.jna:jna:5.5.0 3 | org.jetbrains.kotlin:kotlin-reflect:1.7.10 4 | org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10 5 | org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.10 6 | org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10 7 | org.jetbrains.kotlin:kotlin-stdlib:1.7.10 8 | org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2 9 | org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2 10 | org.jetbrains.kotlinx:kotlinx-coroutines-debug:1.5.2 11 | org.jetbrains.kotlinx:kotlinx-coroutines-test:1.5.2 12 | org.jetbrains:annotations:13.0 13 | org.junit.jupiter:junit-jupiter-api:5.9.0 14 | org.junit.jupiter:junit-jupiter-engine:5.9.0 15 | org.junit.jupiter:junit-jupiter-params:5.9.0 16 | org.junit.jupiter:junit-jupiter:5.9.0 17 | org.junit.platform:junit-platform-commons:1.9.0 18 | org.junit.platform:junit-platform-engine:1.9.0 19 | org.junit:junit-bom:5.9.0 20 | org.opentest4j:opentest4j:1.2.0 21 | -------------------------------------------------------------------------------- /dispatch-test-junit5/gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2021 Rick Busarow 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | POM_ARTIFACT_ID=dispatch-test-junit5 16 | POM_NAME=dispatch-test-junit5 17 | POM_PACKAGING=jar 18 | -------------------------------------------------------------------------------- /dispatch-test-junit5/src/main/java/dispatch/test/CoroutineTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.test 17 | 18 | import kotlinx.coroutines.ExperimentalCoroutinesApi 19 | import org.junit.jupiter.api.extension.ExtendWith 20 | import kotlin.reflect.KClass 21 | 22 | /** 23 | * Annotation for specifying a custom [CoroutineTestExtension.ScopeFactory] while extending a test 24 | * class or function with [CoroutineTestExtension]. 25 | * 26 | * @property scopeFactory *optional* KClass which extends [CoroutineTestExtension.ScopeFactory]. 27 | * **This class must have a default constructor** An instance will 28 | * be automatically initialized inside the [CoroutineTestExtension] 29 | * and used to create custom [TestProvidedCoroutineScope] instances. 30 | * @sample dispatch.test.samples.CoroutineTestDefaultFactorySample 31 | * @sample dispatch.test.samples.CoroutineTestNamedFactorySample 32 | * @see CoroutineTestExtension 33 | */ 34 | @ExperimentalCoroutinesApi 35 | @ExtendWith(CoroutineTestExtension::class) 36 | public annotation class CoroutineTest( 37 | val scopeFactory: KClass<*> = CoroutineTestExtension.ScopeFactory::class 38 | ) 39 | -------------------------------------------------------------------------------- /dispatch-test-junit5/src/main/java/dispatch/test/internal/ResetManager.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.test.internal 17 | 18 | internal class LazyResets( 19 | private val resetManager: ResetManager, 20 | private val valueFactory: () -> T 21 | ) : Lazy, 22 | Resets { 23 | 24 | private var lazyHolder: Lazy = createLazy() 25 | 26 | override val value: T 27 | get() = lazyHolder.value 28 | 29 | override fun isInitialized(): Boolean = lazyHolder.isInitialized() 30 | 31 | private fun createLazy() = lazy { 32 | resetManager.register(this) 33 | valueFactory() 34 | } 35 | 36 | override fun reset() { 37 | lazyHolder = createLazy() 38 | } 39 | } 40 | 41 | internal interface Resets { 42 | fun reset() 43 | } 44 | 45 | internal class ResetManager( 46 | private val delegates: MutableCollection = mutableListOf() 47 | ) { 48 | 49 | fun register(delegate: Resets) { 50 | synchronized(delegates) { 51 | delegates.add(delegate) 52 | } 53 | } 54 | 55 | fun resetAll() { 56 | synchronized(delegates) { 57 | delegates.forEach { it.reset() } 58 | delegates.clear() 59 | } 60 | } 61 | } 62 | 63 | internal inline fun ResetManager.resets( 64 | noinline valueFactory: () -> T 65 | ): LazyResets = LazyResets(this, valueFactory) 66 | -------------------------------------------------------------------------------- /dispatch-test-junit5/src/main/java/dispatch/test/internal/reflect.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.test.internal 17 | 18 | import org.junit.jupiter.api.extension.ExtensionContext 19 | import java.lang.reflect.AnnotatedElement 20 | import java.lang.reflect.Parameter 21 | 22 | internal inline fun ExtensionContext.getAnnotationRecursive(): T? { 23 | 24 | return this.elementOrNull() 25 | ?.getAnnotation(T::class.java) ?: parentOrNull()?.getAnnotationRecursive(T::class.java) 26 | } 27 | 28 | internal fun ExtensionContext.getAnnotationRecursive(aClass: Class): T? { 29 | 30 | return this.elementOrNull() 31 | ?.getAnnotation(aClass) ?: parentOrNull()?.getAnnotationRecursive(aClass) 32 | } 33 | 34 | @Suppress("NewApi") 35 | internal fun ExtensionContext.elementOrNull(): AnnotatedElement? = if (element.isPresent) { 36 | element.get() 37 | } else { 38 | null 39 | } 40 | 41 | @Suppress("NewApi") 42 | internal inline fun Parameter.annotationOrNull(): T? = 43 | getAnnotation(T::class.java) ?: null 44 | 45 | @Suppress("NewApi") 46 | internal fun ExtensionContext.parentOrNull(): ExtensionContext? = if (parent.isPresent) { 47 | parent.get() 48 | } else { 49 | null 50 | } 51 | -------------------------------------------------------------------------------- /dispatch-test-junit5/src/main/java/dispatch/test/internal/resolutionException.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.test.internal 17 | 18 | import dispatch.test.CoroutineTest 19 | import dispatch.test.CoroutineTestExtension 20 | import kotlinx.coroutines.ExperimentalCoroutinesApi 21 | import org.junit.jupiter.api.extension.ParameterResolutionException 22 | import kotlin.reflect.KClass 23 | 24 | @ExperimentalCoroutinesApi 25 | internal fun resolutionException(factoryClass: KClass<*>): ParameterResolutionException { 26 | return ParameterResolutionException( 27 | """A ${CoroutineTest::class.simpleName} annotation was found with an incompatible factory type. 28 | | 29 | |The specified factory must be <${CoroutineTestExtension.ScopeFactory::class.qualifiedName}> or a subtype. 30 | | 31 | |The provided factory type was: <${factoryClass.qualifiedName}> 32 | | 33 | """.trimMargin() 34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /dispatch-test-junit5/src/test/kotlin/dispatch/test/CoroutineTestExtensionInjectionTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.test 17 | 18 | import io.kotest.matchers.shouldNotBe 19 | import kotlinx.coroutines.ExperimentalCoroutinesApi 20 | import org.junit.jupiter.api.BeforeAll 21 | import org.junit.jupiter.api.BeforeEach 22 | import org.junit.jupiter.api.Nested 23 | import org.junit.jupiter.api.Test 24 | import org.junit.jupiter.api.extension.RegisterExtension 25 | 26 | @ExperimentalCoroutinesApi 27 | class CoroutineTestExtensionInjectionTest { 28 | 29 | @JvmField @RegisterExtension 30 | val extension = CoroutineTestExtension() 31 | 32 | @Nested 33 | inner class `nested classes` { 34 | 35 | @Test 36 | fun `function arguments should be automatically injected`(scope: TestProvidedCoroutineScope) { 37 | 38 | scope shouldNotBe null 39 | } 40 | } 41 | 42 | @Nested 43 | inner class `lifecycle callback functions` { 44 | 45 | var beforeAllInjectedScope: TestProvidedCoroutineScope? = null 46 | var beforeEachInjectedScope: TestProvidedCoroutineScope? = null 47 | 48 | @BeforeAll 49 | fun beforeAll(scope: TestProvidedCoroutineScope) { 50 | beforeAllInjectedScope = scope 51 | } 52 | 53 | @BeforeEach 54 | fun beforeEach(scope: TestProvidedCoroutineScope) { 55 | beforeEachInjectedScope = scope 56 | } 57 | 58 | @Test 59 | fun `beforeAll should be injected before a function is called`() { 60 | 61 | beforeAllInjectedScope shouldNotBe null 62 | } 63 | 64 | @Test 65 | fun `beforeEach should be injected before a function is called`() { 66 | 67 | beforeEachInjectedScope shouldNotBe null 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /dispatch-test-junit5/src/test/kotlin/dispatch/test/SetMainTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.test 17 | 18 | import io.kotest.matchers.shouldBe 19 | import kotlinx.coroutines.Dispatchers 20 | import kotlinx.coroutines.ExperimentalCoroutinesApi 21 | import kotlinx.coroutines.test.setMain 22 | import org.junit.jupiter.api.Nested 23 | import org.junit.jupiter.api.Test 24 | import org.junit.jupiter.api.extension.RegisterExtension 25 | 26 | @Suppress("HardCodedDispatcher") 27 | @ExperimentalCoroutinesApi 28 | class SetMainTest { 29 | 30 | @RegisterExtension @JvmField 31 | val ext = CoroutineTestExtension() 32 | 33 | @Test 34 | fun `extension's internal scope's dispatcher should be set as Main by default`() { 35 | 36 | val beforeSet = Dispatchers.Main 37 | 38 | Dispatchers.setMain(ext.scope.dispatcherProvider.main) 39 | 40 | beforeSet shouldBe Dispatchers.Main 41 | } 42 | 43 | @Test 44 | fun `function injected scope's dispatcher should be set as Main by default`( 45 | scope: TestProvidedCoroutineScope 46 | ) { 47 | 48 | val beforeSet = Dispatchers.Main 49 | 50 | Dispatchers.setMain(scope.dispatcherProvider.main) 51 | 52 | beforeSet shouldBe Dispatchers.Main 53 | } 54 | 55 | @Nested 56 | inner class `constructor injection`( 57 | val scope: TestProvidedCoroutineScope 58 | ) { 59 | 60 | @Test 61 | fun `constructor injected scope's dispatcher should be set as Main by default`() { 62 | 63 | val beforeSet = Dispatchers.Main 64 | 65 | Dispatchers.setMain(scope.dispatcherProvider.main) 66 | 67 | beforeSet shouldBe Dispatchers.Main 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /dispatch-test-junit5/src/test/kotlin/dispatch/test/samples/CoroutineTestDefaultFactorySample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | @file:OptIn(ExperimentalCoroutinesApi::class) 17 | 18 | package dispatch.test.samples 19 | 20 | import dispatch.test.CoroutineTest 21 | import dispatch.test.TestProvidedCoroutineScope 22 | import io.kotest.matchers.shouldBe 23 | import kotlinx.coroutines.ExperimentalCoroutinesApi 24 | import kotlinx.coroutines.runBlocking 25 | import org.junit.jupiter.api.Test 26 | 27 | @CoroutineTest 28 | class CoroutineTestDefaultFactorySample( 29 | val testScope: TestProvidedCoroutineScope 30 | ) { 31 | 32 | @Test 33 | fun `extension should automatically inject into test class`() = runBlocking { 34 | 35 | val subject = SomeClass(testScope) 36 | 37 | val resultDeferred = subject.someFunction() 38 | 39 | testScope.advanceUntilIdle() 40 | 41 | resultDeferred.await() shouldBe someValue 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /dispatch-test-junit5/src/test/kotlin/dispatch/test/samples/CoroutineTestExtensionExtendWithSample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | @file:OptIn(ExperimentalCoroutinesApi::class) 17 | 18 | package dispatch.test.samples 19 | 20 | import dispatch.test.CoroutineTestExtension 21 | import dispatch.test.TestProvidedCoroutineScope 22 | import io.kotest.matchers.shouldNotBe 23 | import kotlinx.coroutines.ExperimentalCoroutinesApi 24 | import org.junit.jupiter.api.Test 25 | import org.junit.jupiter.api.extension.ExtendWith 26 | 27 | @ExtendWith(CoroutineTestExtension::class) 28 | class CoroutineTestExtensionExtendWithSample( 29 | val testScope: TestProvidedCoroutineScope 30 | ) { 31 | 32 | @Test 33 | fun `injected scope should be injected`() { 34 | 35 | testScope shouldNotBe null 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /dispatch-test-junit5/src/test/kotlin/dispatch/test/samples/CoroutineTestNamedFactorySample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | @file:OptIn(ExperimentalCoroutinesApi::class) 17 | 18 | package dispatch.test.samples 19 | 20 | import dispatch.test.CoroutineTest 21 | import dispatch.test.CoroutineTestExtension 22 | import dispatch.test.TestProvidedCoroutineScope 23 | import io.kotest.matchers.shouldNotBe 24 | import kotlinx.coroutines.ExperimentalCoroutinesApi 25 | import kotlinx.coroutines.Job 26 | import kotlinx.coroutines.runBlocking 27 | import org.junit.jupiter.api.Test 28 | 29 | class CoroutineTestNamedFactorySample { 30 | 31 | class TestCoroutineScopeWithJobFactory : CoroutineTestExtension.ScopeFactory() { 32 | 33 | override fun create(): TestProvidedCoroutineScope { 34 | return TestProvidedCoroutineScope(context = Job()) 35 | } 36 | } 37 | 38 | @CoroutineTest(TestCoroutineScopeWithJobFactory::class) 39 | class CustomFactorySample(val testScope: TestProvidedCoroutineScope) { 40 | 41 | @Test 42 | fun `injected scope should have a Job context`() = runBlocking { 43 | 44 | testScope.coroutineContext[Job] shouldNotBe null 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /dispatch-test-junit5/src/test/kotlin/dispatch/test/samples/RegisterSample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | @file:OptIn(ExperimentalCoroutinesApi::class) 17 | 18 | package dispatch.test.samples 19 | 20 | import dispatch.test.TestProvidedCoroutineScope 21 | import dispatch.test.coroutineTestExtension 22 | import io.kotest.matchers.shouldBe 23 | import io.kotest.matchers.types.shouldBeInstanceOf 24 | import kotlinx.coroutines.ExperimentalCoroutinesApi 25 | import kotlinx.coroutines.runBlocking 26 | import org.junit.jupiter.api.Test 27 | import org.junit.jupiter.api.extension.RegisterExtension 28 | 29 | class RegisterSample { 30 | 31 | @JvmField 32 | @RegisterExtension 33 | val extension = coroutineTestExtension() 34 | 35 | @Test 36 | fun `extension should be a TestProvidedCoroutineScope`() = runBlocking { 37 | 38 | extension.scope.shouldBeInstanceOf() 39 | } 40 | 41 | @Test 42 | fun `extension should automatically inject into functions`(scope: TestProvidedCoroutineScope) = 43 | runBlocking { 44 | 45 | val subject = SomeClass(scope) 46 | 47 | val resultDeferred = subject.someFunction() 48 | 49 | scope.advanceUntilIdle() 50 | 51 | resultDeferred.await() shouldBe someValue 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /dispatch-test-junit5/src/test/kotlin/dispatch/test/samples/RegisterWithFactorySample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | @file:OptIn(ExperimentalCoroutinesApi::class) 17 | 18 | package dispatch.test.samples 19 | 20 | import dispatch.test.TestProvidedCoroutineScope 21 | import dispatch.test.coroutineTestExtension 22 | import io.kotest.matchers.shouldBe 23 | import kotlinx.coroutines.CoroutineName 24 | import kotlinx.coroutines.ExperimentalCoroutinesApi 25 | import kotlinx.coroutines.runBlocking 26 | import org.junit.jupiter.api.Test 27 | import org.junit.jupiter.api.extension.RegisterExtension 28 | 29 | class RegisterWithFactorySample { 30 | 31 | @JvmField 32 | @RegisterExtension 33 | val extension = coroutineTestExtension { 34 | TestProvidedCoroutineScope(context = CoroutineName("custom name")) 35 | } 36 | 37 | @Test 38 | fun `extension should provide a scope from the custom factory`() = runBlocking { 39 | 40 | extension.scope.coroutineContext[CoroutineName] shouldBe CoroutineName("custom name") 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /dispatch-test-junit5/src/test/kotlin/dispatch/test/samples/utils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.test.samples 17 | 18 | import kotlinx.coroutines.CoroutineScope 19 | import kotlinx.coroutines.Deferred 20 | import kotlinx.coroutines.async 21 | 22 | @Suppress("TopLevelPropertyNaming") 23 | public const val someValue: Boolean = true 24 | 25 | public class SomeClass(public val coroutineScope: CoroutineScope) { 26 | 27 | public fun someFunction(): Deferred = coroutineScope.async { true } 28 | } 29 | -------------------------------------------------------------------------------- /dispatch-test/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /dispatch-test/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | plugins { 17 | id("kotlinx-atomicfu") 18 | javaLibrary 19 | published 20 | } 21 | 22 | dependencies { 23 | 24 | api(libs.kotlinx.coroutines.core) 25 | api(libs.kotlinx.coroutines.jvm) 26 | api(libs.kotlinx.coroutines.test) 27 | 28 | api(projects.dispatchCore) 29 | 30 | testImplementation(libs.junit.api) 31 | testImplementation(libs.kotest.assertions) 32 | testImplementation(libs.kotest.properties) 33 | testImplementation(libs.kotest.runner) 34 | testImplementation(libs.kotlin.test.common) 35 | testImplementation(libs.kotlin.test.core) 36 | testImplementation(libs.mockk) 37 | 38 | testImplementation(projects.dispatchInternalTest) 39 | 40 | testRuntimeOnly(libs.junit.jupiter) 41 | } 42 | -------------------------------------------------------------------------------- /dispatch-test/dependencies/runtimeClasspath.txt: -------------------------------------------------------------------------------- 1 | net.java.dev.jna:jna-platform:5.5.0 2 | net.java.dev.jna:jna:5.5.0 3 | org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10 4 | org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.10 5 | org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10 6 | org.jetbrains.kotlin:kotlin-stdlib:1.7.10 7 | org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2 8 | org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2 9 | org.jetbrains.kotlinx:kotlinx-coroutines-debug:1.5.2 10 | org.jetbrains.kotlinx:kotlinx-coroutines-test:1.5.2 11 | org.jetbrains:annotations:13.0 12 | -------------------------------------------------------------------------------- /dispatch-test/gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2021 Rick Busarow 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | POM_ARTIFACT_ID=dispatch-test 16 | POM_NAME=dispatch-test 17 | POM_PACKAGING=jar 18 | -------------------------------------------------------------------------------- /dispatch-test/src/main/java/dispatch/test/defaultDispatcherProvider.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.test 17 | 18 | import dispatch.core.DefaultDispatcherProvider 19 | import dispatch.core.DispatcherProvider 20 | 21 | /** 22 | * Resets the singleton [DispatcherProvider] instance to the true default. This default instance 23 | * delegates to the [Dispatchers][kotlinx.coroutines.Dispatchers] singleton object properties. 24 | * 25 | * @see DefaultDispatcherProvider 26 | * @sample dispatch.test.samples.DefaultDispatcherProviderExtensionSample.resetSample 27 | */ 28 | @Suppress("unused") 29 | public fun DefaultDispatcherProvider.reset() { 30 | set(object : DispatcherProvider {}) 31 | } 32 | -------------------------------------------------------------------------------- /dispatch-test/src/test/kotlin/dispatch/test/samples/BuildersSample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.test.samples 17 | 18 | import dispatch.internal.test.Sample5 19 | import dispatch.test.TestProvidedCoroutineScope 20 | import dispatch.test.runBlockingProvided 21 | import dispatch.test.testProvided 22 | import io.kotest.matchers.shouldBe 23 | import kotlinx.coroutines.ExperimentalCoroutinesApi 24 | import org.junit.jupiter.api.Test 25 | 26 | @ExperimentalCoroutinesApi 27 | class BuildersSample { 28 | 29 | @Sample5 30 | fun runBlockingProvidedSample() { 31 | 32 | @Test 33 | fun someTest() = runBlockingProvided { 34 | 35 | val subject = SomeClass(this) 36 | 37 | val myData = Data() 38 | 39 | subject.dataDeferred() 40 | .await() shouldBe myData 41 | } 42 | } 43 | 44 | @Sample5 45 | fun testProvidedSample() { 46 | 47 | @Test 48 | fun someTest() = testProvided { 49 | 50 | val subject = SomeClass(this) 51 | 52 | val myData = Data() 53 | 54 | subject.dataDeferred() 55 | .await() shouldBe myData 56 | } 57 | } 58 | 59 | @Sample5 60 | fun testProvidedExtensionSample() { 61 | 62 | val scope = TestProvidedCoroutineScope() 63 | 64 | @Test 65 | fun someTest() = scope.testProvided { 66 | 67 | val subject = SomeClass(this) 68 | 69 | val myData = Data() 70 | 71 | subject.dataDeferred() 72 | .await() shouldBe myData 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /dispatch-test/src/test/kotlin/dispatch/test/samples/SomeClass.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package dispatch.test.samples 17 | 18 | import kotlinx.coroutines.CoroutineScope 19 | import kotlinx.coroutines.async 20 | 21 | class SomeClass(val coroutineScope: CoroutineScope) { 22 | 23 | fun dataDeferred() = coroutineScope.async { Data() } 24 | } 25 | 26 | @Suppress("FunctionOnlyReturningConstant") 27 | fun Data() = 1 28 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2022 Rick Busarow 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | kapt.incremental.apt=true 16 | org.gradle.caching=true 17 | org.gradle.configureondemand=true 18 | org.gradle.daemon=true 19 | org.gradle.jvmargs=-Xmx4g -XX:+UseParallelGC 20 | org.gradle.parallel=true 21 | org.gradle.vfs.watch=true 22 | android.useAndroidX=true 23 | android.enableJetifier=false 24 | android.lifecycleProcessor.incremental=true 25 | # Maven 26 | GROUP=com.rickbusarow.dispatch 27 | VERSION_NAME=1.0.0-beta10-SNAPSHOT 28 | POM_DESCRIPTION=Quality of life coroutine utilities. 29 | POM_INCEPTION_YEAR=2019 30 | POM_URL=https://github.com/rbusarow/Dispatch 31 | POM_SCM_URL=https://github.com/rbusarow/Dispatch.git 32 | POM_SCM_CONNECTION=scm:git:github.com/rbusarow/Dispatch.git 33 | POM_SCM_DEV_CONNECTION=scm:git:ssh://github.com/rbusarow/Dispatch.git 34 | POM_LICENCE_NAME=The Apache License, Version 2.0 35 | POM_LICENSE_URL=https://www.apache.org/licenses/LICENSE-2.0.txt 36 | POM_LICENCE_DIST=repo 37 | POM_DEVELOPER_ID=rbusarow 38 | POM_DEVELOPER_NAME=Rick Busarow 39 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RBusarow/Dispatch/4b231ef18802c064375eee7a58326f8283794dcd/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /knit.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2021 Rick Busarow 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | knit.dir=src/test/java/example/ 16 | knit.package=com.example 17 | test.dir=src/test/kotlin/example/test/ 18 | test.package=com.example.test 19 | site.root=https://rbusarow.github.io/Dispatch/ 20 | module.roots=. 21 | module.marker=build.gradle build.gradle.kts 22 | module.docs=build/dokka 23 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Copyright (C) 2022 Rick Busarow 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | # exit when any command fails 19 | set -e 20 | 21 | # keep track of the last executed command 22 | trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG 23 | # echo an error message before exiting 24 | trap 'echo "\"${last_command}\" command filed with exit code $?."' EXIT 25 | 26 | ./gradlew clean 27 | 28 | # Publish Maven release 29 | ./gradlew publish --no-daemon --no-parallel --no-configuration-cache 30 | 31 | # Close Maven release 32 | ./gradlew closeAndReleaseRepository --no-daemon --no-parallel --no-configuration-cache 33 | 34 | # Create new website docs version 35 | ./gradlew versionDocs 36 | 37 | # Set all versions in the root README to the new version 38 | ./gradlew updateProjectReadmeVersionRefs --no-configuration-cache 39 | 40 | # Copy the CHANGELOG from project root to the website dir and update its formatting 41 | ./gradlew updateWebsiteChangelog 42 | 43 | echo 44 | echo ' ___ _ _ ___ ___ ___ ___ ___' 45 | echo '/ __| | | |/ __/ __/ _ \/ __/ __|' 46 | echo '\__ \ |_| | (_| (_| __/\__ \__ \' 47 | echo '|___/\__,_|\___\___\___||___/___/' 48 | echo 49 | echo 50 | echo The release is done and a new docs version has been created for Docusaurus. 51 | echo 52 | echo These changes need to get merged into main and published. 53 | echo 54 | echo 55 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "labels": ["dependencies", "automerge"], 3 | "extends": [ 4 | "config:base" 5 | ], 6 | "rebaseWhen": "never", 7 | "rebaseLabel": "rebase" 8 | } 9 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | pluginManagement { 17 | repositories { 18 | gradlePluginPortal() 19 | mavenCentral() 20 | google() 21 | } 22 | } 23 | 24 | dependencyResolutionManagement { 25 | @Suppress("UnstableApiUsage") 26 | repositories { 27 | google() 28 | mavenCentral() 29 | } 30 | } 31 | 32 | plugins { 33 | id("com.gradle.enterprise").version("3.10") 34 | } 35 | 36 | gradleEnterprise { 37 | buildScan { 38 | termsOfServiceUrl = "https://gradle.com/terms-of-service" 39 | termsOfServiceAgree = "yes" 40 | publishAlways() 41 | } 42 | } 43 | 44 | rootProject.name = "Dispatch" 45 | 46 | enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") 47 | 48 | include(":dispatch-android-espresso") 49 | include(":dispatch-android-lifecycle") 50 | include(":dispatch-android-lifecycle-extensions") 51 | include(":dispatch-android-viewmodel") 52 | include(":dispatch-bom") 53 | include(":dispatch-core") 54 | include(":dispatch-test") 55 | include(":dispatch-test-junit4") 56 | include(":dispatch-test-junit5") 57 | include(":dispatch-detekt") 58 | include(":dispatch-internal-test") 59 | include(":dispatch-internal-test-android") 60 | include(":dispatch-sample") 61 | -------------------------------------------------------------------------------- /website/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /website/README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using [Docusaurus 2](https://v2.docusaurus.io/), a modern static website generator. 4 | 5 | ## Installation 6 | 7 | ```console 8 | yarn install 9 | ``` 10 | 11 | ## Local Development 12 | 13 | ```console 14 | yarn start 15 | ``` 16 | 17 | This command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server. 18 | 19 | ## Build 20 | 21 | ```console 22 | yarn build 23 | ``` 24 | 25 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 26 | 27 | ## Deployment 28 | 29 | ```console 30 | GIT_USER= USE_SSH=true yarn deploy 31 | ``` 32 | 33 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. 34 | -------------------------------------------------------------------------------- /website/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve("@docusaurus/core/lib/babel/preset")], 3 | }; 4 | -------------------------------------------------------------------------------- /website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dispatch", 3 | "version": "1.0.0-beta10-SNAPSHOT", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "serve": "docusaurus serve", 12 | "clear": "docusaurus clear" 13 | }, 14 | "dependencies": { 15 | "@babel/core": "7.19.1", 16 | "@babel/helper-compilation-targets": "7.19.1", 17 | "@docusaurus/core": "2.1.0", 18 | "@docusaurus/plugin-content-docs": "2.1.0", 19 | "@docusaurus/plugin-content-pages": "2.1.0", 20 | "@docusaurus/preset-classic": "2.1.0", 21 | "@docusaurus/theme-classic": "2.1.0", 22 | "@mdx-js/react": "1.6.22", 23 | "clsx": "1.2.1", 24 | "mdx-mermaid": "1.3.2", 25 | "mermaid": "9.1.7", 26 | "prism-react-renderer": "1.3.5", 27 | "react": "18.2.0", 28 | "react-dom": "18.2.0", 29 | "react-infima": "0.0.1-alpha.4" 30 | }, 31 | "browserslist": { 32 | "production": [ 33 | ">0.5%", 34 | "not dead", 35 | "not op_mini all" 36 | ], 37 | "development": [ 38 | "last 1 chrome version", 39 | "last 1 firefox version", 40 | "last 1 safari version" 41 | ] 42 | }, 43 | "main": "index.js", 44 | "license": "MIT" 45 | } 46 | -------------------------------------------------------------------------------- /website/sidebars.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Rick Busarow 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | module.exports = { 17 | // mySidebar: [ 18 | // { 19 | // type: 'autogenerated', 20 | // dirName: '.', // generate sidebar slice from the docs folder (or versioned_docs/) 21 | // }, 22 | // ], 23 | Docs: [ 24 | "intro", 25 | "quickstart", 26 | "modules/dispatch-core", 27 | "modules/dispatch-detekt", 28 | { 29 | type: "category", 30 | label: "Android", 31 | collapsed: false, 32 | items: [ 33 | "modules/dispatch-android-espresso", 34 | "modules/dispatch-android-lifecycle", 35 | "modules/dispatch-android-lifecycle-extensions", 36 | "modules/dispatch-android-viewmodel", 37 | ], 38 | }, 39 | { 40 | type: "category", 41 | label: "Testing", 42 | collapsed: false, 43 | items: [ 44 | "modules/dispatch-test", 45 | "modules/dispatch-test-junit4", 46 | "modules/dispatch-test-junit5", 47 | ], 48 | }, 49 | ] 50 | } 51 | ; 52 | -------------------------------------------------------------------------------- /website/src/pages/styles.module.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable docusaurus/copyright-header */ 2 | 3 | /** 4 | * CSS files with the .module.css suffix will be treated as CSS modules 5 | * and scoped locally. 6 | */ 7 | 8 | .heroBanner { 9 | padding: 4rem 0; 10 | text-align: center; 11 | position: relative; 12 | overflow: hidden; 13 | } 14 | 15 | @media screen and (max-width: 966px) { 16 | .heroBanner { 17 | padding: 2rem; 18 | } 19 | } 20 | 21 | .buttons { 22 | display: flex; 23 | align-items: center; 24 | justify-content: center; 25 | } 26 | 27 | .container { 28 | display: inline-block; 29 | width: 100%; 30 | text-align: center; 31 | } 32 | 33 | .badges { 34 | text-align: center; 35 | padding: 2rem; 36 | } 37 | 38 | .features { 39 | margin: auto; 40 | text-align: left; 41 | display: flex; 42 | align-items: center; 43 | padding: 2rem 0; 44 | width: 100%; 45 | } 46 | 47 | .feature { 48 | margin: 15px; 49 | width: 100%; 50 | } 51 | 52 | .row { 53 | align-items: center; 54 | text-align: left; 55 | display: flex; 56 | flex-direction: row; 57 | flex-wrap: wrap; 58 | width: 100%; 59 | } 60 | 61 | .column { 62 | display: flex; 63 | flex-direction: column; 64 | margin: 20px; 65 | flex: 1; 66 | } 67 | 68 | .featureImage { 69 | height: 200px; 70 | width: 200px; 71 | } 72 | 73 | .heroSlogan { 74 | font-size: 3em; 75 | line-height: normal; 76 | color: var(--ifm-color-white) !important; 77 | } 78 | 79 | /*.heroSlogan strong {*/ 80 | /* color: #8000ff;*/ 81 | /*}*/ 82 | 83 | .gettingStartedButton { 84 | background: #ffffff; 85 | color: var(--ifm-color-gray-900) !important; 86 | } 87 | 88 | .gettingStartedButton:hover { 89 | background: #ffffff; 90 | color: var(--ifm-color-primary) !important; 91 | } 92 | -------------------------------------------------------------------------------- /website/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RBusarow/Dispatch/4b231ef18802c064375eee7a58326f8283794dcd/website/static/.nojekyll -------------------------------------------------------------------------------- /website/static/img/coffee-solid.svg: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /website/static/img/power-off-solid.svg: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /website/static/img/syringe-solid.svg: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /website/versioned_sidebars/version-1.0.0-beta10-sidebars.json: -------------------------------------------------------------------------------- 1 | { 2 | "version-1.0.0-beta10/Basics": [ 3 | { 4 | "type": "doc", 5 | "id": "version-1.0.0-beta10/intro" 6 | }, 7 | { 8 | "type": "doc", 9 | "id": "version-1.0.0-beta10/quickstart" 10 | }, 11 | { 12 | "type": "doc", 13 | "id": "version-1.0.0-beta10/modules/dispatch-core" 14 | }, 15 | { 16 | "type": "doc", 17 | "id": "version-1.0.0-beta10/modules/dispatch-detekt" 18 | }, 19 | { 20 | "type": "category", 21 | "label": "Android", 22 | "collapsed": false, 23 | "items": [ 24 | { 25 | "type": "doc", 26 | "id": "version-1.0.0-beta10/modules/dispatch-android-espresso" 27 | }, 28 | { 29 | "type": "doc", 30 | "id": "version-1.0.0-beta10/modules/dispatch-android-lifecycle" 31 | }, 32 | { 33 | "type": "doc", 34 | "id": "version-1.0.0-beta10/modules/dispatch-android-lifecycle-extensions" 35 | }, 36 | { 37 | "type": "doc", 38 | "id": "version-1.0.0-beta10/modules/dispatch-android-viewmodel" 39 | } 40 | ], 41 | "collapsible": true 42 | }, 43 | { 44 | "type": "category", 45 | "label": "Testing", 46 | "collapsed": false, 47 | "items": [ 48 | { 49 | "type": "doc", 50 | "id": "version-1.0.0-beta10/modules/dispatch-test" 51 | }, 52 | { 53 | "type": "doc", 54 | "id": "version-1.0.0-beta10/modules/dispatch-test-junit4" 55 | }, 56 | { 57 | "type": "doc", 58 | "id": "version-1.0.0-beta10/modules/dispatch-test-junit5" 59 | } 60 | ], 61 | "collapsible": true 62 | } 63 | ] 64 | } 65 | -------------------------------------------------------------------------------- /website/versions.json: -------------------------------------------------------------------------------- 1 | [ 2 | "1.0.0-beta10" 3 | ] 4 | --------------------------------------------------------------------------------