From 82cc9ad6b4f39809275c93b0a956f7dd3cbdfd81 Mon Sep 17 00:00:00 2001 From: Guillermo Mazzola Date: Thu, 28 Nov 2024 15:39:20 +0100 Subject: [PATCH] Added report content validation test (#199) --- .run/Update specs.run.xml | 24 ++ demo-project/build.gradle.kts | 64 ++++- .../jacocoAggregatedReport.csv | 32 +++ .../tests/classes/MyUseCaseTest.html | 96 +++++++ .../com.example.kmp.KMPObjectAndroidTest.html | 101 ++++++++ .../com.example.kmp.KMPObjectJVMTest.html | 98 +++++++ .../com.example.kmp.KMPObjectTest.html | 110 ++++++++ .../com.example.login.ExampleUnitTest.html | 96 +++++++ ...ple.login.ui.data.LoginDataSourceTest.html | 96 +++++++ ...example.myapplication.ExampleUnitTest.html | 101 ++++++++ ...xample.myapplication.MainActivityTest.html | 114 ++++++++ .../tests/css/base-style.css | 179 +++++++++++++ .../aggregated-reports/tests/css/style.css | 84 ++++++ .../specs/aggregated-reports/tests/index.html | 243 ++++++++++++++++++ .../aggregated-reports/tests/js/report.js | 194 ++++++++++++++ .../tests/packages/com.example.kmp.html | 123 +++++++++ .../tests/packages/com.example.login.html | 103 ++++++++ .../packages/com.example.login.ui.data.html | 103 ++++++++ .../packages/com.example.myapplication.html | 113 ++++++++ .../tests/packages/default-package.html | 103 ++++++++ gradle/libs.versions.toml | 1 + 21 files changed, 2177 insertions(+), 1 deletion(-) create mode 100644 .run/Update specs.run.xml create mode 100644 demo-project/specs/aggregated-reports/jacocoAggregatedReport.csv create mode 100644 demo-project/specs/aggregated-reports/tests/classes/MyUseCaseTest.html create mode 100644 demo-project/specs/aggregated-reports/tests/classes/com.example.kmp.KMPObjectAndroidTest.html create mode 100644 demo-project/specs/aggregated-reports/tests/classes/com.example.kmp.KMPObjectJVMTest.html create mode 100644 demo-project/specs/aggregated-reports/tests/classes/com.example.kmp.KMPObjectTest.html create mode 100644 demo-project/specs/aggregated-reports/tests/classes/com.example.login.ExampleUnitTest.html create mode 100644 demo-project/specs/aggregated-reports/tests/classes/com.example.login.ui.data.LoginDataSourceTest.html create mode 100644 demo-project/specs/aggregated-reports/tests/classes/com.example.myapplication.ExampleUnitTest.html create mode 100644 demo-project/specs/aggregated-reports/tests/classes/com.example.myapplication.MainActivityTest.html create mode 100644 demo-project/specs/aggregated-reports/tests/css/base-style.css create mode 100644 demo-project/specs/aggregated-reports/tests/css/style.css create mode 100644 demo-project/specs/aggregated-reports/tests/index.html create mode 100644 demo-project/specs/aggregated-reports/tests/js/report.js create mode 100644 demo-project/specs/aggregated-reports/tests/packages/com.example.kmp.html create mode 100644 demo-project/specs/aggregated-reports/tests/packages/com.example.login.html create mode 100644 demo-project/specs/aggregated-reports/tests/packages/com.example.login.ui.data.html create mode 100644 demo-project/specs/aggregated-reports/tests/packages/com.example.myapplication.html create mode 100644 demo-project/specs/aggregated-reports/tests/packages/default-package.html diff --git a/.run/Update specs.run.xml b/.run/Update specs.run.xml new file mode 100644 index 0000000..0dd29db --- /dev/null +++ b/.run/Update specs.run.xml @@ -0,0 +1,24 @@ + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/demo-project/build.gradle.kts b/demo-project/build.gradle.kts index b11ec6d..9de74c1 100644 --- a/demo-project/build.gradle.kts +++ b/demo-project/build.gradle.kts @@ -1,3 +1,12 @@ +import com.github.difflib.DiffUtils +import com.github.difflib.UnifiedDiffUtils + +buildscript { + dependencies { + classpath(libs.diffUtils) + } +} + plugins { base id("io.github.gmazzo.test.aggregation.results") @@ -33,6 +42,59 @@ tasks.jacocoAggregatedCoverageVerification { } } +val aggregatedReportsSpecs = layout.projectDirectory.dir("specs/aggregated-reports") + +tasks.jacocoAggregatedReport { + reports.csv.required = true +} + +val reportsSpec = copySpec { + includeEmptyDirs = false + from(tasks.jacocoAggregatedReport) { include("**/*.csv") } + from(tasks.testAggregatedReport) { + into("tests") + filter { if (it.startsWith("")) "" else it } + } +} + +tasks.register("collectExpectedReports") { + with(reportsSpec) + into(aggregatedReportsSpecs) +} + +val checkAggregatedReportsContent by tasks.registering(Sync::class) { + with(reportsSpec) { into("actual") } + into(temporaryDir) + doLast { + fun File.collect() = walkTopDown() + .filter(File::isFile) + .associateBy { it.toRelativeString(this) } + + val expected = File(temporaryDir, "expects").collect() + val actual = File(temporaryDir, "actual").collect() + val diff = (expected.keys + actual.keys).mapNotNull { + val expectedLines = expected[it]?.readLines().orEmpty() + val actualLines = actual[it]?.readLines().orEmpty() + + when (actualLines) { + expectedLines -> null + else -> UnifiedDiffUtils.generateUnifiedDiff( + "expected:${it}", "actual:${it}", + expectedLines, + DiffUtils.diff(expectedLines, actualLines), + 3 + ) + } + } + check(diff.isEmpty()) { + diff.joinToString( + prefix = "The generated reports are different than the expected ones:\n", + separator = "\n\n\n" + ) + } + } +} + tasks.check { - dependsOn(tasks.jacocoAggregatedCoverageVerification) + dependsOn(tasks.jacocoAggregatedCoverageVerification, checkAggregatedReportsContent) } diff --git a/demo-project/specs/aggregated-reports/jacocoAggregatedReport.csv b/demo-project/specs/aggregated-reports/jacocoAggregatedReport.csv new file mode 100644 index 0000000..2c0cab7 --- /dev/null +++ b/demo-project/specs/aggregated-reports/jacocoAggregatedReport.csv @@ -0,0 +1,32 @@ +GROUP,PACKAGE,CLASS,INSTRUCTION_MISSED,INSTRUCTION_COVERED,BRANCH_MISSED,BRANCH_COVERED,LINE_MISSED,LINE_COVERED,COMPLEXITY_MISSED,COMPLEXITY_COVERED,METHOD_MISSED,METHOD_COVERED +demo-project,com.example.myapplication,SecondFragment,48,0,0,0,12,0,6,0,6,0 +demo-project,com.example.myapplication,FirstFragment,6,42,0,0,2,10,1,5,1,5 +demo-project,com.example.myapplication,MainActivity.onPostCreate..inlined.AppBarConfiguration.default.new Function0() {...},3,0,0,0,1,0,1,0,1,0 +demo-project,com.example.myapplication,MainActivity,29,48,4,0,6,10,4,2,2,2 +demo-project,com.example.login.databinding,ActivityLoginBinding,109,0,10,0,34,0,10,0,5,0 +demo-project,com.example.kmp,KMPObjectAndroid,0,9,0,0,0,1,0,2,0,2 +demo-project,com.example.kmp,KMPObject,0,9,0,0,0,1,0,2,0,2 +demo-project,com.example.kmp,MoshiObjAndroidJsonAdapter,173,0,16,0,29,0,13,0,4,0 +demo-project,com.example.kmp,KMPObjectJVM,0,9,0,0,0,1,0,2,0,2 +demo-project,com.example.kmp,MoshiObjJVMJsonAdapter,173,0,16,0,29,0,13,0,4,0 +demo-project,com.example.kmp,MoshiObjJVM,21,0,0,0,3,0,3,0,3,0 +demo-project,com.example.kmp,MoshiObjAndroid,21,0,0,0,3,0,3,0,3,0 +demo-project,com.example.kmp,PlatformKt,0,5,0,0,0,1,0,2,0,2 +demo-project,com.example.domain,MyUseCase,0,5,0,0,0,2,0,2,0,2 +demo-project,com.example.login.ui.login,LoginViewModel,162,0,12,0,21,0,13,0,7,0 +demo-project,com.example.login.ui.login,LoginActivityKt.afterTextChanged.new TextWatcher() {...},21,0,0,0,5,0,4,0,4,0 +demo-project,com.example.login.ui.login,LoginActivityKt,14,0,0,0,2,0,1,0,1,0 +demo-project,com.example.login.ui.login,LoggedInUserView,12,0,0,0,2,0,2,0,2,0 +demo-project,com.example.login.ui.login,LoginActivity,269,0,14,0,62,0,17,0,10,0 +demo-project,com.example.login.ui.login,LoginViewModelFactory,26,0,2,0,6,0,3,0,2,0 +demo-project,com.example.login.ui.login,LoginFormState,42,0,0,0,5,0,5,0,5,0 +demo-project,com.example.login.ui.login,LoginResult,30,0,0,0,4,0,4,0,4,0 +demo-project,com.example.login.ui.data,Result,18,0,2,0,3,0,2,0,1,0 +demo-project,com.example.login.ui.data,Result.Success,0,13,0,0,0,1,0,2,0,2 +demo-project,com.example.login.ui.data,LoginRepository,61,0,4,0,15,0,9,0,7,0 +demo-project,com.example.login.ui.data,Result.Error,13,0,0,0,1,0,2,0,2,0 +demo-project,com.example.login.ui.data,LoginDataSource,13,26,0,0,3,4,1,2,1,2 +demo-project,com.example.login.ui.data.model,LoggedInUser,3,18,0,0,0,3,1,2,1,2 +demo-project,com.example.myapplication.databinding,FragmentFirstBinding,22,52,3,3,6,16,4,4,1,4 +demo-project,com.example.myapplication.databinding,FragmentSecondBinding,74,0,6,0,22,0,8,0,5,0 +demo-project,com.example.myapplication.databinding,ActivityMainBinding,17,57,3,3,5,17,3,5,0,5 diff --git a/demo-project/specs/aggregated-reports/tests/classes/MyUseCaseTest.html b/demo-project/specs/aggregated-reports/tests/classes/MyUseCaseTest.html new file mode 100644 index 0000000..ea0cf8f --- /dev/null +++ b/demo-project/specs/aggregated-reports/tests/classes/MyUseCaseTest.html @@ -0,0 +1,96 @@ + + + + + +Test results - Class MyUseCaseTest + + + + + +
+

Class MyUseCaseTest

+
+
+ + + + + +
+
+ + + + + + + +
+
+
1
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.008s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Tests

+ + + + + + + + + + + + + +
TestDurationResult
testIsDone0.008spassed
+
+
+ +
+ + diff --git a/demo-project/specs/aggregated-reports/tests/classes/com.example.kmp.KMPObjectAndroidTest.html b/demo-project/specs/aggregated-reports/tests/classes/com.example.kmp.KMPObjectAndroidTest.html new file mode 100644 index 0000000..4c5cee7 --- /dev/null +++ b/demo-project/specs/aggregated-reports/tests/classes/com.example.kmp.KMPObjectAndroidTest.html @@ -0,0 +1,101 @@ + + + + + +Test results - Class com.example.kmp.KMPObjectAndroidTest + + + + + +
+

Class com.example.kmp.KMPObjectAndroidTest

+ +
+ + + + + +
+
+ + + + + + + +
+
+
2
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.067s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Tests

+ + + + + + + + + + + + + + + + + + +
TestDurationResult
testKMPObject0.034spassed
testKMPObject0.033spassed
+
+
+ +
+ + diff --git a/demo-project/specs/aggregated-reports/tests/classes/com.example.kmp.KMPObjectJVMTest.html b/demo-project/specs/aggregated-reports/tests/classes/com.example.kmp.KMPObjectJVMTest.html new file mode 100644 index 0000000..6684edb --- /dev/null +++ b/demo-project/specs/aggregated-reports/tests/classes/com.example.kmp.KMPObjectJVMTest.html @@ -0,0 +1,98 @@ + + + + + +Test results - Class com.example.kmp.KMPObjectJVMTest + + + + + +
+

Class com.example.kmp.KMPObjectJVMTest

+ +
+ + + + + +
+
+ + + + + + + +
+
+
1
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.060s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Tests

+ + + + + + + + + + + + + + + +
TestMethod nameDurationResult
testKMPObject[jvm]testKMPObject0.060spassed
+
+
+ +
+ + diff --git a/demo-project/specs/aggregated-reports/tests/classes/com.example.kmp.KMPObjectTest.html b/demo-project/specs/aggregated-reports/tests/classes/com.example.kmp.KMPObjectTest.html new file mode 100644 index 0000000..791f8f4 --- /dev/null +++ b/demo-project/specs/aggregated-reports/tests/classes/com.example.kmp.KMPObjectTest.html @@ -0,0 +1,110 @@ + + + + + +Test results - Class com.example.kmp.KMPObjectTest + + + + + +
+

Class com.example.kmp.KMPObjectTest

+ +
+ + + + + +
+
+ + + + + + + +
+
+
3
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.003s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Tests

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TestMethod nameDurationResult
testKMPObjecttestKMPObject0spassed
testKMPObject[jvm]testKMPObject0.002spassed
testKMPObjecttestKMPObject0.001spassed
+
+
+ +
+ + diff --git a/demo-project/specs/aggregated-reports/tests/classes/com.example.login.ExampleUnitTest.html b/demo-project/specs/aggregated-reports/tests/classes/com.example.login.ExampleUnitTest.html new file mode 100644 index 0000000..427b573 --- /dev/null +++ b/demo-project/specs/aggregated-reports/tests/classes/com.example.login.ExampleUnitTest.html @@ -0,0 +1,96 @@ + + + + + +Test results - Class com.example.login.ExampleUnitTest + + + + + +
+

Class com.example.login.ExampleUnitTest

+ +
+ + + + + +
+
+ + + + + + + +
+
+
1
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.001s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Tests

+ + + + + + + + + + + + + +
TestDurationResult
addition_isCorrect0.001spassed
+
+
+ +
+ + diff --git a/demo-project/specs/aggregated-reports/tests/classes/com.example.login.ui.data.LoginDataSourceTest.html b/demo-project/specs/aggregated-reports/tests/classes/com.example.login.ui.data.LoginDataSourceTest.html new file mode 100644 index 0000000..137681d --- /dev/null +++ b/demo-project/specs/aggregated-reports/tests/classes/com.example.login.ui.data.LoginDataSourceTest.html @@ -0,0 +1,96 @@ + + + + + +Test results - Class com.example.login.ui.data.LoginDataSourceTest + + + + + +
+

Class com.example.login.ui.data.LoginDataSourceTest

+ +
+ + + + + +
+
+ + + + + + + +
+
+
1
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.003s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Tests

+ + + + + + + + + + + + + +
TestDurationResult
testLogin0.003spassed
+
+
+ +
+ + diff --git a/demo-project/specs/aggregated-reports/tests/classes/com.example.myapplication.ExampleUnitTest.html b/demo-project/specs/aggregated-reports/tests/classes/com.example.myapplication.ExampleUnitTest.html new file mode 100644 index 0000000..4b54f63 --- /dev/null +++ b/demo-project/specs/aggregated-reports/tests/classes/com.example.myapplication.ExampleUnitTest.html @@ -0,0 +1,101 @@ + + + + + +Test results - Class com.example.myapplication.ExampleUnitTest + + + + + +
+

Class com.example.myapplication.ExampleUnitTest

+ +
+ + + + + +
+
+ + + + + + + +
+
+
2
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.006s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Tests

+ + + + + + + + + + + + + + + + + + +
TestDurationResult
addition_isCorrect0.001spassed
addition_isCorrect0.005spassed
+
+
+ +
+ + diff --git a/demo-project/specs/aggregated-reports/tests/classes/com.example.myapplication.MainActivityTest.html b/demo-project/specs/aggregated-reports/tests/classes/com.example.myapplication.MainActivityTest.html new file mode 100644 index 0000000..567af80 --- /dev/null +++ b/demo-project/specs/aggregated-reports/tests/classes/com.example.myapplication.MainActivityTest.html @@ -0,0 +1,114 @@ + + + + + +Test results - Class com.example.myapplication.MainActivityTest + + + + + +
+

Class com.example.myapplication.MainActivityTest

+ +
+ + + + + +
+
+ + + + + + + +
+
+
2
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
6.137s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Tests

+ + + + + + + + + + + + + + + + + + +
TestDurationResult
shouldStart3.048spassed
shouldStart3.089spassed
+
+
+

Standard error

+ +
[Robolectric] WARN: Android SDK 34 requires Java 17 (have Java 11). Tests won't be run on SDK 34 unless explicitly requested.
+[Robolectric] WARN: Android SDK 35 requires Java 17 (have Java 11). Tests won't be run on SDK 35 unless explicitly requested.
+[Robolectric] WARN: Android SDK 34 requires Java 17 (have Java 11). Tests won't be run on SDK 34 unless explicitly requested.
+[Robolectric] WARN: Android SDK 35 requires Java 17 (have Java 11). Tests won't be run on SDK 35 unless explicitly requested.
+
+
+
+
+ +
+ + diff --git a/demo-project/specs/aggregated-reports/tests/css/base-style.css b/demo-project/specs/aggregated-reports/tests/css/base-style.css new file mode 100644 index 0000000..4afa73e --- /dev/null +++ b/demo-project/specs/aggregated-reports/tests/css/base-style.css @@ -0,0 +1,179 @@ + +body { + margin: 0; + padding: 0; + font-family: sans-serif; + font-size: 12pt; +} + +body, a, a:visited { + color: #303030; +} + +#content { + padding-left: 50px; + padding-right: 50px; + padding-top: 30px; + padding-bottom: 30px; +} + +#content h1 { + font-size: 160%; + margin-bottom: 10px; +} + +#footer { + margin-top: 100px; + font-size: 80%; + white-space: nowrap; +} + +#footer, #footer a { + color: #a0a0a0; +} + +#line-wrapping-toggle { + vertical-align: middle; +} + +#label-for-line-wrapping-toggle { + vertical-align: middle; +} + +ul { + margin-left: 0; +} + +h1, h2, h3 { + white-space: nowrap; +} + +h2 { + font-size: 120%; +} + +ul.tabLinks { + padding-left: 0; + padding-top: 10px; + padding-bottom: 10px; + overflow: auto; + min-width: 800px; + width: auto !important; + width: 800px; +} + +ul.tabLinks li { + float: left; + height: 100%; + list-style: none; + padding-left: 10px; + padding-right: 10px; + padding-top: 5px; + padding-bottom: 5px; + margin-bottom: 0; + -moz-border-radius: 7px; + border-radius: 7px; + margin-right: 25px; + border: solid 1px #d4d4d4; + background-color: #f0f0f0; +} + +ul.tabLinks li:hover { + background-color: #fafafa; +} + +ul.tabLinks li.selected { + background-color: #c5f0f5; + border-color: #c5f0f5; +} + +ul.tabLinks a { + font-size: 120%; + display: block; + outline: none; + text-decoration: none; + margin: 0; + padding: 0; +} + +ul.tabLinks li h2 { + margin: 0; + padding: 0; +} + +div.tab { +} + +div.selected { + display: block; +} + +div.deselected { + display: none; +} + +div.tab table { + min-width: 350px; + width: auto !important; + width: 350px; + border-collapse: collapse; +} + +div.tab th, div.tab table { + border-bottom: solid #d0d0d0 1px; +} + +div.tab th { + text-align: left; + white-space: nowrap; + padding-left: 6em; +} + +div.tab th:first-child { + padding-left: 0; +} + +div.tab td { + white-space: nowrap; + padding-left: 6em; + padding-top: 5px; + padding-bottom: 5px; +} + +div.tab td:first-child { + padding-left: 0; +} + +div.tab td.numeric, div.tab th.numeric { + text-align: right; +} + +span.code { + display: inline-block; + margin-top: 0em; + margin-bottom: 1em; +} + +span.code pre { + font-size: 11pt; + padding-top: 10px; + padding-bottom: 10px; + padding-left: 10px; + padding-right: 10px; + margin: 0; + background-color: #f7f7f7; + border: solid 1px #d0d0d0; + min-width: 700px; + width: auto !important; + width: 700px; +} + +span.wrapped pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: break-all; +} + +label.hidden { + display: none; +} \ No newline at end of file diff --git a/demo-project/specs/aggregated-reports/tests/css/style.css b/demo-project/specs/aggregated-reports/tests/css/style.css new file mode 100644 index 0000000..3dc4913 --- /dev/null +++ b/demo-project/specs/aggregated-reports/tests/css/style.css @@ -0,0 +1,84 @@ + +#summary { + margin-top: 30px; + margin-bottom: 40px; +} + +#summary table { + border-collapse: collapse; +} + +#summary td { + vertical-align: top; +} + +.breadcrumbs, .breadcrumbs a { + color: #606060; +} + +.infoBox { + width: 110px; + padding-top: 15px; + padding-bottom: 15px; + text-align: center; +} + +.infoBox p { + margin: 0; +} + +.counter, .percent { + font-size: 120%; + font-weight: bold; + margin-bottom: 8px; +} + +#duration { + width: 125px; +} + +#successRate, .summaryGroup { + border: solid 2px #d0d0d0; + -moz-border-radius: 10px; + border-radius: 10px; +} + +#successRate { + width: 140px; + margin-left: 35px; +} + +#successRate .percent { + font-size: 180%; +} + +.success, .success a { + color: #008000; +} + +div.success, #successRate.success { + background-color: #bbd9bb; + border-color: #008000; +} + +.failures, .failures a { + color: #b60808; +} + +.skipped, .skipped a { + color: #c09853; +} + +div.failures, #successRate.failures { + background-color: #ecdada; + border-color: #b60808; +} + +ul.linkList { + padding-left: 0; +} + +ul.linkList li { + list-style: none; + margin-bottom: 5px; +} diff --git a/demo-project/specs/aggregated-reports/tests/index.html b/demo-project/specs/aggregated-reports/tests/index.html new file mode 100644 index 0000000..4d91c72 --- /dev/null +++ b/demo-project/specs/aggregated-reports/tests/index.html @@ -0,0 +1,243 @@ + + + + + +Test results - Test Summary + + + + + +
+

Test Summary

+
+ + + + + +
+
+ + + + + + + +
+
+
13
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
6.285s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Packages

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PackageTestsFailuresIgnoredDurationSuccess rate
+default-package +1000.008s100%
+com.example.kmp +6000.130s100%
+com.example.login +1000.001s100%
+com.example.login.ui.data +1000.003s100%
+com.example.myapplication +4006.143s100%
+
+
+

Classes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+MyUseCaseTest +1000.008s100%
+com.example.kmp.KMPObjectAndroidTest +2000.067s100%
+com.example.kmp.KMPObjectJVMTest +1000.060s100%
+com.example.kmp.KMPObjectTest +3000.003s100%
+com.example.login.ExampleUnitTest +1000.001s100%
+com.example.login.ui.data.LoginDataSourceTest +1000.003s100%
+com.example.myapplication.ExampleUnitTest +2000.006s100%
+com.example.myapplication.MainActivityTest +2006.137s100%
+
+
+ +
+ + diff --git a/demo-project/specs/aggregated-reports/tests/js/report.js b/demo-project/specs/aggregated-reports/tests/js/report.js new file mode 100644 index 0000000..83bab4a --- /dev/null +++ b/demo-project/specs/aggregated-reports/tests/js/report.js @@ -0,0 +1,194 @@ +(function (window, document) { + "use strict"; + + var tabs = {}; + + function changeElementClass(element, classValue) { + if (element.getAttribute("className")) { + element.setAttribute("className", classValue); + } else { + element.setAttribute("class", classValue); + } + } + + function getClassAttribute(element) { + if (element.getAttribute("className")) { + return element.getAttribute("className"); + } else { + return element.getAttribute("class"); + } + } + + function addClass(element, classValue) { + changeElementClass(element, getClassAttribute(element) + " " + classValue); + } + + function removeClass(element, classValue) { + changeElementClass(element, getClassAttribute(element).replace(classValue, "")); + } + + function initTabs() { + var container = document.getElementById("tabs"); + + tabs.tabs = findTabs(container); + tabs.titles = findTitles(tabs.tabs); + tabs.headers = findHeaders(container); + tabs.select = select; + tabs.deselectAll = deselectAll; + tabs.select(0); + + return true; + } + + function getCheckBox() { + return document.getElementById("line-wrapping-toggle"); + } + + function getLabelForCheckBox() { + return document.getElementById("label-for-line-wrapping-toggle"); + } + + function findCodeBlocks() { + var spans = document.getElementById("tabs").getElementsByTagName("span"); + var codeBlocks = []; + for (var i = 0; i < spans.length; ++i) { + if (spans[i].className.indexOf("code") >= 0) { + codeBlocks.push(spans[i]); + } + } + return codeBlocks; + } + + function forAllCodeBlocks(operation) { + var codeBlocks = findCodeBlocks(); + + for (var i = 0; i < codeBlocks.length; ++i) { + operation(codeBlocks[i], "wrapped"); + } + } + + function toggleLineWrapping() { + var checkBox = getCheckBox(); + + if (checkBox.checked) { + forAllCodeBlocks(addClass); + } else { + forAllCodeBlocks(removeClass); + } + } + + function initControls() { + if (findCodeBlocks().length > 0) { + var checkBox = getCheckBox(); + var label = getLabelForCheckBox(); + + checkBox.onclick = toggleLineWrapping; + checkBox.checked = false; + + removeClass(label, "hidden"); + } + } + + function switchTab() { + var id = this.id.substr(1); + + for (var i = 0; i < tabs.tabs.length; i++) { + if (tabs.tabs[i].id === id) { + tabs.select(i); + break; + } + } + + return false; + } + + function select(i) { + this.deselectAll(); + + changeElementClass(this.tabs[i], "tab selected"); + changeElementClass(this.headers[i], "selected"); + + while (this.headers[i].firstChild) { + this.headers[i].removeChild(this.headers[i].firstChild); + } + + var h2 = document.createElement("H2"); + + h2.appendChild(document.createTextNode(this.titles[i])); + this.headers[i].appendChild(h2); + } + + function deselectAll() { + for (var i = 0; i < this.tabs.length; i++) { + changeElementClass(this.tabs[i], "tab deselected"); + changeElementClass(this.headers[i], "deselected"); + + while (this.headers[i].firstChild) { + this.headers[i].removeChild(this.headers[i].firstChild); + } + + var a = document.createElement("A"); + + a.setAttribute("id", "ltab" + i); + a.setAttribute("href", "#tab" + i); + a.onclick = switchTab; + a.appendChild(document.createTextNode(this.titles[i])); + + this.headers[i].appendChild(a); + } + } + + function findTabs(container) { + return findChildElements(container, "DIV", "tab"); + } + + function findHeaders(container) { + var owner = findChildElements(container, "UL", "tabLinks"); + return findChildElements(owner[0], "LI", null); + } + + function findTitles(tabs) { + var titles = []; + + for (var i = 0; i < tabs.length; i++) { + var tab = tabs[i]; + var header = findChildElements(tab, "H2", null)[0]; + + header.parentNode.removeChild(header); + + if (header.innerText) { + titles.push(header.innerText); + } else { + titles.push(header.textContent); + } + } + + return titles; + } + + function findChildElements(container, name, targetClass) { + var elements = []; + var children = container.childNodes; + + for (var i = 0; i < children.length; i++) { + var child = children.item(i); + + if (child.nodeType === 1 && child.nodeName === name) { + if (targetClass && child.className.indexOf(targetClass) < 0) { + continue; + } + + elements.push(child); + } + } + + return elements; + } + + // Entry point. + + window.onload = function() { + initTabs(); + initControls(); + }; +} (window, window.document)); \ No newline at end of file diff --git a/demo-project/specs/aggregated-reports/tests/packages/com.example.kmp.html b/demo-project/specs/aggregated-reports/tests/packages/com.example.kmp.html new file mode 100644 index 0000000..7313fd8 --- /dev/null +++ b/demo-project/specs/aggregated-reports/tests/packages/com.example.kmp.html @@ -0,0 +1,123 @@ + + + + + +Test results - Package com.example.kmp + + + + + +
+

Package com.example.kmp

+ +
+ + + + + +
+
+ + + + + + + +
+
+
6
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.130s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Classes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+KMPObjectAndroidTest +2000.067s100%
+KMPObjectJVMTest +1000.060s100%
+KMPObjectTest +3000.003s100%
+
+
+ +
+ + diff --git a/demo-project/specs/aggregated-reports/tests/packages/com.example.login.html b/demo-project/specs/aggregated-reports/tests/packages/com.example.login.html new file mode 100644 index 0000000..1900256 --- /dev/null +++ b/demo-project/specs/aggregated-reports/tests/packages/com.example.login.html @@ -0,0 +1,103 @@ + + + + + +Test results - Package com.example.login + + + + + +
+

Package com.example.login

+ +
+ + + + + +
+
+ + + + + + + +
+
+
1
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.001s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Classes

+ + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+ExampleUnitTest +1000.001s100%
+
+
+ +
+ + diff --git a/demo-project/specs/aggregated-reports/tests/packages/com.example.login.ui.data.html b/demo-project/specs/aggregated-reports/tests/packages/com.example.login.ui.data.html new file mode 100644 index 0000000..0e607aa --- /dev/null +++ b/demo-project/specs/aggregated-reports/tests/packages/com.example.login.ui.data.html @@ -0,0 +1,103 @@ + + + + + +Test results - Package com.example.login.ui.data + + + + + +
+

Package com.example.login.ui.data

+ +
+ + + + + +
+
+ + + + + + + +
+
+
1
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.003s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Classes

+ + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+LoginDataSourceTest +1000.003s100%
+
+
+ +
+ + diff --git a/demo-project/specs/aggregated-reports/tests/packages/com.example.myapplication.html b/demo-project/specs/aggregated-reports/tests/packages/com.example.myapplication.html new file mode 100644 index 0000000..7c094e6 --- /dev/null +++ b/demo-project/specs/aggregated-reports/tests/packages/com.example.myapplication.html @@ -0,0 +1,113 @@ + + + + + +Test results - Package com.example.myapplication + + + + + +
+

Package com.example.myapplication

+ +
+ + + + + +
+
+ + + + + + + +
+
+
4
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
6.143s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Classes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+ExampleUnitTest +2000.006s100%
+MainActivityTest +2006.137s100%
+
+
+ +
+ + diff --git a/demo-project/specs/aggregated-reports/tests/packages/default-package.html b/demo-project/specs/aggregated-reports/tests/packages/default-package.html new file mode 100644 index 0000000..4560447 --- /dev/null +++ b/demo-project/specs/aggregated-reports/tests/packages/default-package.html @@ -0,0 +1,103 @@ + + + + + +Test results - Default package + + + + + +
+

Default package

+ +
+ + + + + +
+
+ + + + + + + +
+
+
1
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.008s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Classes

+ + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+MyUseCaseTest +1000.008s100%
+
+
+ +
+ + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index db42add..34fee0e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,6 +18,7 @@ androidx-navigation-ui = { module = "androidx.navigation:navigation-ui-ktx", ver androidx-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "androidx-lifecycle" } androidx-test-junit = "androidx.test.ext:junit:1.2.1" androidx-test-espresso = "androidx.test.espresso:espresso-core:3.6.1" +diffUtils = { module = "io.github.java-diff-utils:java-diff-utils", version = "4.12" } google-material = "com.google.android.material:material:1.12.0" kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } moshi-kotlin = { module = "com.squareup.moshi:moshi-kotlin", version.ref = "moshi" }