7f645807创建于 2025年10月27日历史提交
/*
 * 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.

/**
 * @file
 *
 * This is a library for class JsonNull, JsonBool, JsonInt, JsonFloat, JsonString, JsonArray, JsonObject.
 */
package std.unittest.common

import std.collection.*

/*
 * Space for JSON output.
 */
const SPACE: Rune = r' '

/*
 * Size of indentation in JSON format.
 */
const INDENT_SIZE: Int64 = 2

/**
 * JsonNull class used for encapsulate JSON data: null.
 */
protected class JsonNull <: JsonValue {

    /**
     * Determine the JSON type to which the JsonNull belongs.
     *
     * @return type of the JsonNull is JsNull.
     *
     * @since 0.17.4
     */
    public func kind(): JsonKind {
        return JsNull
    }

    /**
     * Convert JsonNull to String.
     *
     * @return json-converted String is "".
     *
     * @since 0.17.4
     */
    public func toString(): String {
        return "null"
    }

    /**
     * Convert JsonNull to json-String.
     *
     * @return json-converted prettified String is "".
     *
     * @since 0.21.1
     */
    public func toJsonString(): String {
        return toString()
    }
}

/**
 * JsonBool class used for encapsulate JSON data: true or false.
 */
protected class JsonBool <: JsonValue {
    /* Json data of the JsonBool(Bool). */
    private var value: Bool

    /**
     * Create a new JsonBool object.
     * Construction with parameters.
     *
     * @param bv The json data of JsonBool.
     *
     * @since 0.17.4
     */
    public init(bv: Bool) {
        this.value = bv
    }

    /**
     * Get the value data of the JsonBool.
     *
     * @return value of the JsonBool.
     *
     * @since 0.17.4
     */
    public func getValue(): Bool {
        return value
    }

    /**
     * Determine the JSON type to which the JsonBool belongs.
     *
     * @return type of the JsonBool is JsBool.
     *
     * @since 0.17.4
     */
    public func kind(): JsonKind {
        return JsBool
    }

    /**
     * Convert JsonBool to String.
     *
     * @return json-converted String is value string data: true or false.
     *
     * @since 0.17.4
     */
    public func toString(): String {
        return value.toString()
    }

    /**
     * Convert JsonBool to json-String.
     *
     * @return json-converted prettified String is value string data: true or false.
     *
     * @since 0.21.1
     */
    public func toJsonString(): String {
        return toString()
    }
}

/**
 * JsonInt class used for encapsulate JSON data: number(integer).
 */
protected class JsonInt <: JsonValue {
    /* Json data of the JsonInt(Int64). */
    private var value: Int64

    /**
     * Create a new JsonInt object.
     * Construction with parameters.
     *
     * @param iv The json data of JsonInt.
     *
     * @since 0.17.4
     */
    public init(iv: Int64) {
        this.value = iv
    }

    /**
     * Get the value data of the JsonInt.
     *
     * @return value of the JsonInt.
     *
     * @since 0.17.4
     */
    public func getValue(): Int64 {
        return value
    }

    /**
     * Determine the JSON type to which the JsonInt belongs.
     *
     * @return type of the JsonInt is JsInt.
     *
     * @since 0.17.4
     */
    public func kind(): JsonKind {
        return JsInt
    }

    /**
     * Convert JsonInt to String.
     *
     * @return json-converted String is value string data.
     *
     * @since 0.17.4
     */
    public func toString(): String {
        return value.toString()
    }

    /**
     * Convert JsonInt to json-String.
     *
     * @return json-converted prettified String is value string data.
     *
     * @since 0.21.1
     */
    public func toJsonString(): String {
        return toString()
    }
}

/**
 * JsonFloat class used for encapsulate JSON data: number(float).
 */
protected class JsonFloat <: JsonValue {
    /* Json data of the JsonFloat(Float64). */
    private var value: Float64

    /**
     * Create a new JsonFloat object.
     * Construction with parameters.
     *
     * @param fv The json data of JsonFloat.
     *
     * @since 0.17.4
     */
    public init(fv: Float64) {
        this.value = fv
    }

    /**
     * Create a new JsonFloat object.
     * Construction with parameters.
     *
     * @param v The json data of JsonInt.
     *
     * @since 0.17.4
     */
    public init(v: Int64) {
        this.value = Float64(v)
    }

    /**
     * Get the value data of the JsonFloat.
     *
     * @return value of the JsonFloat.
     *
     * @since 0.17.4
     */
    public func getValue(): Float64 {
        return value
    }

    /**
     * Determine the JSON type to which the JsonFloat belongs.
     *
     * @return type of the JsonFloat is JsFloat.
     *
     * @since 0.17.4
     */
    public func kind(): JsonKind {
        return JsFloat
    }

    /**
     * Convert JsonFloat to String.
     *
     * @return json-converted String is value string data.
     *
     * @since 0.17.4
     */
    public func toString(): String {
        return value.toString()
    }

    /**
     * Convert JsonFloat to json-String.
     *
     * @return json-converted prettified String is value string data.
     *
     * @since 0.21.1
     */
    public func toJsonString(): String {
        return toString()
    }
}

