1 /*
2 * Copyright (C) 2023 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 package com.android.intentresolver.validation
17
18 import android.util.Log
19 import com.android.intentresolver.validation.Importance.CRITICAL
20 import com.android.intentresolver.validation.Importance.WARNING
21 import kotlin.reflect.KClass
22
23 sealed interface Finding {
24 val importance: Importance
25 val message: String
26 }
27
28 enum class Importance {
29 CRITICAL,
30 WARNING,
31 }
32
33 val Finding.logcatPriority
34 get() =
35 when (importance) {
36 CRITICAL -> Log.ERROR
37 WARNING -> Log.WARN
38 }
39
lognull40 fun Finding.log(tag: String) {
41 Log.println(logcatPriority, tag, message)
42 }
43
<lambda>null44 private fun formatMessage(key: String? = null, msg: String) = buildString {
45 key?.also { append("['$key']: ") }
46 append(msg)
47 }
48
49 data class IgnoredValue(
50 val key: String,
51 val reason: String,
52 ) : Finding {
53 override val importance = WARNING
54
55 override val message: String
56 get() = formatMessage(key, "Ignored. $reason")
57 }
58
59 data class NoValue(
60 val key: String,
61 override val importance: Importance,
62 val allowedType: KClass<*>,
63 ) : Finding {
64
65 override val message: String
66 get() =
67 formatMessage(
68 key,
69 if (importance == CRITICAL) {
70 "expected value of ${allowedType.simpleName}, " + "but no value was present"
71 } else {
72 "no ${allowedType.simpleName} value present"
73 }
74 )
75 }
76
77 data class WrongElementType(
78 val key: String,
79 override val importance: Importance,
80 val container: KClass<*>,
81 val actualType: KClass<*>,
82 val expectedType: KClass<*>
83 ) : Finding {
84 override val message: String
85 get() =
86 formatMessage(
87 key,
88 "${container.simpleName} expected with elements of " +
89 "${expectedType.simpleName} " +
90 "but found ${actualType.simpleName} values instead"
91 )
92 }
93
94 data class ValueIsWrongType(
95 val key: String,
96 override val importance: Importance,
97 val actualType: KClass<*>,
98 val allowedTypes: List<KClass<*>>,
99 ) : Finding {
100
101 override val message: String
102 get() =
103 formatMessage(
104 key,
105 "expected value of ${allowedTypes.map(KClass<*>::simpleName)} " +
106 "but was ${actualType.simpleName}"
107 )
108 }
109
110 data class UncaughtException(val thrown: Throwable, val key: String? = null) : Finding {
111 override val importance: Importance
112 get() = CRITICAL
113 override val message: String
114 get() =
115 formatMessage(
116 key,
117 "An unhandled exception was caught during validation: " +
118 thrown.stackTraceToString()
119 )
120 }
121