1 /*
2  * Copyright (C) 2024 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 android.tools.flicker.junit
18 
19 import android.tools.Scenario
20 import android.tools.flicker.datastore.DataStore
21 import android.tools.flicker.legacy.FlickerBuilder
22 import android.tools.flicker.legacy.LegacyFlickerTest
23 import java.lang.reflect.Modifier
24 import org.junit.runner.Description
25 import org.junit.runners.model.FrameworkMethod
26 import org.junit.runners.model.Statement
27 import org.junit.runners.model.TestClass
28 
29 class LegacyFlickerDecorator(
30     testClass: TestClass,
31     val scenario: Scenario?,
32     val transitionRunner: ITransitionRunner,
33     inner: IFlickerJUnitDecorator? = null
34 ) : AbstractFlickerRunnerDecorator(testClass, inner) {
getChildDescriptionnull35     override fun getChildDescription(method: FrameworkMethod): Description {
36         return inner?.getChildDescription(method)
37             ?: error("Need inner to provide child description")
38     }
39 
getTestMethodsnull40     override fun getTestMethods(test: Any): List<FrameworkMethod> {
41         return inner?.getTestMethods(test) ?: error("Need inner to provide test methods")
42     }
43 
getMethodInvokernull44     override fun getMethodInvoker(method: FrameworkMethod, test: Any): Statement {
45         return object : Statement() {
46             override fun evaluate() {
47                 requireNotNull(scenario) { "Expected to have a scenario to run" }
48                 val description = getChildDescription(method)
49                 if (!android.tools.flicker.datastore.DataStore.containsResult(scenario)) {
50                     transitionRunner.runTransition(scenario, test, description)
51                 }
52                 inner?.getMethodInvoker(method, test)?.evaluate()
53             }
54         }
55     }
56 
doValidateConstructornull57     override fun doValidateConstructor(): List<Throwable> {
58         val errors = super.doValidateConstructor().toMutableList()
59         val ctor = testClass.javaClass.constructors.firstOrNull()
60         if (ctor?.parameterTypes?.none { it == LegacyFlickerTest::class.java } != false) {
61             errors.add(
62                 IllegalStateException(
63                     "Constructor should have a parameter of type " +
64                         LegacyFlickerTest::class.java.simpleName
65                 )
66             )
67         }
68         return errors
69     }
70 
doValidateInstanceMethodsnull71     override fun doValidateInstanceMethods(): List<Throwable> {
72         val errors = super.doValidateInstanceMethods().toMutableList()
73 
74         val methods = getCandidateProviderMethods(testClass)
75 
76         if (methods.isEmpty() || methods.size > 1) {
77             val prefix = if (methods.isEmpty()) "One" else "Only one"
78             errors.add(
79                 IllegalArgumentException(
80                     "$prefix object should be annotated with @FlickerBuilderProvider"
81                 )
82             )
83         } else {
84             val method = methods.first()
85 
86             if (Modifier.isStatic(method.method.modifiers)) {
87                 errors.add(IllegalArgumentException("Method ${method.name}() should not be static"))
88             }
89             if (!Modifier.isPublic(method.method.modifiers)) {
90                 errors.add(IllegalArgumentException("Method ${method.name}() should be public"))
91             }
92             if (method.returnType != FlickerBuilder::class.java) {
93                 errors.add(
94                     IllegalArgumentException(
95                         "Method ${method.name}() should return a " +
96                             "${FlickerBuilder::class.java.simpleName} object"
97                     )
98                 )
99             }
100             if (method.method.parameterTypes.isNotEmpty()) {
101                 errors.add(
102                     IllegalArgumentException("Method ${method.name} should have no parameters")
103                 )
104             }
105         }
106 
107         return errors
108     }
109 
110     private val providerMethod: FrameworkMethod
111         get() =
112             getCandidateProviderMethods(testClass).firstOrNull()
113                 ?: error("Provider method not found")
114 
115     companion object {
getCandidateProviderMethodsnull116         private fun getCandidateProviderMethods(testClass: TestClass): List<FrameworkMethod> =
117             testClass.getAnnotatedMethods(FlickerBuilderProvider::class.java) ?: emptyList()
118     }
119 }
120