1 /*
<lambda>null2  * Copyright (C) 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  *      http://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 package com.android.compose.theme
18 
19 import android.content.Context
20 import androidx.annotation.AttrRes
21 import androidx.compose.material3.ColorScheme
22 import androidx.compose.material3.MaterialTheme
23 import androidx.compose.material3.Text
24 import androidx.compose.runtime.LaunchedEffect
25 import androidx.compose.ui.graphics.Color
26 import androidx.compose.ui.platform.LocalContext
27 import androidx.compose.ui.test.assertIsDisplayed
28 import androidx.compose.ui.test.junit4.createComposeRule
29 import androidx.compose.ui.test.onNodeWithText
30 import androidx.test.ext.junit.runners.AndroidJUnit4
31 import com.android.internal.R
32 import com.google.common.truth.Truth.assertThat
33 import com.google.common.truth.Truth.assertWithMessage
34 import org.junit.Assert.assertThrows
35 import org.junit.Rule
36 import org.junit.Test
37 import org.junit.runner.RunWith
38 
39 @RunWith(AndroidJUnit4::class)
40 class PlatformThemeTest {
41     @get:Rule val composeRule = createComposeRule()
42 
43     @Test
44     fun testThemeShowsContent() {
45         composeRule.setContent { PlatformTheme { Text("foo") } }
46 
47         composeRule.onNodeWithText("foo").assertIsDisplayed()
48     }
49 
50     @Test
51     fun testAndroidColorsAreAvailableInsideTheme() {
52         composeRule.setContent {
53             PlatformTheme { Text("foo", color = LocalAndroidColorScheme.current.primaryFixed) }
54         }
55 
56         composeRule.onNodeWithText("foo").assertIsDisplayed()
57     }
58 
59     @Test
60     fun testAccessingAndroidColorsWithoutThemeThrows() {
61         assertThrows(IllegalStateException::class.java) {
62             composeRule.setContent {
63                 Text("foo", color = LocalAndroidColorScheme.current.primaryFixed)
64             }
65         }
66     }
67 
68     @Test
69     fun testMaterialColorsMatchAttributeValue() {
70         val colorValues = mutableListOf<ColorValue>()
71 
72         fun onLaunch(colorScheme: ColorScheme, context: Context) {
73             fun addValue(name: String, materialValue: Color, @AttrRes attr: Int) {
74                 colorValues.add(ColorValue(name, materialValue, colorAttr(context, attr)))
75             }
76 
77             addValue("primary", colorScheme.primary, R.attr.materialColorPrimary)
78             addValue("onPrimary", colorScheme.onPrimary, R.attr.materialColorOnPrimary)
79             addValue(
80                 "primaryContainer",
81                 colorScheme.primaryContainer,
82                 R.attr.materialColorPrimaryContainer,
83             )
84             addValue(
85                 "onPrimaryContainer",
86                 colorScheme.onPrimaryContainer,
87                 R.attr.materialColorOnPrimaryContainer,
88             )
89             addValue(
90                 "inversePrimary",
91                 colorScheme.inversePrimary,
92                 R.attr.materialColorInversePrimary,
93             )
94             addValue("secondary", colorScheme.secondary, R.attr.materialColorSecondary)
95             addValue("onSecondary", colorScheme.onSecondary, R.attr.materialColorOnSecondary)
96             addValue(
97                 "secondaryContainer",
98                 colorScheme.secondaryContainer,
99                 R.attr.materialColorSecondaryContainer,
100             )
101             addValue(
102                 "onSecondaryContainer",
103                 colorScheme.onSecondaryContainer,
104                 R.attr.materialColorOnSecondaryContainer,
105             )
106             addValue("tertiary", colorScheme.tertiary, R.attr.materialColorTertiary)
107             addValue("onTertiary", colorScheme.onTertiary, R.attr.materialColorOnTertiary)
108             addValue(
109                 "tertiaryContainer",
110                 colorScheme.tertiaryContainer,
111                 R.attr.materialColorTertiaryContainer,
112             )
113             addValue(
114                 "onTertiaryContainer",
115                 colorScheme.onTertiaryContainer,
116                 R.attr.materialColorOnTertiaryContainer,
117             )
118             addValue("onBackground", colorScheme.onBackground, R.attr.materialColorOnBackground)
119             addValue("surface", colorScheme.surface, R.attr.materialColorSurface)
120             addValue("onSurface", colorScheme.onSurface, R.attr.materialColorOnSurface)
121             addValue(
122                 "surfaceVariant",
123                 colorScheme.surfaceVariant,
124                 R.attr.materialColorSurfaceVariant,
125             )
126             addValue(
127                 "onSurfaceVariant",
128                 colorScheme.onSurfaceVariant,
129                 R.attr.materialColorOnSurfaceVariant,
130             )
131             addValue(
132                 "inverseSurface",
133                 colorScheme.inverseSurface,
134                 R.attr.materialColorInverseSurface,
135             )
136             addValue(
137                 "inverseOnSurface",
138                 colorScheme.inverseOnSurface,
139                 R.attr.materialColorInverseOnSurface,
140             )
141             addValue("error", colorScheme.error, R.attr.materialColorError)
142             addValue("onError", colorScheme.onError, R.attr.materialColorOnError)
143             addValue(
144                 "errorContainer",
145                 colorScheme.errorContainer,
146                 R.attr.materialColorErrorContainer,
147             )
148             addValue(
149                 "onErrorContainer",
150                 colorScheme.onErrorContainer,
151                 R.attr.materialColorOnErrorContainer,
152             )
153             addValue("outline", colorScheme.outline, R.attr.materialColorOutline)
154             addValue(
155                 "outlineVariant",
156                 colorScheme.outlineVariant,
157                 R.attr.materialColorOutlineVariant,
158             )
159             addValue("surfaceBright", colorScheme.surfaceBright, R.attr.materialColorSurfaceBright)
160             addValue("surfaceDim", colorScheme.surfaceDim, R.attr.materialColorSurfaceDim)
161             addValue(
162                 "surfaceContainer",
163                 colorScheme.surfaceContainer,
164                 R.attr.materialColorSurfaceContainer,
165             )
166             addValue(
167                 "surfaceContainerHigh",
168                 colorScheme.surfaceContainerHigh,
169                 R.attr.materialColorSurfaceContainerHigh,
170             )
171             addValue(
172                 "surfaceContainerHighest",
173                 colorScheme.surfaceContainerHighest,
174                 R.attr.materialColorSurfaceContainerHighest,
175             )
176             addValue(
177                 "surfaceContainerLow",
178                 colorScheme.surfaceContainerLow,
179                 R.attr.materialColorSurfaceContainerLow,
180             )
181             addValue(
182                 "surfaceContainerLowest",
183                 colorScheme.surfaceContainerLowest,
184                 R.attr.materialColorSurfaceContainerLowest,
185             )
186         }
187 
188         composeRule.setContent {
189             PlatformTheme {
190                 val colorScheme = MaterialTheme.colorScheme
191                 val context = LocalContext.current
192 
193                 LaunchedEffect(Unit) { onLaunch(colorScheme, context) }
194             }
195         }
196 
197         assertThat(colorValues).hasSize(33)
198         colorValues.forEach { colorValue ->
199             assertWithMessage(
200                     "MaterialTheme.colorScheme.${colorValue.name} matches attribute color"
201                 )
202                 .that(colorValue.materialValue)
203                 .isEqualTo(colorValue.attrValue)
204         }
205     }
206 
207     private data class ColorValue(val name: String, val materialValue: Color, val attrValue: Color)
208 }
209