/**
 * JsonString class used for encapsulate JSON data: string.
 */
protected class JsonString <: JsonValue {
    /* Json data of the JsonString(String). */
    var value: String

    /**
     * Create a new JsonString object.
     * Construction with parameters.
     *
     * @param sv The json data of JsonString.
     *
     * @since 0.17.4
     */
    public init(sv: String) {
        this.value = sv
    }

    /**
     * Get the value data of the JsonString.
     *
     * @return value of the JsonString.
     *
     * @since 0.17.4
     */
    public func getValue(): String {
        return value
    }

    /**
     * Determine the JSON type to which the JsonString belongs.
     *
     * @return type of the JsonString is JsString.
     *
     * @since 0.17.4
     */
    public func kind(): JsonKind {
        return JsString
    }

    /**
     * Convert JsonString to String.
     *
     * @return json-converted String is value string data.
     *
     * @since 0.17.4
     */
    public func toString(): String {
        let buff = WriteBuffer(value.size + 2)
        jsonWriteWithoutFormat(this, buff)
        return unsafe { String.fromUtf8Unchecked(buff.getAndClear()) }
    }

    /**
     * Convert JsonString to json-String.
     *
     * @return json-converted prettified String is value string data.
     *
     * @since 0.21.1
     */
    public func toJsonString(): String {
        let buff = WriteBuffer(value.size + 2)
        jsonWriteWithoutFormat(this, buff)
        return unsafe { String.fromUtf8Unchecked(buff.getAndClear()) }
    }
}

/**
 * JsonArray class used for encapsulate JSON data: array.
 */
protected class JsonArray <: JsonValue {
    /* Json data of the JsonArray(ArrayList<JsonValue>). */
    private var items: ArrayList<JsonValue>

    /**
     * Create a new JsonArray object.
     * Construction without parameters.
     *
     * @since 0.17.4
     */
    init(capacity: Int64) {
        items = ArrayList<JsonValue>(capacity)
    }

    public init() {
        items = ArrayList<JsonValue>()
    }
    /**
     * Create a new JsonArray object.
     * Construction with parameters.
     *
     * @param list type ArrayList<JsonValue>, the json data of JsonArray.
     *
     * @since 0.17.4
     */
    public init(list: ArrayList<JsonValue>) {
        items = list
    }

    /**
     * Create a new JsonArray object.
     * Construction with parameters.
     *
     * @param list type Array<JsonValue>,The json data of JsonArray.
     *
     * @since 0.17.4
     */
    public init(list: Array<JsonValue>) {
        items = ArrayList<JsonValue>(list)
    }

    /**
     * Determine the JSON type to which the JsonArray belongs.
     *
     * @return type of the JsonArray is JsArray.
     *
     * @since 0.17.4
     */
    public func kind(): JsonKind {
        return JsArray
    }

    /**
     * Convert JsonArray to Json-String.
     *
     * @return json-converted String is items string data.
     *
     * @since 0.17.4
     *
     * @throws JsonException if there exists JsonValue which cannot be converted to String.
     */
    public func toJsonString(): String {
        return toJsonString(0)
    }

    /**
     * Convert JsonArray to Json-String.
     *
     * @param depth of indentation in JSON format.
     * @return json-converted String is items string data.
     *
     * @since 0.17.4
     *
     * @throws JsonException if there exists JsonValue which cannot be converted to String.
     */
    public func toJsonString(depth: Int64, bracketInNewLine!: Bool = false, indent!: String = "  "): String {
        if (depth < 0) {
            throw IllegalArgumentException("Depth cannot be negative.")
        }
        if (!indent.isContainOnlySpaceAndTab()) {
            throw IllegalArgumentException("Indent must be an empty string or any combination of spaces and tabs.")
        }
        let buff = WriteBuffer(asumecapacity(this))
        jsonWriteArray(this, buff, depth, bracketInNewLine, indent)
        return unsafe { String.fromUtf8Unchecked(buff.getAndClear()) }
    }

    /**
     * Convert JsonArray to String.
     *
     * @return json-converted String is items string data.
     *
     * @since 0.21.1
     *
     * @throws JsonException if there exists JsonValue which cannot be converted to String.
     */
    public func toString(): String {
        let buff = WriteBuffer(asumecapacity(this))
        jsonWriteWithoutFormat(this, buff)
        return unsafe { String.fromUtf8Unchecked(buff.getAndClear()) }
    }

    /**
     * Get the size of JsonArray.
     *
     * @return the size of items.
     *
     * @since 0.17.4
     */
    public func size(): Int64 {
        return items.size
    }

    /**
     * Add the Data to JsonArray.
     *
     * @param jv JsonValue data to be added.
     *
     * @since 0.17.4
     */
    public func add(jv: JsonValue): JsonArray {
        items.add(jv)
        return this
    }

    /**
     * Obtains the option version of JsonValue data of JsonArray at a specified location.
     *
     * @param index Index position.
     * @return get the option version of element of the index.
     *
     * @since 0.17.4
     */
    public func get(index: Int64): Option<JsonValue> {
        return items.get(index)
    }

