/*
* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
* This source file is part of the Cangjie project, licensed under Apache-2.0
* with Runtime Library Exception.
*
* See https://cangjie-lang.cn/pages/LICENSE for license information.
*/
// The Cangjie API is in Beta. For details on its capabilities and limitations, please refer to the README file.
package std.unittest
import std.unittest.common.PrettyText
import std.unittest.mock.PrettyException
func renderException(exception: Exception, preamble: ?PrettyText): PrettyText {
let text = PrettyText()
if (let Some(preamble) <- preamble) {
text.append(preamble)
}
if (let Some(prettyError) <- (exception as PrettyException)) {
text.append(prettyError)
} else {
text.append(exceptionToString(exception))
}
text
}
func exceptionToString(e: Exception): String {
let traceElementArray: Array<StackTraceElement> = e.getStackTrace()
var msg = StringBuilder("An exception has occurred:${e}\n")
let indexAfterLast = indexOfFirstIrrelevantEntry(traceElementArray)
for (index in 0..indexAfterLast) {
let element = traceElementArray[index]
let declaringClass = element.declaringClass
let fileName = element.fileName
let lineNumber = element.lineNumber.toString()
msg.append("\tat ${declaringClass}.${methodName(element)}(${fileName}:${lineNumber})")
if (index != indexAfterLast - 1) {
msg.append("\n")
}
}
return msg.toString()
}
func indexOfFirstIrrelevantEntry(elements: Array<StackTraceElement>): Int64 {
var index = elements.size - 1
while (index > 0) {
let element = elements[index]
if (index == elements.size - 1 && isEntryPoint(element)) {
index--
continue
}
let frameInsideUnittest = elements[index].declaringClass.startsWith("std.unittest")
if (frameInsideUnittest) {
index--
continue
}
let hasAnyFramesInsideUnittest = index != (elements.size - 1)
if (hasAnyFramesInsideUnittest) {
if (isLambda(element)) {
// this wrapping lambda is the last irrelevant entry
return index
} else {
return index + 1
}
} else {
return elements.size
}
}
return elements.size
}
@When[backend == "cjnative"]
func isEntryPoint(_: StackTraceElement): Bool {
false
}
@When[backend == "cjnative"]
func isLambda(element: StackTraceElement): Bool {
element.methodName.startsWith("lambda.")
}
@When[backend == "cjnative"]
func methodName(element: StackTraceElement): String {
element.methodName.replace("::", ".")
}