• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.server.wm.flicker.assertions
18 
19 import com.android.server.wm.flicker.TraceFile
20 import com.android.server.wm.flicker.dsl.AssertionTag
21 import com.android.server.wm.flicker.traces.FlickerSubjectException
22 import com.google.common.truth.Fact
23 import java.io.ByteArrayOutputStream
24 import java.io.PrintStream
25 
26 class FlickerAssertionErrorBuilder {
27     private var error: Throwable? = null
28     private var traceFile: TraceFile? = null
29     private var tag = ""
30 
31     fun fromError(error: Throwable): FlickerAssertionErrorBuilder = apply {
32         this.error = error
33     }
34 
35     fun withTrace(traceFile: TraceFile?): FlickerAssertionErrorBuilder = apply {
36         this.traceFile = traceFile
37     }
38 
39     fun atTag(tag: String): FlickerAssertionErrorBuilder = apply {
40         this.tag = when (tag) {
41             AssertionTag.START -> "before transition (initial state)"
42             AssertionTag.END -> "after transition (final state)"
43             AssertionTag.ALL -> "during transition"
44             else -> "at user-defined location ($tag)"
45         }
46     }
47 
48     fun build(): FlickerAssertionError {
49         return FlickerAssertionError(errorMessage, rootCause, traceFile)
50     }
51 
52     private val errorMessage get() = buildString {
53         val error = error
54         requireNotNull(error)
55         if (error is FlickerSubjectException) {
56             appendLine(error.errorType)
57             appendLine()
58             append(error.errorDescription)
59             appendLine()
60             append(error.subjectInformation)
61             append("\t").appendLine(Fact.fact("Location", tag))
62             appendLine()
63         } else {
64             appendLine(error.message)
65         }
66         append("Trace file:").append(traceFileMessage)
67         appendLine()
68         appendLine("Cause:")
69         append(rootCauseStackTrace)
70         appendLine()
71         appendLine("Full stacktrace:")
72         appendLine()
73     }
74 
75     private val traceFileMessage get() = buildString {
76         traceFile?.traceFile?.let {
77             append("\t")
78             append(it)
79         }
80     }
81 
82     private val rootCauseStackTrace: String get() {
83         val rootCause = rootCause
84         return if (rootCause != null) {
85             val baos = ByteArrayOutputStream()
86             PrintStream(baos, true)
87                     .use { ps -> rootCause.printStackTrace(ps) }
88             "\t$baos"
89         } else {
90             ""
91         }
92     }
93 
94     /**
95      * In some paths the exceptions are encapsulated by the Truth subjects
96      * To make sure the correct error is printed, located the first non-subject
97      * related exception and use that as cause.
98      */
99     private val rootCause: Throwable? get() {
100         var childCause: Throwable? = this.error?.cause
101         if (childCause != null && childCause is FlickerSubjectException) {
102             childCause = childCause.cause
103         }
104         return childCause
105     }
106 }
107