    /**
     * Obtains JsonValue data of JsonArray at a specified location.
     *
     * @param index Index position.
     * @return get the element of the index.
     *
     * @since 0.17.4
     *
     * @throws JsonException if index of JsonArray does not exist.
     */
    public operator func [](index: Int64): JsonValue {
        return match (items.get(index)) {
            case Some(v) => v
            case None => throw JsonException("The index ${index} of JsonArray does not exist.")
        }
    }

    /**
     * Get the items data of JsonArray.
     *
     * @return the items of JsonArray.
     *
     * @since 0.17.4
     */
    public func getItems(): ArrayList<JsonValue> {
        return items
    }
}

/**
 * JsonObject class used for encapsulate JSON data: object.
 */
protected class JsonObject <: JsonValue {
    /* Json data of the JsonObject(HashMap<String,JsonValue>). */
    private var fields: HashMap<String, JsonValue>

    /**
     * Create a new JsonObject object.
     * Construction without parameters.
     *
     * @since 0.17.4
     */
    public init() {
        fields = HashMap<String, JsonValue>()
    }

    init(capacity: Int64) {
        fields = HashMap<String, JsonValue>(capacity)
    }

    /**
     * Create a new JsonObject object.
     * Construction with parameters.
     *
     * @param map The json data of JsonObject.
     *
     * @since 0.17.4
     */
    public init(map: HashMap<String, JsonValue>) {
        fields = map
    }

    /**
     * Determine the JSON type to which the JsonObject belongs.
     *
     * @return type of the JsonObject is JsObject.
     *
     * @since 0.17.4
     */
    public func kind(): JsonKind {
        return JsObject
    }

    /**
     * Convert JsonObject to Json-String.
     *
     * @return json-converted String is fields string data.
     *
     * @since 0.17.4
     *
     * @throws JsonException if there exists JsonValue which cannot be converted to String.
     */
    public func toJsonString(): String {
        return toJsonString(0)
    }

    /**
     * Convert JsonObject to Json-String.
     *
     * @param depth of indentation in JSON format.
     * @return json-converted String is fields string data.
     *
     * @since 0.17.4
     *
     * @throws JsonException if there exists JsonValue which cannot be converted to String.
     */
    public func toJsonString(depth: Int64, bracketInNewLine!: Bool = false, indent!: String = "  "): String {
        if (depth < 0) {
            throw IllegalArgumentException("Depth cannot be negative.")
        }
        if (!indent.isContainOnlySpaceAndTab()) {
            throw IllegalArgumentException("Indent must be an empty string or any combination of spaces and tabs.")
        }
        let buff = WriteBuffer(asumecapacity(this))
        jsonWriteObject(this, buff, depth, bracketInNewLine, indent)
        return unsafe { String.fromUtf8Unchecked(buff.getAndClear()) }
    }

    /**
     * Convert JsonObject to String.
     *
     * @return json-converted String is fields string data.
     *
     * @since 0.21.1
     *
     * @throws JsonException if there exists JsonValue which cannot be converted to String.
     */
    public func toString(): String {
        let buff = WriteBuffer(asumecapacity(this))
        jsonWriteWithoutFormat(this, buff)
        return unsafe { String.fromUtf8Unchecked(buff.getAndClear()) }
    }

    /**
     * Get the size of JsonObject.
     *
     * @return the size of fields.
     *
     * @since 0.17.4
     */
    public func size(): Int64 {
        return fields.size
    }

    /**
     * Check whether the JsonObject contains a key.
     *
     * @param key Key position.
     * @return check whether the fields contains the key.
     *
     * @since 0.17.4
     */
    public func containsKey(key: String): Bool {
        return fields.contains(key)
    }

    /**
     * Put the Data to JsonObject.
     *
     * @param key Key position.
     * @param v JsonValue data.
     *
     * @since 0.17.4
     */
    public func put(key: String, v: JsonValue): Unit {
        fields.add(key, v)
    }

    /**
     * Obtains the option version of JsonValue data of JsonObject at a specified location.
     *
     * @param key Key position.
     * @return get option version of data corresponding to the key.
     *
     * @since 0.17.4
     */
    public func get(key: String): Option<JsonValue> {
        return fields.get(key)
    }

    /**
     * Obtains JsonValue data of JsonObject at a specified location.
     *
     * @param key Key position.
     * @return get data corresponding to the key.
     *
     * @since 0.17.4
     *
     * @throws JsonException if key of JsonObject does not exist.
     */
    public operator func [](key: String): JsonValue {
        return match (fields.get(key)) {
            case Some(v) => v
            case None => throw JsonException("The Value of JsonObject does not exist")
        }
    }

    /**
     * Get the fields data of JsonObject.
     *
     * @return the fields of JsonObject.
     *
     * @since 0.17.4
     */
    public func getFields(): HashMap<String, JsonValue> {
        return fields
    }
}

extend String {
    func isContainOnlySpaceAndTab() {
        for (i in this) {
            if (i != b' ' && i != b'\t') {
                return false
            }
        }
        return true
    }
}