/*
* 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.mock
import std.collection.HashMap
public class SyntheticField<T> {
SyntheticField(let description: SyntheticFieldDescription) {}
public static func create(initialValue!: T): SyntheticField<T> {
SyntheticField(SyntheticFieldDescription(initialValue))
}
}
class SyntheticFieldDescription {
let id = _FRAMEWORK.generateUniqueId()
SyntheticFieldDescription(
let initialValue: Any
) {}
}
class FieldStorage {
private let explicitFields = HashMap<UInt64, Box<Any>>()
private let autoFields = HashMap<AutoFieldId, Box<Any>>()
func getExplicitFieldValue(fieldDescription: SyntheticFieldDescription): Any {
getOrCreateExplicitFieldBox(fieldDescription).value
}
func setExplicitFieldValue(fieldDescription: SyntheticFieldDescription, value: Any): Unit {
getOrCreateExplicitFieldBox(fieldDescription).value = value
}
private func getOrCreateExplicitFieldBox(fieldDescription: SyntheticFieldDescription): Box<Any> {
match (explicitFields.get(fieldDescription.id)) {
case Some(existingStorage) => existingStorage
case None =>
let newStorage = Box<Any>(fieldDescription.initialValue)
explicitFields[fieldDescription.id] = newStorage
newStorage
}
}
func getAutoFieldValue(id: AutoFieldId): ?Any {
autoFields.get(id)?.value
}
func setAutoFieldValue(id: AutoFieldId, value: Any): Unit {
match (autoFields.get(id)) {
case Some(existingStorage) =>
existingStorage.value = value
case None =>
let newStorage = Box<Any>(value)
autoFields[id] = newStorage
}
}
}
struct AutoFieldId <: Hashable & Equatable<AutoFieldId> {
AutoFieldId(
private let mockObjectId: UInt64,
private let memberName: String
) {}
init(mockObject: MockObject, memberName: String) {
this(mockObject.id, memberName)
}
@OverflowWrapping
public func hashCode(): Int64 {
return Int64(mockObjectId) + 31 * memberName.hashCode()
}
public operator func ==(that: AutoFieldId): Bool {
return this.mockObjectId == that.mockObjectId && this.memberName == that.memberName
}
public operator func !=(that: AutoFieldId): Bool {
return this.mockObjectId != that.mockObjectId || this.memberName != that.memberName
}
}
class FieldsErrorReport <: FailureReport {
func errorReadingField(invocation: Invocation) {
let funcInfo = invocation.call.funcInfo
if (!funcInfo.isGetter) {
internalError("Must be a field or property getter")
}
if (funcInfo.hasSetter) {
valueNotSet(invocation)
} else {
mustUseStubs(invocation)
}
}
func valueNotSet(invocation: Invocation): PrettyException {
let text = build {
errorHeader("Unhandled invocation")
line {
renderInvocationWithLocation(invocation)
}
line {
text("Trying to read value of")
renderDeclarationNameAndKind(invocation.call.funcInfo, getterSetterPrefix: false)
text("before it was set")
}
}
return UnhandledCallException(text)
}
func mustUseStubs(invocation: Invocation): PrettyException {
let text = build {
errorHeader("Unhandled invocation")
line {
renderInvocationWithLocation(invocation)
}
line {
text("Trying to read value of readonly")
renderDeclarationNameAndKind(invocation.call.funcInfo, getterSetterPrefix: false)
}
line {
text("Use stubs to define the value.")
}
}
return UnhandledCallException(text)
}
}