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