1 /*
2 * Copyright 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 @file:Suppress("DEPRECATION")
18
19 package com.google.accompanist.themeadapter.material3
20
21 import androidx.appcompat.app.AppCompatActivity
22 import androidx.compose.foundation.shape.CornerSize
23 import androidx.compose.foundation.shape.CutCornerShape
24 import androidx.compose.foundation.shape.RoundedCornerShape
25 import androidx.compose.material3.LocalContentColor
26 import androidx.compose.material3.MaterialTheme
27 import androidx.compose.ui.geometry.Size
28 import androidx.compose.ui.platform.LocalDensity
29 import androidx.compose.ui.res.colorResource
30 import androidx.compose.ui.test.junit4.createAndroidComposeRule
31 import androidx.compose.ui.text.font.Font
32 import androidx.compose.ui.text.font.FontFamily
33 import androidx.compose.ui.text.font.FontWeight
34 import androidx.compose.ui.text.font.toFontFamily
35 import androidx.compose.ui.unit.Density
36 import androidx.compose.ui.unit.Dp
37 import androidx.compose.ui.unit.TextUnit
38 import androidx.compose.ui.unit.dp
39 import androidx.compose.ui.unit.em
40 import androidx.compose.ui.unit.sp
41 import com.google.accompanist.themeadapter.core.FontFamilyWithWeight
42 import com.google.accompanist.themeadapter.material3.test.R
43 import org.junit.Assert.assertEquals
44 import org.junit.Assert.assertNotNull
45 import org.junit.Assert.assertNull
46 import org.junit.Assert.assertTrue
47 import org.junit.Rule
48 import org.junit.Test
49
50 /**
51 * Class which contains the majority of the tests. This class is extended
52 * in both the `androidTest` and `test` source sets for setup of the relevant
53 * test runner.
54 */
55 abstract class BaseMdc3ThemeTest<T : AppCompatActivity>(
56 activityClass: Class<T>
57 ) {
58 @get:Rule
59 val composeTestRule = createAndroidComposeRule(activityClass)
60
61 @Test
<lambda>null62 fun colors() = composeTestRule.setContent {
63 Mdc3Theme {
64 val colorScheme = MaterialTheme.colorScheme
65
66 assertEquals(colorResource(R.color.aquamarine), colorScheme.primary)
67 assertEquals(colorResource(R.color.pale_turquoise), colorScheme.onPrimary)
68 assertEquals(colorResource(R.color.midnight_blue), colorScheme.inversePrimary)
69 assertEquals(colorResource(R.color.royal_blue), colorScheme.primaryContainer)
70 assertEquals(colorResource(R.color.steel_blue), colorScheme.onPrimaryContainer)
71
72 assertEquals(colorResource(R.color.dodger_blue), colorScheme.secondary)
73 assertEquals(colorResource(R.color.dark_golden_rod), colorScheme.onSecondary)
74 assertEquals(colorResource(R.color.peru), colorScheme.secondaryContainer)
75 assertEquals(colorResource(R.color.blue_violet), colorScheme.onSecondaryContainer)
76
77 assertEquals(colorResource(R.color.dark_orchid), colorScheme.tertiary)
78 assertEquals(colorResource(R.color.slate_gray), colorScheme.onTertiary)
79 assertEquals(colorResource(R.color.gray), colorScheme.tertiaryContainer)
80 assertEquals(colorResource(R.color.spring_green), colorScheme.onTertiaryContainer)
81
82 assertEquals(colorResource(R.color.medium_spring_green), colorScheme.background)
83 assertEquals(colorResource(R.color.navy), colorScheme.onBackground)
84
85 assertEquals(colorResource(R.color.dark_blue), colorScheme.surface)
86 assertEquals(colorResource(R.color.light_coral), colorScheme.onSurface)
87 assertEquals(colorResource(R.color.salmon), colorScheme.surfaceVariant)
88 assertEquals(colorResource(R.color.dark_salmon), colorScheme.onSurfaceVariant)
89 assertEquals(colorResource(R.color.indian_red), colorScheme.surfaceTint)
90 assertEquals(colorResource(R.color.light_salmon), colorScheme.inverseSurface)
91 assertEquals(colorResource(R.color.orchid), colorScheme.inverseOnSurface)
92
93 assertEquals(colorResource(R.color.violet), colorScheme.outline)
94 // TODO: MDC-Android doesn't include outlineVariant yet, add when available
95
96 assertEquals(colorResource(R.color.beige), colorScheme.error)
97 assertEquals(colorResource(R.color.white_smoke), colorScheme.onError)
98 assertEquals(colorResource(R.color.olive), colorScheme.errorContainer)
99 assertEquals(colorResource(R.color.olive_drab), colorScheme.onErrorContainer)
100
101 assertEquals(colorResource(R.color.crimson), colorScheme.scrim)
102
103 // Mdc3Theme updates the LocalContentColor to match the calculated onBackground
104 assertEquals(colorResource(R.color.navy), LocalContentColor.current)
105 }
106 }
107
108 @Test
<lambda>null109 fun shapes() = composeTestRule.setContent {
110 Mdc3Theme {
111 val shapes = MaterialTheme.shapes
112 val density = LocalDensity.current
113
114 shapes.extraSmall.run {
115 assertTrue(this is RoundedCornerShape)
116 assertEquals(4f, topStart.toPx(density))
117 assertEquals(9.dp.scaleToPx(density), topEnd.toPx(density))
118 assertEquals(5f, bottomEnd.toPx(density))
119 assertEquals(3.dp.scaleToPx(density), bottomStart.toPx(density))
120 }
121 shapes.small.run {
122 assertTrue(this is CutCornerShape)
123 assertEquals(4f, topStart.toPx(density))
124 assertEquals(9.dp.scaleToPx(density), topEnd.toPx(density))
125 assertEquals(5f, bottomEnd.toPx(density))
126 assertEquals(3.dp.scaleToPx(density), bottomStart.toPx(density))
127 }
128 shapes.medium.run {
129 assertTrue(this is RoundedCornerShape)
130 assertEquals(12.dp.scaleToPx(density), topStart.toPx(density))
131 assertEquals(12.dp.scaleToPx(density), topEnd.toPx(density))
132 assertEquals(12.dp.scaleToPx(density), bottomEnd.toPx(density))
133 assertEquals(12.dp.scaleToPx(density), bottomStart.toPx(density))
134 }
135 shapes.large.run {
136 assertTrue(this is CutCornerShape)
137 assertEquals(16.dp.scaleToPx(density), topStart.toPx(density))
138 assertEquals(16.dp.scaleToPx(density), topEnd.toPx(density))
139 assertEquals(16.dp.scaleToPx(density), bottomEnd.toPx(density))
140 assertEquals(16.dp.scaleToPx(density), bottomStart.toPx(density))
141 }
142 shapes.extraLarge.run {
143 assertTrue(this is RoundedCornerShape)
144 assertEquals(28.dp.scaleToPx(density), topStart.toPx(density))
145 assertEquals(28.dp.scaleToPx(density), topEnd.toPx(density))
146 assertEquals(28.dp.scaleToPx(density), bottomEnd.toPx(density))
147 assertEquals(28.dp.scaleToPx(density), bottomStart.toPx(density))
148 }
149 }
150 }
151
152 @Test
<lambda>null153 fun type() = composeTestRule.setContent {
154 Mdc3Theme {
155 val typography = MaterialTheme.typography
156 val density = LocalDensity.current
157
158 val rubik300 = Font(R.font.rubik_300).toFontFamily()
159 val rubik400 = Font(R.font.rubik_400).toFontFamily()
160 val rubik500 = Font(R.font.rubik_500).toFontFamily()
161 val rubik700 = Font(R.font.rubik_700).toFontFamily()
162 val sansSerif = FontFamilyWithWeight(FontFamily.SansSerif)
163 val sansSerifLight = FontFamilyWithWeight(FontFamily.SansSerif, FontWeight.Light)
164 val sansSerifBlack = FontFamilyWithWeight(FontFamily.SansSerif, FontWeight.Black)
165 val serif = FontFamilyWithWeight(FontFamily.Serif)
166 val cursive = FontFamilyWithWeight(FontFamily.Cursive)
167 val monospace = FontFamilyWithWeight(FontFamily.Monospace)
168
169 typography.displayLarge.run {
170 assertTextUnitEquals(97.54.sp, fontSize, density)
171 assertTextUnitEquals((-0.0015).em, letterSpacing, density)
172 assertEquals(rubik300, fontFamily)
173 }
174
175 assertNotNull(typography.displayMedium.shadow)
176 typography.displayMedium.shadow!!.run {
177 assertEquals(colorResource(R.color.olive_drab), color)
178 assertEquals(4.43f, offset.x)
179 assertEquals(8.19f, offset.y)
180 assertEquals(2.13f, blurRadius)
181 }
182
183 typography.displaySmall.run {
184 assertEquals(sansSerif.fontFamily, fontFamily)
185 assertEquals(sansSerif.weight, fontWeight)
186 }
187
188 typography.headlineLarge.run {
189 assertEquals(sansSerifLight.fontFamily, fontFamily)
190 assertEquals(sansSerifLight.weight, fontWeight)
191 }
192
193 typography.headlineMedium.run {
194 assertEquals(sansSerifLight.fontFamily, fontFamily)
195 assertEquals(sansSerifLight.weight, fontWeight)
196 }
197
198 typography.headlineSmall.run {
199 assertEquals(sansSerifBlack.fontFamily, fontFamily)
200 assertEquals(sansSerifBlack.weight, fontWeight)
201 }
202
203 typography.titleLarge.run {
204 assertEquals(serif.fontFamily, fontFamily)
205 assertEquals(serif.weight, fontWeight)
206 }
207
208 typography.titleMedium.run {
209 assertEquals(monospace.fontFamily, fontFamily)
210 assertEquals(monospace.weight, fontWeight)
211 assertTextUnitEquals(0.em, letterSpacing, density)
212 }
213
214 typography.titleSmall.run {
215 assertEquals(FontFamily.SansSerif, fontFamily)
216 }
217
218 typography.bodyLarge.run {
219 assertTextUnitEquals(16.26.sp, fontSize, density)
220 assertTextUnitEquals(0.005.em, letterSpacing, density)
221 assertEquals(rubik400, fontFamily)
222 assertNull(shadow)
223 }
224
225 typography.bodyMedium.run {
226 assertEquals(cursive.fontFamily, fontFamily)
227 assertEquals(cursive.weight, fontWeight)
228 }
229
230 typography.bodySmall.run {
231 assertEquals(FontFamily.SansSerif, fontFamily)
232 assertTextUnitEquals(0.04.em, letterSpacing, density)
233 }
234
235 typography.labelLarge.run {
236 assertEquals(rubik500, fontFamily)
237 }
238
239 typography.labelMedium.run {
240 assertEquals(rubik700, fontFamily)
241 }
242
243 typography.labelSmall.run {
244 assertEquals(FontFamily.SansSerif, fontFamily)
245 }
246 }
247 }
248 }
249
Dpnull250 private fun Dp.scaleToPx(density: Density): Float {
251 val dp = this
252 return with(density) { dp.toPx() }
253 }
254
assertTextUnitEqualsnull255 private fun assertTextUnitEquals(expected: TextUnit, actual: TextUnit, density: Density) {
256 if (expected.javaClass == actual.javaClass) {
257 // If the expected and actual are the same type, compare the raw values with a
258 // delta to account for float inaccuracy
259 assertEquals(expected.value, actual.value, 0.001f)
260 } else {
261 // Otherwise we need to flatten to a px to compare the values. Again using a
262 // delta to account for float inaccuracy
263 with(density) { assertEquals(expected.toPx(), actual.toPx(), 0.001f) }
264 }
265 }
266
toPxnull267 private fun CornerSize.toPx(density: Density) = toPx(Size.Unspecified, density)
268