1 /*
<lambda>null2  * Copyright (C) 2021 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 androidx.constraintlayout.compose
18 
19 import android.content.Context
20 import androidx.compose.foundation.layout.Box
21 import androidx.compose.foundation.layout.size
22 import androidx.compose.ui.Modifier
23 import androidx.compose.ui.layout.layoutId
24 import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
25 import androidx.compose.ui.test.junit4.createComposeRule
26 import androidx.compose.ui.unit.IntSize
27 import androidx.compose.ui.unit.dp
28 import androidx.constraintlayout.core.parser.CLParser
29 import androidx.constraintlayout.core.parser.CLParsingException
30 import androidx.constraintlayout.core.state.TransitionParser
31 import androidx.test.core.app.ApplicationProvider
32 import androidx.test.ext.junit.runners.AndroidJUnit4
33 import androidx.test.filters.MediumTest
34 import kotlin.test.assertFailsWith
35 import org.junit.After
36 import org.junit.Before
37 import org.junit.Rule
38 import org.junit.Test
39 import org.junit.runner.RunWith
40 
41 @MediumTest
42 @RunWith(AndroidJUnit4::class)
43 internal class MotionParserTest {
44     @get:Rule val rule = createComposeRule()
45 
46     var displaySize: IntSize = IntSize.Zero
47 
48     // region sizing tests
49 
50     @Before
51     fun before() {
52         isDebugInspectorInfoEnabled = true
53         displaySize =
54             ApplicationProvider.getApplicationContext<Context>().resources.displayMetrics.let {
55                 IntSize(it.widthPixels, it.heightPixels)
56             }
57     }
58 
59     @After
60     fun after() {
61         isDebugInspectorInfoEnabled = false
62     }
63 
64     @OptIn(ExperimentalMotionApi::class)
65     @Test
66     fun testTransitionParseFailsSilently() {
67         // We don't want applications to hard-crash when the parser sees an error
68         var coreTransition = androidx.constraintlayout.core.state.Transition { dp -> dp }
69         val transitionContent =
70             """
71             {
72               from: "start",
73               to: "end",
74               KeyFrames: {
75                 KeyAttributes: [{
76                   target: ['id1'],
77                   frames: [10, 20],
78                   alpha: [0.5,],
79                 }],
80               }
81             }
82         """
83                 .trimIndent()
84         // Parsing transition throws an exception but the Composable should not crash the app
85         assertFailsWith<CLParsingException> {
86             TransitionParser.parse(CLParser.parse(transitionContent), coreTransition)
87         }
88         coreTransition = androidx.constraintlayout.core.state.Transition { dp -> dp }
89         rule.setContent {
90             val transition = Transition(content = transitionContent)
91             MotionLayout(
92                 modifier = Modifier.size(100.dp),
93                 start =
94                     ConstraintSet(
95                         """
96                     {
97                       id1: {
98                         width: 10, height: 10,
99                         centerVertically: 'parent', start: ['parent', 'start', 0]
100                       }
101                     }
102                 """
103                             .trimIndent()
104                     ),
105                 end =
106                     ConstraintSet(
107                         """
108                     {
109                       id1: {
110                         width: 10, height: 10,
111                         centerVertically: 'parent', end: ['parent', 'end', 0]
112                       }
113                     }
114                 """
115                             .trimIndent()
116                     ),
117                 transition = transition,
118                 progress = 0f
119             ) {
120                 Box(modifier = Modifier.layoutId("id1"))
121             }
122         }
123         // Test should finish without exceptions
124         rule.waitForIdle()
125     }
126 }
127