From 33c66fb4a71f607cd714b625d0980d691b8f6f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Haris=20Dautovi=C4=87?= Date: Mon, 24 Jun 2024 11:25:42 +0200 Subject: [PATCH 1/2] Fix sonar lint issues (#130) --- .../charts/internal/DataValidation.kt | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/charts/src/commonMain/kotlin/io/github/dautovicharis/charts/internal/DataValidation.kt b/charts/src/commonMain/kotlin/io/github/dautovicharis/charts/internal/DataValidation.kt index 51a2b63..5b26fcb 100644 --- a/charts/src/commonMain/kotlin/io/github/dautovicharis/charts/internal/DataValidation.kt +++ b/charts/src/commonMain/kotlin/io/github/dautovicharis/charts/internal/DataValidation.kt @@ -79,12 +79,10 @@ internal fun validatePieData( } // Rule 2: If colors are not empty, it should match pointsSize - if (colorsSize > 0) { - if (colorsSize != pointsSize) { - val validationError = - ValidationErrors.RULE_COLORS_SIZE_MISMATCH.format(colorsSize, pointsSize) - validationErrors.add(validationError) - } + if (colorsSize > 0 && colorsSize != pointsSize) { + val validationError = + ValidationErrors.RULE_COLORS_SIZE_MISMATCH.format(colorsSize, pointsSize) + validationErrors.add(validationError) } return validationErrors } @@ -119,23 +117,19 @@ private fun validateChartData( } // Rule 3: If categories are not empty, it should match pointsSize - if (data.hasCategories()) { - if (data.categories.size != pointsSize) { - val validationError = ValidationErrors.RULE_CATEGORIES_SIZE_MISMATCH.format( - data.categories.size, - pointsSize - ) - validationErrors.add(validationError) - } + if (data.hasCategories() && data.categories.size != pointsSize) { + val validationError = ValidationErrors.RULE_CATEGORIES_SIZE_MISMATCH.format( + data.categories.size, + pointsSize + ) + validationErrors.add(validationError) } // Rule 4: If colors are not empty, it should match expectedColorsSize - if (colorsSize > 0) { - if (colorsSize != expectedColorsSize) { - val validationError = - ValidationErrors.RULE_COLORS_SIZE_MISMATCH.format(colorsSize, expectedColorsSize) - validationErrors.add(validationError) - } + if (colorsSize > 0 && colorsSize != expectedColorsSize) { + val validationError = + ValidationErrors.RULE_COLORS_SIZE_MISMATCH.format(colorsSize, expectedColorsSize) + validationErrors.add(validationError) } return validationErrors } From 0d5e0c984f75fd518a3038f8a767089c71e54b78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Haris=20Dautovi=C4=87?= Date: Mon, 24 Jun 2024 11:36:09 +0200 Subject: [PATCH 2/2] Improvement/tests (#131) * Exclude preview from code coverage * Validate bar chart data * Add more tests --- app/build.gradle.kts | 6 +- build.gradle.kts | 1 + charts/build.gradle.kts | 15 ++++- .../dautovicharis/charts/BarChartPreview.kt | 50 -------------- .../charts/preview/BarChartPreview.kt | 51 ++++++++++++++ .../{ => preview}/BarStackedChartPreview.kt | 31 +++++---- .../charts/preview/LineChartPreview.kt | 67 +++++++++++++++++++ .../MultiLineChartPreview.kt} | 31 +++++---- .../charts/{ => preview}/PieChartPreview.kt | 49 +++++++------- .../charts/{ => preview}/mock/Mock.kt | 17 +++-- .../dautovicharis/charts/BarChartView.kt | 23 +++++++ .../charts/internal/DataValidation.kt | 23 ++++++- .../dautovicharis/charts/ui/BarChartTest.kt | 23 +++++++ .../dautovicharis/charts/ui/LineChartTest.kt | 41 ++++-------- .../charts/ui/MultiLineChartTest.kt | 45 +++++++++++++ .../dautovicharis/charts/ui/PieChartTest.kt | 2 +- .../charts/ui/StackedBarChartTest.kt | 62 +++++++++++++++++ .../unit/validation/DataValidationBarTest.kt | 4 +- 18 files changed, 392 insertions(+), 149 deletions(-) delete mode 100644 charts/src/androidMain/kotlin/io/github/dautovicharis/charts/BarChartPreview.kt create mode 100644 charts/src/androidMain/kotlin/io/github/dautovicharis/charts/preview/BarChartPreview.kt rename charts/src/androidMain/kotlin/io/github/dautovicharis/charts/{ => preview}/BarStackedChartPreview.kt (61%) create mode 100644 charts/src/androidMain/kotlin/io/github/dautovicharis/charts/preview/LineChartPreview.kt rename charts/src/androidMain/kotlin/io/github/dautovicharis/charts/{LineChartPreview.kt => preview/MultiLineChartPreview.kt} (73%) rename charts/src/androidMain/kotlin/io/github/dautovicharis/charts/{ => preview}/PieChartPreview.kt (66%) rename charts/src/androidMain/kotlin/io/github/dautovicharis/charts/{ => preview}/mock/Mock.kt (87%) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7b3054f..beafd9f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,5 +1,5 @@ + import org.jetbrains.compose.desktop.application.dsl.TargetFormat -import org.jetbrains.kotlin.gradle.targets.js.internal.filterClassName import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig plugins { @@ -139,7 +139,3 @@ buildConfig { buildConfigField("DEMO_VERSION_CODE", Config.demoVersionCode) useKotlinOutput() } - -kover { - filterClassName("androidx.compose.ui.tooling.preview.Preview") -} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 9c0704c..10be759 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -18,6 +18,7 @@ sonar { "${project.rootDir}/charts/build/reports/kover/report.xml," + "${project.rootDir}/app/build/reports/kover/report.xml" ) + property("sonar.coverage.exclusions", "**/preview/**") } } diff --git a/charts/build.gradle.kts b/charts/build.gradle.kts index 7778223..32550b7 100644 --- a/charts/build.gradle.kts +++ b/charts/build.gradle.kts @@ -1,7 +1,6 @@ import com.vanniktech.maven.publish.SonatypeHost import org.jetbrains.dokka.versioning.VersioningConfiguration import org.jetbrains.dokka.versioning.VersioningPlugin -import org.jetbrains.kotlin.gradle.targets.js.internal.filterClassName plugins { alias(libs.plugins.kotlinMultiplatform) @@ -171,5 +170,15 @@ dependencies { } kover { - filterClassName("androidx.compose.ui.tooling.preview.Preview") -} \ No newline at end of file + reports { + filters { + excludes { + packages("io.github.dautovicharis.charts.preview") + annotatedBy( + "androidx.compose.ui.tooling.preview.Preview" + ) + androidGeneratedClasses() + } + } + } +} diff --git a/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/BarChartPreview.kt b/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/BarChartPreview.kt deleted file mode 100644 index fe31236..0000000 --- a/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/BarChartPreview.kt +++ /dev/null @@ -1,50 +0,0 @@ -package io.github.dautovicharis.charts - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.wrapContentHeight -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import io.github.dautovicharis.charts.internal.common.theme.ChartsDefaultTheme -import io.github.dautovicharis.charts.mock.Mock -import io.github.dautovicharis.charts.style.BarChartDefaults - -@Composable -private fun BarChartViewPreview() { - Column( - modifier = Modifier - .size(400.dp) - .wrapContentHeight(), - ) { - BarChartView( - dataSet = Mock.barChart(), - style = BarChartDefaults.style() - ) - } -} - -@Preview -@Composable -private fun BarChartViewDefault() { - ChartsDefaultTheme(darkTheme = false) { - BarChartViewPreview() - } -} - -@Preview -@Composable -private fun BarChartViewDark() { - ChartsDefaultTheme(darkTheme = true) { - BarChartViewPreview() - } -} - -@Preview -@Composable -private fun BarChartViewDynamic() { - ChartsDefaultTheme(dynamicColor = true) { - BarChartViewPreview() - } -} diff --git a/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/preview/BarChartPreview.kt b/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/preview/BarChartPreview.kt new file mode 100644 index 0000000..f3bd4e3 --- /dev/null +++ b/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/preview/BarChartPreview.kt @@ -0,0 +1,51 @@ +package io.github.dautovicharis.charts.preview + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import io.github.dautovicharis.charts.BarChartView +import io.github.dautovicharis.charts.internal.common.theme.ChartsDefaultTheme +import io.github.dautovicharis.charts.preview.mock.Mock +import io.github.dautovicharis.charts.style.BarChartDefaults + +@Composable +private fun BarChartPreview() { + BarChartView( + dataSet = Mock.barChart(), + style = BarChartDefaults.style() + ) +} + +@Preview +@Composable +private fun BarChartDefault() { + ChartsDefaultTheme(darkTheme = false) { + BarChartPreview() + } +} + +@Preview +@Composable +private fun BarChartDark() { + ChartsDefaultTheme(darkTheme = true) { + BarChartPreview() + } +} + +@Preview +@Composable +private fun BarChartDynamic() { + ChartsDefaultTheme(dynamicColor = true) { + BarChartPreview() + } +} + +@Preview +@Composable +private fun BarChartError() { + ChartsDefaultTheme { + BarChartView( + dataSet = Mock.barChart(1), + style = BarChartDefaults.style() + ) + } +} diff --git a/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/BarStackedChartPreview.kt b/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/preview/BarStackedChartPreview.kt similarity index 61% rename from charts/src/androidMain/kotlin/io/github/dautovicharis/charts/BarStackedChartPreview.kt rename to charts/src/androidMain/kotlin/io/github/dautovicharis/charts/preview/BarStackedChartPreview.kt index d29666d..7ace540 100644 --- a/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/BarStackedChartPreview.kt +++ b/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/preview/BarStackedChartPreview.kt @@ -1,14 +1,15 @@ -package io.github.dautovicharis.charts +package io.github.dautovicharis.charts.preview import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import io.github.dautovicharis.charts.StackedBarChartView import io.github.dautovicharis.charts.internal.common.theme.ChartsDefaultTheme -import io.github.dautovicharis.charts.mock.Mock +import io.github.dautovicharis.charts.preview.mock.Mock import io.github.dautovicharis.charts.style.StackedBarChartDefaults @Composable -private fun StackedBarChartViewPreview() { +private fun StackedBarChartPreview() { StackedBarChartView( dataSet = Mock.stackedBarChart(), style = StackedBarChartDefaults.style() @@ -17,39 +18,41 @@ private fun StackedBarChartViewPreview() { @Preview @Composable -private fun StackedBarChartViewDefault() { +private fun StackedBarChartDefault() { ChartsDefaultTheme(darkTheme = false, dynamicColor = false) { - StackedBarChartViewPreview() + StackedBarChartPreview() } } @Preview @Composable -private fun StackedBarChartViewDark() { +private fun StackedBarChartDark() { ChartsDefaultTheme(darkTheme = true, dynamicColor = false) { - StackedBarChartViewPreview() + StackedBarChartPreview() } } @Preview(apiLevel = 33) @Composable -private fun StackedBarChartViewDynamic() { +private fun StackedBarChartDynamic() { ChartsDefaultTheme(darkTheme = false, dynamicColor = true) { - StackedBarChartViewPreview() + StackedBarChartPreview() } } @Preview @Composable -private fun StackedBarChartViewInvalidData() { +private fun StackedBarChartError() { val barColor = MaterialTheme.colorScheme.primary val style = StackedBarChartDefaults.style( barColors = listOf(barColor), space = 8.dp ) - StackedBarChartView( - dataSet = Mock.stackedBarChartInvalid(), - style = style - ) + ChartsDefaultTheme { + StackedBarChartView( + dataSet = Mock.stackedBarChartInvalid(), + style = style + ) + } } diff --git a/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/preview/LineChartPreview.kt b/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/preview/LineChartPreview.kt new file mode 100644 index 0000000..e1117a6 --- /dev/null +++ b/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/preview/LineChartPreview.kt @@ -0,0 +1,67 @@ +package io.github.dautovicharis.charts.preview + +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import io.github.dautovicharis.charts.LineChartView +import io.github.dautovicharis.charts.internal.common.theme.ChartsDefaultTheme +import io.github.dautovicharis.charts.preview.mock.Mock +import io.github.dautovicharis.charts.style.ChartViewDefaults +import io.github.dautovicharis.charts.style.LineChartDefaults + +@Composable +private fun LineChartViewPreview() { + val colors = listOf( + MaterialTheme.colorScheme.primary + + ) + + val style = LineChartDefaults.style( + bezier = true, + lineColors = colors, + dragPointSize = 5f, + pointVisible = true, + chartViewStyle = ChartViewDefaults.style(width = 300.dp) + ) + + LineChartView( + dataSet = Mock.lineChartSimple(), + style = style + ) +} + +@Preview +@Composable +private fun LineChartDefault() { + ChartsDefaultTheme(darkTheme = false, dynamicColor = false) { + LineChartViewPreview() + } +} + +@Preview +@Composable +private fun LineChartDark() { + ChartsDefaultTheme(darkTheme = true, dynamicColor = false) { + LineChartViewPreview() + } +} + +@Preview +@Composable +private fun LineChartDynamic() { + ChartsDefaultTheme(dynamicColor = true) { + LineChartViewPreview() + } +} + +@Preview +@Composable +private fun LineChartError() { + ChartsDefaultTheme { + LineChartView( + dataSet = Mock.lineChartSimple(1), + style = LineChartDefaults.style() + ) + } +} diff --git a/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/LineChartPreview.kt b/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/preview/MultiLineChartPreview.kt similarity index 73% rename from charts/src/androidMain/kotlin/io/github/dautovicharis/charts/LineChartPreview.kt rename to charts/src/androidMain/kotlin/io/github/dautovicharis/charts/preview/MultiLineChartPreview.kt index d637085..2a6d052 100644 --- a/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/LineChartPreview.kt +++ b/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/preview/MultiLineChartPreview.kt @@ -1,17 +1,18 @@ -package io.github.dautovicharis.charts +package io.github.dautovicharis.charts.preview import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import io.github.dautovicharis.charts.LineChartView import io.github.dautovicharis.charts.internal.common.theme.ChartsDefaultTheme -import io.github.dautovicharis.charts.mock.Mock +import io.github.dautovicharis.charts.preview.mock.Mock import io.github.dautovicharis.charts.style.ChartViewDefaults import io.github.dautovicharis.charts.style.LineChartDefaults @Composable -private fun LineChartViewPreview() { +private fun MultiLineChartPreview() { val colors = listOf( MaterialTheme.colorScheme.primary, MaterialTheme.colorScheme.secondary, @@ -35,31 +36,31 @@ private fun LineChartViewPreview() { @Preview @Composable -private fun LineChartViewDefault() { +private fun MultiLineChartDefault() { ChartsDefaultTheme(darkTheme = false, dynamicColor = false) { - LineChartViewPreview() + MultiLineChartPreview() } } @Preview @Composable -private fun LineChartViewDark() { +private fun MultiLineChartDark() { ChartsDefaultTheme(darkTheme = true, dynamicColor = false) { - LineChartViewPreview() + MultiLineChartPreview() } } @Preview(apiLevel = 33) @Composable -private fun LineChartViewDynamic() { +private fun MultiLineChartDynamic() { ChartsDefaultTheme(darkTheme = false, dynamicColor = true) { - LineChartViewPreview() + MultiLineChartPreview() } } @Preview @Composable -private fun LineChartViewInvalidData() { +private fun MultiLineChartError() { val colors = listOf( MaterialTheme.colorScheme.primary, MaterialTheme.colorScheme.secondary, @@ -74,8 +75,10 @@ private fun LineChartViewInvalidData() { chartViewStyle = ChartViewDefaults.style(width = 300.dp) ) - LineChartView( - dataSet = Mock.lineChartInvalid(), - style = style - ) + ChartsDefaultTheme { + LineChartView( + dataSet = Mock.lineChartInvalid(), + style = style + ) + } } diff --git a/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/PieChartPreview.kt b/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/preview/PieChartPreview.kt similarity index 66% rename from charts/src/androidMain/kotlin/io/github/dautovicharis/charts/PieChartPreview.kt rename to charts/src/androidMain/kotlin/io/github/dautovicharis/charts/preview/PieChartPreview.kt index 81b64fe..3f500e2 100644 --- a/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/PieChartPreview.kt +++ b/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/preview/PieChartPreview.kt @@ -1,20 +1,18 @@ -package io.github.dautovicharis.charts -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.wrapContentHeight +package io.github.dautovicharis.charts.preview + import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import io.github.dautovicharis.charts.PieChartView import io.github.dautovicharis.charts.internal.common.theme.ChartsDefaultTheme -import io.github.dautovicharis.charts.mock.Mock +import io.github.dautovicharis.charts.preview.mock.Mock import io.github.dautovicharis.charts.style.ChartViewDefaults import io.github.dautovicharis.charts.style.PieChartDefaults import io.github.dautovicharis.charts.style.PieChartStyle @Composable -private fun PieChartViewPreview() { +private fun PieChartPreview() { val pieColor = MaterialTheme.colorScheme.primary val backgroundColor = MaterialTheme.colorScheme.surface val borderColor = MaterialTheme.colorScheme.surface @@ -31,38 +29,43 @@ private fun PieChartViewPreview() { ) ) - Row( - modifier = Modifier - .width(300.dp) - .wrapContentHeight(), - ) { - PieChartView( - dataSet = Mock.pieChart(), - style = style - ) - } + PieChartView( + dataSet = Mock.pieChart(), + style = style + ) } @Preview @Composable -private fun PieChartViewDefault() { +private fun PieChartDefault() { ChartsDefaultTheme(darkTheme = false, dynamicColor = false) { - PieChartViewPreview() + PieChartPreview() } } @Preview @Composable -private fun PieChartViewDark() { +private fun PieChartDark() { ChartsDefaultTheme(darkTheme = true, dynamicColor = false) { - PieChartViewPreview() + PieChartPreview() } } @Preview(apiLevel = 33) @Composable -private fun PieChartViewDynamic() { +private fun PieChartDynamic() { ChartsDefaultTheme(darkTheme = false, dynamicColor = true) { - PieChartViewPreview() + PieChartPreview() + } +} + +@Preview +@Composable +private fun PieChartError() { + ChartsDefaultTheme { + PieChartView( + dataSet = Mock.pieChart(1), + style = PieChartDefaults.style() + ) } } diff --git a/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/mock/Mock.kt b/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/preview/mock/Mock.kt similarity index 87% rename from charts/src/androidMain/kotlin/io/github/dautovicharis/charts/mock/Mock.kt rename to charts/src/androidMain/kotlin/io/github/dautovicharis/charts/preview/mock/Mock.kt index 55298e9..71cff26 100644 --- a/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/mock/Mock.kt +++ b/charts/src/androidMain/kotlin/io/github/dautovicharis/charts/preview/mock/Mock.kt @@ -1,4 +1,4 @@ -package io.github.dautovicharis.charts.mock +package io.github.dautovicharis.charts.preview.mock import io.github.dautovicharis.charts.common.model.ChartDataSet import io.github.dautovicharis.charts.common.model.MultiChartDataSet @@ -43,9 +43,9 @@ internal object Mock { return mockList } - fun barChart(): ChartDataSet { + fun barChart(size: Int = 10): ChartDataSet { return ChartDataSet( - items = mockList(size = 10), + items = mockList(size = size), title = BAR_CHART_TITLE ) } @@ -82,6 +82,13 @@ internal object Mock { ) } + fun lineChartSimple(size: Int = 10): ChartDataSet { + return ChartDataSet( + items = mockList(size = size), + title = LINE_CHART_TITLE + ) + } + fun lineChartInvalid(): MultiChartDataSet { val items = listOf( FIRST_ITEM_NAME to FIRST_ITEM.dropLast(1), @@ -98,9 +105,9 @@ internal object Mock { ) } - fun pieChart(): ChartDataSet { + fun pieChart(size: Int = 9): ChartDataSet { return ChartDataSet( - items = mockList(size = 9, minFloat = 7f, maxFloat = 54f), + items = mockList(size = size, minFloat = 7f, maxFloat = 54f), title = PIE_CHART_TITLE ) } diff --git a/charts/src/commonMain/kotlin/io/github/dautovicharis/charts/BarChartView.kt b/charts/src/commonMain/kotlin/io/github/dautovicharis/charts/BarChartView.kt index aaf8837..22276ff 100644 --- a/charts/src/commonMain/kotlin/io/github/dautovicharis/charts/BarChartView.kt +++ b/charts/src/commonMain/kotlin/io/github/dautovicharis/charts/BarChartView.kt @@ -11,7 +11,9 @@ import io.github.dautovicharis.charts.common.model.ChartDataSet import io.github.dautovicharis.charts.internal.NO_SELECTION import io.github.dautovicharis.charts.internal.TestTags import io.github.dautovicharis.charts.internal.barchart.BarChart +import io.github.dautovicharis.charts.internal.common.composable.ChartErrors import io.github.dautovicharis.charts.internal.common.composable.ChartView +import io.github.dautovicharis.charts.internal.validateBarData import io.github.dautovicharis.charts.style.BarChartDefaults import io.github.dautovicharis.charts.style.BarChartStyle @@ -26,6 +28,27 @@ fun BarChartView( dataSet: ChartDataSet, style: BarChartStyle = BarChartDefaults.style() ) { + + val errors by remember { + mutableStateOf( + validateBarData( + data = dataSet.data.item + ) + ) + } + + if (errors.isEmpty()) { + ChartContent(dataSet = dataSet, style = style) + } else { + ChartErrors(chartViewStyle = style.chartViewStyle, errors = errors) + } +} + +@Composable +private fun ChartContent( + dataSet: ChartDataSet, + style: BarChartStyle +) { var title by remember { mutableStateOf(dataSet.data.label) } ChartView(chartViewsStyle = style.chartViewStyle) { Text( diff --git a/charts/src/commonMain/kotlin/io/github/dautovicharis/charts/internal/DataValidation.kt b/charts/src/commonMain/kotlin/io/github/dautovicharis/charts/internal/DataValidation.kt index 5b26fcb..2d6a952 100644 --- a/charts/src/commonMain/kotlin/io/github/dautovicharis/charts/internal/DataValidation.kt +++ b/charts/src/commonMain/kotlin/io/github/dautovicharis/charts/internal/DataValidation.kt @@ -4,6 +4,8 @@ import io.github.dautovicharis.charts.common.model.ChartDataSet import io.github.dautovicharis.charts.internal.ValidationErrors.MIN_REQUIRED_BAR import io.github.dautovicharis.charts.internal.ValidationErrors.MIN_REQUIRED_LINE import io.github.dautovicharis.charts.internal.ValidationErrors.MIN_REQUIRED_PIE +import io.github.dautovicharis.charts.internal.ValidationErrors.MIN_REQUIRED_STACKED_BAR +import io.github.dautovicharis.charts.internal.common.model.ChartData import io.github.dautovicharis.charts.internal.common.model.MultiChartData import io.github.dautovicharis.charts.style.LineChartStyle import io.github.dautovicharis.charts.style.PieChartStyle @@ -14,11 +16,13 @@ internal object ValidationErrors { const val RULE_CATEGORIES_SIZE_MISMATCH: String = "Categories size %d does not match expected %d." const val RULE_COLORS_SIZE_MISMATCH: String = "Colors size %d does not match expected %d." - const val RULE_DATA_POINTS_LESS_THAN_MIN: String = "Data points size should be greater than %d." + const val RULE_DATA_POINTS_LESS_THAN_MIN: String = + "Data points size should be greater than or equal to %d." const val MIN_REQUIRED_PIE: Int = 2 const val MIN_REQUIRED_LINE: Int = 2 - const val MIN_REQUIRED_BAR: Int = 1 + const val MIN_REQUIRED_STACKED_BAR: Int = 1 + const val MIN_REQUIRED_BAR: Int = 2 } internal fun String.format(vararg args: Any?): String { @@ -56,12 +60,25 @@ internal fun validateBarData( return validateChartData( data = data, pointsSize = firstPointsSize, - minRequiredPointsSize = MIN_REQUIRED_BAR, + minRequiredPointsSize = MIN_REQUIRED_STACKED_BAR, colorsSize = colorsSize, expectedColorsSize = firstPointsSize ) } +internal fun validateBarData(data: ChartData): List { + val validationErrors = mutableListOf() + val pointsSize = data.points.size + + if (pointsSize < MIN_REQUIRED_BAR) { + val validationError = + ValidationErrors.RULE_DATA_POINTS_LESS_THAN_MIN.format(MIN_REQUIRED_PIE) + validationErrors.add(validationError) + return validationErrors + } + return validationErrors +} + internal fun validatePieData( dataSet: ChartDataSet, style: PieChartStyle diff --git a/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/ui/BarChartTest.kt b/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/ui/BarChartTest.kt index 0fdcb47..ae296c9 100644 --- a/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/ui/BarChartTest.kt +++ b/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/ui/BarChartTest.kt @@ -4,9 +4,15 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.assertTextEquals import androidx.compose.ui.test.isDisplayed import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.runComposeUiTest import io.github.dautovicharis.charts.BarChartView +import io.github.dautovicharis.charts.common.model.ChartDataSet import io.github.dautovicharis.charts.internal.TestTags +import io.github.dautovicharis.charts.internal.ValidationErrors.MIN_REQUIRED_LINE +import io.github.dautovicharis.charts.internal.ValidationErrors.RULE_DATA_POINTS_LESS_THAN_MIN +import io.github.dautovicharis.charts.internal.format +import io.github.dautovicharis.charts.mock.MockTest.TITLE import io.github.dautovicharis.charts.mock.MockTest.dataSet import kotlin.test.Test @@ -28,4 +34,21 @@ class BarChartTest { onNodeWithTag(TestTags.CHART_TITLE) .assertTextEquals(expectedTitle).isDisplayed() } + + @OptIn(ExperimentalTestApi::class) + @Test + fun barChart_withInvalidData_displaysError () = runComposeUiTest { + val dataSet = ChartDataSet( + items = listOf(1f), + title = TITLE + ) + val expectedError = RULE_DATA_POINTS_LESS_THAN_MIN.format(MIN_REQUIRED_LINE) + + setContent { + BarChartView(dataSet) + } + + onNodeWithTag(TestTags.CHART_ERROR).isDisplayed() + onNodeWithText("${expectedError}\n").isDisplayed() + } } diff --git a/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/ui/LineChartTest.kt b/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/ui/LineChartTest.kt index b1f55bd..3d71f37 100644 --- a/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/ui/LineChartTest.kt +++ b/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/ui/LineChartTest.kt @@ -7,14 +7,13 @@ import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.runComposeUiTest import io.github.dautovicharis.charts.LineChartView +import io.github.dautovicharis.charts.common.model.ChartDataSet import io.github.dautovicharis.charts.internal.TestTags -import io.github.dautovicharis.charts.internal.ValidationErrors.RULE_COLORS_SIZE_MISMATCH -import io.github.dautovicharis.charts.internal.ValidationErrors.RULE_ITEM_POINTS_SIZE +import io.github.dautovicharis.charts.internal.ValidationErrors.MIN_REQUIRED_LINE +import io.github.dautovicharis.charts.internal.ValidationErrors.RULE_DATA_POINTS_LESS_THAN_MIN import io.github.dautovicharis.charts.internal.format -import io.github.dautovicharis.charts.mock.MockTest.colors +import io.github.dautovicharis.charts.mock.MockTest.TITLE import io.github.dautovicharis.charts.mock.MockTest.dataSet -import io.github.dautovicharis.charts.mock.MockTest.invalidMultiDataSet -import io.github.dautovicharis.charts.style.LineChartDefaults import kotlin.test.Test class LineChartTest { @@ -39,34 +38,18 @@ class LineChartTest { @OptIn(ExperimentalTestApi::class) @Test - fun lineChart_withInvalidData_displaysError() = runComposeUiTest { - // Arrange - val dataSet = invalidMultiDataSet() - val index = 1 - val colors = colors.drop(1) - - val expectedPointsSize = dataSet.data.items.first().item.points.size - val pointsSize = dataSet.data.items[index].item.points.size - val expectedPointsError = RULE_ITEM_POINTS_SIZE.format(index, pointsSize, expectedPointsSize) - - val expectedColorsSize = dataSet.data.items.size - val colorsSize = colors.size - val expectedColorsError = RULE_COLORS_SIZE_MISMATCH.format(colorsSize, expectedColorsSize) + fun lineChart_withInvalidData_displaysError () = runComposeUiTest { + val dataSet = ChartDataSet( + items = listOf(1f), + title = TITLE + ) + val expectedError = RULE_DATA_POINTS_LESS_THAN_MIN.format(MIN_REQUIRED_LINE) - // Act setContent { - val style = LineChartDefaults.style( - lineColors = colors - ) - LineChartView( - dataSet = dataSet, - style = style - ) + LineChartView(dataSet) } - // Assert onNodeWithTag(TestTags.CHART_ERROR).isDisplayed() - onNodeWithText("${expectedPointsError}\n").isDisplayed() - onNodeWithText("${expectedColorsError}\n").isDisplayed() + onNodeWithText("${expectedError}\n").isDisplayed() } } diff --git a/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/ui/MultiLineChartTest.kt b/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/ui/MultiLineChartTest.kt index 9e4f74f..ebb5ef6 100644 --- a/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/ui/MultiLineChartTest.kt +++ b/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/ui/MultiLineChartTest.kt @@ -4,10 +4,17 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.assertTextEquals import androidx.compose.ui.test.isDisplayed import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.runComposeUiTest import io.github.dautovicharis.charts.LineChartView import io.github.dautovicharis.charts.internal.TestTags +import io.github.dautovicharis.charts.internal.ValidationErrors.RULE_COLORS_SIZE_MISMATCH +import io.github.dautovicharis.charts.internal.ValidationErrors.RULE_ITEM_POINTS_SIZE +import io.github.dautovicharis.charts.internal.format +import io.github.dautovicharis.charts.mock.MockTest.colors +import io.github.dautovicharis.charts.mock.MockTest.invalidMultiDataSet import io.github.dautovicharis.charts.mock.MockTest.multiDataSet +import io.github.dautovicharis.charts.style.LineChartDefaults import kotlin.test.Test class MultiLineChartTest { @@ -29,4 +36,42 @@ class MultiLineChartTest { .assertTextEquals(expectedTitle) .isDisplayed() } + + @OptIn(ExperimentalTestApi::class) + @Test + fun multiLineChart_withInvalidData_displaysError() = runComposeUiTest { + // Arrange + val dataSet = invalidMultiDataSet() + val colors = colors.drop(1) + val firstIndex = 1 + val thirdIndex = 3 + + val pointsSizeFirst = dataSet.data.items[firstIndex].item.points.size + val pointsSizeThird = dataSet.data.items[thirdIndex].item.points.size + val expectedPointsSize = dataSet.data.items.first().item.points.size + + val expectedPointsErrorFirst = RULE_ITEM_POINTS_SIZE.format(firstIndex, pointsSizeFirst, expectedPointsSize) + val expectedPointsErrorSecond = RULE_ITEM_POINTS_SIZE.format(thirdIndex, pointsSizeThird, expectedPointsSize) + + val expectedColorsSize = dataSet.data.items.size + val colorsSize = colors.size + val expectedColorsError = RULE_COLORS_SIZE_MISMATCH.format(colorsSize, expectedColorsSize) + + // Act + setContent { + val style = LineChartDefaults.style( + lineColors = colors + ) + LineChartView( + dataSet = dataSet, + style = style + ) + } + + // Assert + onNodeWithTag(TestTags.CHART_ERROR).isDisplayed() + onNodeWithText("${expectedPointsErrorFirst}\n").isDisplayed() + onNodeWithText("${expectedPointsErrorSecond}\n").isDisplayed() + onNodeWithText("${expectedColorsError}\n").isDisplayed() + } } diff --git a/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/ui/PieChartTest.kt b/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/ui/PieChartTest.kt index cbfe744..7517df9 100644 --- a/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/ui/PieChartTest.kt +++ b/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/ui/PieChartTest.kt @@ -96,7 +96,7 @@ class PieChartTest { @OptIn(ExperimentalTestApi::class) @Test - fun pieChart_withInvalidDataColors_displaysError() = runComposeUiTest { + fun pieChart_withInvalidColors_displaysError() = runComposeUiTest { // Arrange val colors = colors.drop(2) val pieChartStyle = mockPieChartStyle(colors) diff --git a/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/ui/StackedBarChartTest.kt b/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/ui/StackedBarChartTest.kt index 8ba3ab6..55b9a48 100644 --- a/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/ui/StackedBarChartTest.kt +++ b/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/ui/StackedBarChartTest.kt @@ -4,10 +4,17 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.assertTextEquals import androidx.compose.ui.test.isDisplayed import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.runComposeUiTest import io.github.dautovicharis.charts.StackedBarChartView import io.github.dautovicharis.charts.internal.TestTags +import io.github.dautovicharis.charts.internal.ValidationErrors.RULE_COLORS_SIZE_MISMATCH +import io.github.dautovicharis.charts.internal.ValidationErrors.RULE_ITEM_POINTS_SIZE +import io.github.dautovicharis.charts.internal.format +import io.github.dautovicharis.charts.mock.MockTest.colors +import io.github.dautovicharis.charts.mock.MockTest.invalidMultiDataSet import io.github.dautovicharis.charts.mock.MockTest.multiDataSet +import io.github.dautovicharis.charts.style.StackedBarChartDefaults import kotlin.test.Test class StackedBarChartTest { @@ -29,4 +36,59 @@ class StackedBarChartTest { .assertTextEquals(expectedTitle) .isDisplayed() } + + @OptIn(ExperimentalTestApi::class) + @Test + fun stackedBarChart_withInvalidData_displaysError () = runComposeUiTest { + // Arrange + val dataSet = invalidMultiDataSet() + val firstIndex = 1 + val thirdIndex = 3 + + val pointsSizeFirst = dataSet.data.items[firstIndex].item.points.size + val pointsSizeThird = dataSet.data.items[thirdIndex].item.points.size + val expectedPointsSize = dataSet.data.items.first().item.points.size + + val expectedPointsErrorFirst = RULE_ITEM_POINTS_SIZE.format(firstIndex, pointsSizeFirst, expectedPointsSize) + val expectedPointsErrorSecond = RULE_ITEM_POINTS_SIZE.format(thirdIndex, pointsSizeThird, expectedPointsSize) + + // Act + setContent { + val style = StackedBarChartDefaults.style() + StackedBarChartView( + dataSet = dataSet, + style = style + ) + } + + // Assert + onNodeWithTag(TestTags.CHART_ERROR).isDisplayed() + onNodeWithText("${expectedPointsErrorFirst}\n").isDisplayed() + onNodeWithText("${expectedPointsErrorSecond}\n").isDisplayed() + } + + @OptIn(ExperimentalTestApi::class) + @Test + fun stackedBarChart_withInvalidColors_displaysError () = runComposeUiTest { + // Arrange + val dataSet = multiDataSet + val colors = colors.drop(1) + + val expectedColorsSize = dataSet.data.items.size + val colorsSize = colors.size + val expectedColorsError = RULE_COLORS_SIZE_MISMATCH.format(colorsSize, expectedColorsSize) + + // Act + setContent { + val style = StackedBarChartDefaults.style(barColors = colors) + StackedBarChartView( + dataSet = dataSet, + style = style + ) + } + + // Assert + onNodeWithTag(TestTags.CHART_ERROR).isDisplayed() + onNodeWithText("${expectedColorsError}\n").isDisplayed() + } } diff --git a/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/unit/validation/DataValidationBarTest.kt b/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/unit/validation/DataValidationBarTest.kt index 9b9b5f7..d8f48cd 100644 --- a/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/unit/validation/DataValidationBarTest.kt +++ b/charts/src/commonTest/kotlin/io/github/dautovicharis/charts/unit/validation/DataValidationBarTest.kt @@ -1,7 +1,7 @@ package io.github.dautovicharis.charts.unit.validation import io.github.dautovicharis.charts.internal.ValidationErrors -import io.github.dautovicharis.charts.internal.ValidationErrors.MIN_REQUIRED_BAR +import io.github.dautovicharis.charts.internal.ValidationErrors.MIN_REQUIRED_STACKED_BAR import io.github.dautovicharis.charts.internal.format import io.github.dautovicharis.charts.internal.validateBarData import io.github.dautovicharis.charts.mock.MockTest.colors @@ -88,7 +88,7 @@ class DataValidationBarTest { // Assert val expectedError = - ValidationErrors.RULE_DATA_POINTS_LESS_THAN_MIN.format(MIN_REQUIRED_BAR) + ValidationErrors.RULE_DATA_POINTS_LESS_THAN_MIN.format(MIN_REQUIRED_STACKED_BAR) assertTrue(validationErrors.isNotEmpty()) assertEquals(validationErrors.first(), expectedError) }