From bf14d4a9a1c4f2a3466b5a11ef0decd3ad433526 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 10 May 2023 20:15:08 -0400 Subject: [PATCH] Revert "Implemented Json to Tlv and Tlv to Json Converter in Kotlin (#26458)" (#26492) This reverts commit 60866e88614ef729472f683d7710d9647e2cd020. https://github.com/project-chip/connectedhomeip/pull/26458 was merged with failing CI, and the failure is in the files the PR added. CI is now permanently failing. --- examples/java-matter-controller/BUILD.gn | 3 +- src/controller/java/BUILD.gn | 35 +- .../java/src/chip/json/JsonToTlv.kt | 201 -- .../java/src/chip/json/TlvToJson.kt | 205 --- src/controller/java/src/chip/tlv/utils.kt | 16 +- .../tests/chip/json/JsonToTlvToJsonTest.kt | 1630 ----------------- third_party/java_deps/BUILD.gn | 6 +- third_party/java_deps/set_up_java_deps.sh | 3 +- 8 files changed, 6 insertions(+), 2093 deletions(-) delete mode 100644 src/controller/java/src/chip/json/JsonToTlv.kt delete mode 100644 src/controller/java/src/chip/json/TlvToJson.kt delete mode 100644 src/controller/java/tests/chip/json/JsonToTlvToJsonTest.kt diff --git a/examples/java-matter-controller/BUILD.gn b/examples/java-matter-controller/BUILD.gn index 92ae40df938568..cdb67f1b8ed41d 100644 --- a/examples/java-matter-controller/BUILD.gn +++ b/examples/java-matter-controller/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2022-2023 Project CHIP Authors +# Copyright (c) 2022 Project CHIP Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -38,7 +38,6 @@ kotlin_binary("java-matter-controller") { output_name = "java-matter-controller" deps = [ ":java", - "${chip_root}/src/controller/java:json_to_tlv_to_json_test", "${chip_root}/src/controller/java:tlv_read_write_test", "${chip_root}/src/controller/java:tlv_reader_test", "${chip_root}/src/controller/java:tlv_writer_test", diff --git a/src/controller/java/BUILD.gn b/src/controller/java/BUILD.gn index a92ec4164aae43..84565a2bf18e08 100644 --- a/src/controller/java/BUILD.gn +++ b/src/controller/java/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2020-2023 Project CHIP Authors +# Copyright (c) 2020-2021 Project CHIP Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -204,39 +204,6 @@ kotlin_library("tlv_read_write_test") { kotlinc_flags = [ "-Xlint:deprecation" ] } -kotlin_library("json") { - output_name = "libCHIPJson.jar" - - deps = [ - ":tlv", - "${chip_root}/third_party/java_deps:gson", - ] - - sources = [ - "src/chip/json/JsonToTlv.kt", - "src/chip/json/TlvToJson.kt", - ] - - kotlinc_flags = [ "-Xlint:deprecation" ] -} - -kotlin_library("json_to_tlv_to_json_test") { - output_name = "JsonToTlvToJsonTest.jar" - - deps = [ - ":json", - ":tlv", - "${chip_root}/third_party/java_deps:gson", - "${chip_root}/third_party/java_deps:junit-4", - "${chip_root}/third_party/java_deps:kotlin-test", - "${chip_root}/third_party/java_deps:truth", - ] - - sources = [ "tests/chip/json/JsonToTlvToJsonTest.kt" ] - - kotlinc_flags = [ "-Xlint:deprecation" ] -} - android_library("java") { output_name = "CHIPController.jar" diff --git a/src/controller/java/src/chip/json/JsonToTlv.kt b/src/controller/java/src/chip/json/JsonToTlv.kt deleted file mode 100644 index 4ef5889ecf2c5b..00000000000000 --- a/src/controller/java/src/chip/json/JsonToTlv.kt +++ /dev/null @@ -1,201 +0,0 @@ -/* - * - * Copyright (c) 2023 Project CHIP Authors - * Copyright (c) 2023 Google LLC. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package chip.json - -import com.google.gson.JsonArray -import com.google.gson.JsonElement -import com.google.gson.JsonObject -import com.google.gson.JsonParser -import com.google.protobuf.ByteString -import java.util.Base64 - -/** - * Implements Matter JSON to TLV converter. - * - * Note that NOT all TLV configurations are supported by the current implementation. Below is the - * list of limitations: - * - TLV Lists are not supported - * - Multi-Dimensional TLV Arrays are not supported - * - All elements of an array MUST be of the same type - * - The top level TLV element MUST be a single structure with AnonymousTag - * - The following tags are supported: - * - AnonymousTag are used only with TLV Arrays elements or a top-level structure - * - ContextSpecificTag are used only with TLV Structure elements - * - CommonProfileTag are used only with TLV Structure elements - * - Infinity Float/Double values are not supported - * - * @param json string representing Json encoded data to be converted into TLV format - * @throws IllegalArgumentException if the data was invalid - */ -fun TlvWriter.fromJsonString(json: String): ByteArray { - validateIsJsonObjectAndConvert(JsonParser.parseString(json), AnonymousTag) - return validateTlv().getEncoded() -} - -/** - * Converts Json Object into TLV Structure or TLV top level elements. - * - * @param json object to be converted to TLV. - * @throws IllegalArgumentException if the data was invalid - */ -private fun TlvWriter.fromJson(json: JsonObject): TlvWriter { - json.keySet().forEach { key -> - val (tag, type, subType) = extractTagAndTypeFromJsonKey(key) - fromJson(json.get(key), tag, type, subType) - } - return this -} - -/** - * Converts Json Array into TLV Array. - * - * @param json object to be converted to TLV. - * @param type Type of array elements. - * @throws IllegalArgumentException if the data was invalid - */ -private fun TlvWriter.fromJson(json: JsonArray, type: String): TlvWriter { - json.iterator().forEach { element -> fromJson(element, AnonymousTag, type) } - return this -} - -/** - * Converts Json Element into TLV Array. - * - * @param element element to be converted to TLV. - * @param tag element tag. - * @param type element type. - * @param subType array elements type. Only relevant when type is an Array. Should be empty string - * in all other cases. - * @throws IllegalArgumentException if the data was invalid - */ -private fun TlvWriter.fromJson(element: JsonElement, tag: Tag, type: String, subType: String = "") { - when (type) { - JSON_VALUE_TYPE_INT -> put(tag, validateIsNumber(element).toLong()) - JSON_VALUE_TYPE_UINT -> put(tag, validateIsNumber(element).toLong().toULong()) - JSON_VALUE_TYPE_BOOL -> put(tag, validateIsBoolean(element)) - JSON_VALUE_TYPE_FLOAT -> put(tag, validateIsDouble(element).toFloat()) - JSON_VALUE_TYPE_DOUBLE -> put(tag, validateIsDouble(element)) - JSON_VALUE_TYPE_BYTES -> put(tag, validateIsString(element).base64Encode()) - JSON_VALUE_TYPE_STRING -> put(tag, validateIsString(element)) - JSON_VALUE_TYPE_NULL -> validateIsNullAndPut(element, tag) - JSON_VALUE_TYPE_STRUCT -> validateIsJsonObjectAndConvert(element, tag) - JSON_VALUE_TYPE_ARRAY -> { - if (subType.isEmpty()) { - throw IllegalArgumentException("Multi-Dimensional JSON Array is Invalid") - } else { - require(element.isJsonArray()) { "Expected Array; the actual element is: $element" } - startArray(tag).fromJson(element.getAsJsonArray(), subType).endArray() - } - } - JSON_VALUE_TYPE_EMPTY -> - throw IllegalArgumentException("Empty array was expected but there is value: $element}") - else -> throw IllegalArgumentException("Invalid type was specified: $type") - } -} - -/** - * Extracts tag and type fields from Json key. Valid JSON key SHOULD have 1, 2, or 3 fields - * constracted as [name:][tag:]type[-subtype] - * - * @param key Json element key value. - * @throws IllegalArgumentException if the key format was invalid - */ -private fun extractTagAndTypeFromJsonKey(key: String): Triple { - val keyFields = key.split(":") - var type = keyFields.last() - val typeFields = type.split("-") - var subType = "" - - val tagNumber = - when (keyFields.size) { - 2 -> keyFields.first().toUIntOrNull() - 3 -> keyFields[1].toUIntOrNull() - else -> throw IllegalArgumentException("Invalid JSON key value: $key") - } - - val tag = - when { - tagNumber == null -> throw IllegalArgumentException("Invalid JSON key value: $key") - tagNumber <= UByte.MAX_VALUE.toUInt() -> ContextSpecificTag(tagNumber.toInt()) - tagNumber <= UShort.MAX_VALUE.toUInt() -> CommonProfileTag(2, tagNumber) - else -> CommonProfileTag(4, tagNumber) - } - - // Valid type field of the JSON key SHOULD have type and optional subtype component - require(typeFields.size in (1..2)) { "Invalid JSON key value: $key" } - - if (typeFields.size == 2) { - require(typeFields[0] == JSON_VALUE_TYPE_ARRAY) { "Invalid JSON key value: $key" } - type = JSON_VALUE_TYPE_ARRAY - subType = typeFields[1] - } - - return Triple(tag, type, subType) -} - -private fun String.base64Encode(): ByteString { - return ByteString.copyFrom(Base64.getDecoder().decode(this)) -} - -/** Verifies JsonElement is Number. If yes, returns the value. */ -private fun validateIsNumber(element: JsonElement): Number { - require( - element.isJsonPrimitive() && - (element.getAsJsonPrimitive().isNumber() || element.getAsJsonPrimitive().isString()) - ) { - "Expected Integer represented as a Number or as a String; the actual element is: $element" - } - return element.getAsJsonPrimitive().getAsNumber() -} - -/** Verifies JsonElement is Boolean. If yes, returns the value. */ -private fun validateIsBoolean(element: JsonElement): Boolean { - require(element.isJsonPrimitive() && element.getAsJsonPrimitive().isBoolean()) { - "Expected Boolean; the actual element is: $element" - } - return element.getAsJsonPrimitive().getAsBoolean() -} - -/** Verifies JsonElement is Double. If yes, returns the value. */ -private fun validateIsDouble(element: JsonElement): Double { - require(element.isJsonPrimitive() && element.getAsJsonPrimitive().isNumber()) { - "Expected Double; the actual element is: $element" - } - return element.getAsJsonPrimitive().getAsDouble() -} - -/** Verifies JsonElement is String. If yes, returns the value. */ -private fun validateIsString(element: JsonElement): String { - require(element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) { - "Expected String; the actual element is: $element" - } - return element.getAsJsonPrimitive().getAsString() -} - -/** Verifies JsonElement is Null. If yes, puts it into TLV. */ -private fun TlvWriter.validateIsNullAndPut(element: JsonElement, tag: Tag) { - require(element.isJsonNull()) { "Expected Null; the actual element is: $element" } - putNull(tag) -} - -/** Verifies JsonElement is JsonObject. If yes, converts it into TLV Structure. */ -private fun TlvWriter.validateIsJsonObjectAndConvert(element: JsonElement, tag: Tag) { - require(element.isJsonObject()) { "Expected JsonObject; the actual element is: $element" } - startStructure(tag).fromJson(element.getAsJsonObject()).endStructure() -} diff --git a/src/controller/java/src/chip/json/TlvToJson.kt b/src/controller/java/src/chip/json/TlvToJson.kt deleted file mode 100644 index cd1e6c30245400..00000000000000 --- a/src/controller/java/src/chip/json/TlvToJson.kt +++ /dev/null @@ -1,205 +0,0 @@ -/* - * - * Copyright (c) 2023 Project CHIP Authors - * Copyright (c) 2023 Google LLC. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package chip.json - -import com.google.gson.JsonArray -import com.google.gson.JsonNull -import com.google.gson.JsonObject -import java.util.Base64 - -/** - * Implements Matter TLV to JSON converter. - * - * Note that NOT all TLV configurations are supported by the current implementation. Below is the - * list of limitations: - * - TLV Lists are not supported - * - Multi-Dimensional TLV Arrays are not supported - * - All elements of an array MUST be of the same type - * - The top level TLV element MUST be a single structure with AnonymousTag - * - The following tags are supported: - * - AnonymousTag are used only with TLV Arrays elements or a top-level structure - * - ContextSpecificTag are used only with TLV Structure elements - * - CommonProfileTag are used only with TLV Structure elements - * - Infinity Float/Double values are not supported - * - * Rules for representing integers in the Json format: - * - If the size of the integer is less or equal to 32-bits then it is represetned as a Number. - * - If the size of the integer is larger than 32 bits then it will be represented as a String. - * - * @throws IllegalArgumentException if the data was invalid - */ -fun TlvReader.toJsonString(): String { - val element = nextElement() - require(element.value is StructureValue) { - "The top level element must be a structure. The actual value is ${element.value}" - } - require(element.tag is AnonymousTag) { - "The top level TLV Structure MUST have anonymous tag. The actual tag is ${element.tag}" - } - return getStructJson().toString() -} -/** - * Encodes TLV Structure into Json Object. The TLV reader should be positioned at the start of a TLV - * Structure (StructureValue element). After this call the TLV reader is positioned at the end of - * the a TLV Structure (EndOfContainerValue element). - */ -private fun TlvReader.getStructJson(): JsonObject { - var json = JsonObject() - while (!isEndOfTlv()) { - val element = nextElement() - val tag = element.tag - val value = element.value - - val key = - when (tag) { - is AnonymousTag -> "" - is ContextSpecificTag -> tag.tagNumber.toString() + ":" - is CommonProfileTag -> tag.tagNumber.toString() + ":" - else -> throw IllegalArgumentException("Unsupported TLV tag format: $tag") - } + getJsonValueTypeField(value) - - when (value) { - is IntValue -> { - if (value.value >= Int.MIN_VALUE && value.value <= Int.MAX_VALUE) { - json.addProperty(key, value.value) - } else { - json.addProperty(key, value.value.toString()) - } - } - is UnsignedIntValue -> { - if (value.value.toULong() <= UInt.MAX_VALUE.toULong()) { - json.addProperty(key, value.value) - } else { - json.addProperty(key, value.value.toULong().toString()) - } - } - is Utf8StringValue -> json.addProperty(key, value.value) - is ByteStringValue -> - json.addProperty(key, Base64.getEncoder().encodeToString(value.value.toByteArray())) - is BooleanValue -> json.addProperty(key, value.value) - is FloatValue -> json.addProperty(key, validateFloat(value.value)) - is DoubleValue -> json.addProperty(key, validateDouble(value.value)) - is StructureValue -> json.add(key, getStructJson()) - is ArrayValue -> { - val (array, type) = getArrayJsonWithElementsType() - json.add("$key-$type", array) - } - is ListValue -> - throw IllegalArgumentException("Invalid TLV element: TLV List is not supported") - is NullValue -> json.add(key, JsonNull.INSTANCE) - is EndOfContainerValue -> return json - } - } - return json -} - -/** - * Encodes TLV Array data into Json Array. The TLV reader should be positioned at the start of a TLV - * Array (ArrayValue element). After this call the TLV reader is positioned at the end of the a TLV - * Structure (EndOfContainerValue element). This method returns Json encoded array and a String - * specifying types of the elements in the array. - */ -private fun TlvReader.getArrayJsonWithElementsType(): Pair { - var json = JsonArray() - var lastValue: Value = ArrayValue - - while (!isEndOfTlv()) { - val value = nextElement().value - if (lastValue !is ArrayValue && value !is EndOfContainerValue) { - require(value::class == lastValue::class) { - "Invalid TLV element: all elements in array MUST be of the same type. Value ($value) is different from previous value ($lastValue)." - } - } - - when (value) { - is IntValue -> { - if (value.value >= Int.MIN_VALUE && value.value <= Int.MAX_VALUE) { - json.add(value.value) - } else { - json.add(value.value.toString()) - } - } - is UnsignedIntValue -> { - if (value.value.toULong() <= UInt.MAX_VALUE) { - json.add(value.value) - } else { - json.add(value.value.toULong().toString()) - } - } - is Utf8StringValue -> json.add(value.value) - is ByteStringValue -> json.add(Base64.getEncoder().encodeToString(value.value.toByteArray())) - is BooleanValue -> json.add(value.value) - is FloatValue -> json.add(validateFloat(value.value)) - is DoubleValue -> json.add(validateDouble(value.value)) - is StructureValue -> json.add(getStructJson()) - is ArrayValue -> - throw IllegalArgumentException( - "Invalid TLV element: multi-dimensional TLV Array not supported" - ) - is ListValue -> throw IllegalArgumentException("Invalid TLV Element: TLV List not supported") - is NullValue -> json.add(JsonNull.INSTANCE) - is EndOfContainerValue -> { - var subType = getJsonValueTypeField(lastValue) - if (subType == JSON_VALUE_TYPE_ARRAY) { - subType = JSON_VALUE_TYPE_EMPTY - } - return Pair(json, subType) - } - } - - lastValue = value - } - - throw IllegalArgumentException( - "Invalid TLV structure: TLV Array with last value ($lastValue) is not closed" - ) -} - -/** Returns type string that should be encoded in the Json key string for the specified value. */ -private fun getJsonValueTypeField(value: Value): String { - return when (value) { - is IntValue -> JSON_VALUE_TYPE_INT - is UnsignedIntValue -> JSON_VALUE_TYPE_UINT - is BooleanValue -> JSON_VALUE_TYPE_BOOL - is FloatValue -> JSON_VALUE_TYPE_FLOAT - is DoubleValue -> JSON_VALUE_TYPE_DOUBLE - is ByteStringValue -> JSON_VALUE_TYPE_BYTES - is Utf8StringValue -> JSON_VALUE_TYPE_STRING - is NullValue -> JSON_VALUE_TYPE_NULL - is StructureValue -> JSON_VALUE_TYPE_STRUCT - is ArrayValue -> JSON_VALUE_TYPE_ARRAY - else -> JSON_VALUE_TYPE_EMPTY - } -} - -/** Verifies that Float value is valid supported value. */ -private fun validateFloat(value: Float): Float { - require(value != Float.NEGATIVE_INFINITY && value != Float.POSITIVE_INFINITY) { - "Unsupported Float Infinity value" - } - return value -} - -/** Verifies that Double value is valid supported value. */ -private fun validateDouble(value: Double): Double { - require(value != Double.NEGATIVE_INFINITY && value != Double.POSITIVE_INFINITY) { - "Unsupported Double Infinity value" - } - return value -} diff --git a/src/controller/java/src/chip/tlv/utils.kt b/src/controller/java/src/chip/tlv/utils.kt index 3aadf79bdf621e..e68e7482045495 100644 --- a/src/controller/java/src/chip/tlv/utils.kt +++ b/src/controller/java/src/chip/tlv/utils.kt @@ -20,8 +20,8 @@ package chip.tlv /** Converts bytes in a Little Endian format into Long integer. */ internal fun ByteArray.fromLittleEndianToLong(isSigned: Boolean = false): Long = - foldRightIndexed(0) { i, value, acc -> - (acc shl 8) or (if (i == lastIndex && isSigned) value.toLong() else (value.toLong() and 0xFF)) + foldRightIndexed(0) { i, it, acc -> + (acc shl 8) or (if (i == lastIndex && isSigned) it.toLong() else (it.toLong() and 0xFF)) } /** Converts Number into a byte array in a Little Endian format. */ @@ -62,15 +62,3 @@ internal fun unsignedIntSize(value: ULong): Short { } internal fun Byte.toBinary(): String = Integer.toBinaryString(toInt() and 0xFF) - -internal const val JSON_VALUE_TYPE_INT = "INT" -internal const val JSON_VALUE_TYPE_UINT = "UINT" -internal const val JSON_VALUE_TYPE_BOOL = "BOOL" -internal const val JSON_VALUE_TYPE_FLOAT = "FLOAT" -internal const val JSON_VALUE_TYPE_DOUBLE = "DOUBLE" -internal const val JSON_VALUE_TYPE_BYTES = "BYTES" -internal const val JSON_VALUE_TYPE_STRING = "STRING" -internal const val JSON_VALUE_TYPE_NULL = "NULL" -internal const val JSON_VALUE_TYPE_STRUCT = "STRUCT" -internal const val JSON_VALUE_TYPE_ARRAY = "ARRAY" -internal const val JSON_VALUE_TYPE_EMPTY = "?" diff --git a/src/controller/java/tests/chip/json/JsonToTlvToJsonTest.kt b/src/controller/java/tests/chip/json/JsonToTlvToJsonTest.kt deleted file mode 100644 index 04bfb69eb809fa..00000000000000 --- a/src/controller/java/tests/chip/json/JsonToTlvToJsonTest.kt +++ /dev/null @@ -1,1630 +0,0 @@ -/* - * - * Copyright (c) 2023 Project CHIP Authors - * Copyright (c) 2023 Google LLC. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package chip.json - -import com.google.common.truth.Truth.assertThat -import com.google.gson.JsonParser -import com.google.protobuf.ByteString -import kotlin.test.assertFailsWith -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.JUnit4 - -@RunWith(JUnit4::class) -class JsonToTlvToJsonTest { - - private fun String.octetsToByteArray(): ByteArray = - replace(" ", "").chunked(2).map { it.toInt(16) and 0xFF }.map { it.toByte() }.toByteArray() - - private fun String.toByteString(): ByteString = ByteString.copyFrom(this.toByteArray()) - - private fun checkValidConversion( - jsonOriginal: String, - tlvEncoding: ByteArray, - jsonExpected: String = jsonOriginal - ) { - assertThat(TlvWriter().fromJsonString(jsonOriginal)).isEqualTo(tlvEncoding) - assertThat(TlvReader(tlvEncoding).toJsonString()) - .isEqualTo(JsonParser.parseString(jsonExpected).asJsonObject.toString()) - if (jsonOriginal != jsonExpected) { - assertThat(TlvWriter().fromJsonString(jsonExpected)).isEqualTo(tlvEncoding) - } - } - - @Test - fun convertBoolean_false() { - // Boolean false - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(0), false) - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "0:BOOL" : false - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertBoolean_true() { - // Boolean true - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(1), true) - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "1:BOOL" : true - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertSignedInt_1BytePositive() { - // Signed Integer 42, 1-octet - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(2), 42) - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "2:INT" : 42 - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertSignedInt_1ByteNegative() { - // Signed Integer -17, 1-octet - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(3), -17) - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "3:INT" : -17 - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertUnsignedInt_1Byte() { - // Unsigned Integer 42, 1-octet - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(4), 42U) - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "value:4:UINT" : 42 - } - """ - val expectedJson = """ - { - "4:UINT" : 42 - } - """ - - checkValidConversion(json, encoding, expectedJson) - } - - @Test - fun convertSignedInt_1Byte2octet() { - // Signed Integer 42, 1-byte encoded as 2-octet - val encoding = "15 21 06 2a 00 18".octetsToByteArray() - val expectedJson = """ - { - "6:INT" : 42 - } - """ - - // Note: the current implementation follows the minimum encoding policy, which encodes this - // value as 1-octet. Testing only decoding. - assertThat(TlvReader(encoding).toJsonString()) - .isEqualTo(JsonParser.parseString(expectedJson).asJsonObject.toString()) - } - - @Test - fun convertSignedInt_2Bytes() { - // Signed Integer 4242, 2-octet - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(7), 4242) - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "7:INT" : 4242 - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertSignedInt_4Bytes() { - // Signed Integer -170000, 4-octet - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(80), -170000) - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "80:INT" : -170000 - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertSignedInt_8Bytes() { - // Signed Integer (Long) 40000000000, 8-octet - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(202), 40000000000) - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "202:INT" : "40000000000" - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertUnsignedInt_8Bytes() { - // Unsigned Integer (Long) 40000000000, 8-octet - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(222), 40000000000U) - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "222:UINT" : "40000000000" - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertUtf8String_hello() { - // UTF-8 String, 1-octet length, "Hello!" - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(0), "Hello!") - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "0:STRING" : "Hello!" - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertUtf8String_tschuh() { - // UTF-8 String, 1-octet length, "Tschüs" - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(250), "Tschüs") - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "250:STRING" : "Tschüs" - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertOctetString() { - // Octet String, 1-octet length, octets 00 01 02 03 04 - val value = ByteString.fromHex("0001020304") - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(1), value) - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "1:BYTES" : "AAECAwQ=" - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertNull() { - // Null - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .putNull(ContextSpecificTag(1)) - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "1:NULL" : null - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertFloat_0() { - // Single precision floating point 0.0 - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(1), 0.0f) - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "1:FLOAT" : 0.0 - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertFloat_1third() { - // Single precision floating point (1.0 / 3.0) - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(100), 1.0f / 3.0f) - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "100:FLOAT" : 0.33333334 - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertFloat_17_9() { - // Single precision floating point 17.9 - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(101), 17.9f) - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "101:FLOAT" : 17.9 - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertFloat_positiveInfinity_throwsIllegalArgumentException() { - // Single precision floating point infinity (∞) - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(1), Float.POSITIVE_INFINITY) - .endStructure() - .validateTlv() - .getEncoded() - - // Throws exception because the encoded value is unsupported Infinity value - assertFailsWith { TlvReader(encoding).toJsonString() } - } - - @Test - fun convertFloat_negativeInfinity_throwsIllegalArgumentException() { - // Single precision floating point negative infinity (-∞) - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(1), Float.NEGATIVE_INFINITY) - .endStructure() - .validateTlv() - .getEncoded() - - // Throws exception because the encoded value is unsupported Infinity value - assertFailsWith { TlvReader(encoding).toJsonString() } - } - - @Test - fun convertDouble_0() { - // Double precision floating point 0.0 - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(1), 0.0) - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "1:DOUBLE" : 0.0 - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertDouble_1third() { - // Double precision floating point (1.0 / 3.0) - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(1), 1.0 / 3.0) - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "1:DOUBLE" : 0.3333333333333333 - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertDouble_17_9() { - // Double precision floating point 17.9 - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(1), 17.9) - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "1:DOUBLE" : 17.9 - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertDouble_positiveInfinity_throwsIllegalArgumentException() { - // Double precision floating point infinity (∞) - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(1), Double.POSITIVE_INFINITY) - .endStructure() - .validateTlv() - .getEncoded() - - // Throws exception because the encoded value is unsupported Infinity value - assertFailsWith { TlvReader(encoding).toJsonString() } - } - - @Test - fun convertDouble_negativeInfinity_throwsIllegalArgumentException() { - // Double precision floating point negative infinity (-∞) - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(1), Double.NEGATIVE_INFINITY) - .endStructure() - .validateTlv() - .getEncoded() - - // Throws exception because the encoded value is unsupported Infinity value - assertFailsWith { TlvReader(encoding).toJsonString() } - } - - @Test - fun convertEmptyStructure() { - // Empty Structure, {} - val encoding = - TlvWriter().startStructure(AnonymousTag).endStructure().validateTlv().getEncoded() - val json = """ - { - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertEmptyStructureWithinStructure() { - // Empty Structure, {} - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .startStructure(ContextSpecificTag(1)) - .endStructure() - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "1:STRUCT" : {} - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertEmptyStructureWithCommonProfileTag_throwsIllegalArgumentException() { - // Empty Structure, {} - val encoding = - TlvWriter() - .startStructure(CommonProfileTag(2, 1000u)) - .endStructure() - .validateTlv() - .getEncoded() - - // Throws exception because top level element must be anonymous Structure - assertFailsWith { TlvReader(encoding).toJsonString() } - } - - @Test - fun convertTopLevelArray_throwsIllegalArgumentException() { - // Empty Array, [] - val tag = AnonymousTag - val encoding = TlvWriter().startArray(tag).endArray().validateTlv().getEncoded() - - // Throws exception because top level element must be anonymous Structure - assertFailsWith { TlvReader(encoding).toJsonString() } - } - - @Test - fun convertTopLevelInt_throwsIllegalArgumentException() { - // Empty Array, [] - val value = 42 - val tag = CommonProfileTag(2, 1000u) - val encoding = TlvWriter().put(tag, value).validateTlv().getEncoded() - - // Throws exception because top level element must be anonymous Structure - assertFailsWith { TlvReader(encoding).toJsonString() } - } - - @Test - fun convertArray_empty() { - // Empty Array, [] - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .startArray(ContextSpecificTag(1)) - .endArray() - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "1:ARRAY-?" : [] - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertArrayWithCommonProfileTag2_empty() { - // Empty Array, [] - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .startArray(CommonProfileTag(2, 10000u)) - .endArray() - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "value:10000:ARRAY-?" : [] - } - """ - val expectedJson = """ - { - "10000:ARRAY-?" : [] - } - """ - - checkValidConversion(json, encoding, expectedJson) - } - - @Test - fun convertArrayWithCommonProfileTag4_empty() { - // Empty Array, [] - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .startArray(CommonProfileTag(4, 1000000u)) - .endArray() - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "1000000:ARRAY-?" : [] - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertList_empty_throwsIllegalArgumentException() { - // Empty List, [] - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .startList(ContextSpecificTag(1)) - .endList() - .endStructure() - .validateTlv() - .getEncoded() - - // Throws exception because TLV Lists are not supported - assertFailsWith { TlvReader(encoding).toJsonString() } - } - - @Test - fun convertIntegersWithContextTags() { - // Structure, two context specific tags, Signed Integer, 1 octet values, {0 = 42, 1 = -17} - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(0), 42) - .put(ContextSpecificTag(1), -17) - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "0:INT" : 42, - "1:INT" : -17 - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertStructure_intsWithContextTags() { - // Structure, two context specific tags, Signed Integer, 1 octet values, {0 = 42, 1 = -17} - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .startStructure(ContextSpecificTag(0)) - .put(ContextSpecificTag(0), 42) - .put(ContextSpecificTag(1), -17) - .endStructure() - .endStructure() - .validateTlv() - .getEncoded() - val json = - """ - { - "0:STRUCT" : { - "0:INT" : 42, - "1:INT" : -17 - } - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertArray_ints() { - // Array of Signed Integers (1-octet values): [0, 1, 2, 3, 4] - val values = longArrayOf(0, 1, 2, 3, 4) - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .putSignedLongArray(ContextSpecificTag(0), values) - .endStructure() - .validateTlv() - .getEncoded() - val json = - """ - { - "0:ARRAY-INT" : [ - 0, - 1, - 2, - 3, - 4 - ] - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertArray_double() { - // Array of Doubles: [1.1, 134.2763, -12345.87] - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .startArray(ContextSpecificTag(0)) - .put(AnonymousTag, 1.1) - .put(AnonymousTag, 134.2763) - .put(AnonymousTag, -12345.87) - .endArray() - .endStructure() - .validateTlv() - .getEncoded() - val json = - """ - { - "0:ARRAY-DOUBLE" : [ - 1.1, - 134.2763, - -12345.87 - ] - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertArray_float() { - // Array of Floats: [1.1, 134.2763, -12345.87] - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .startArray(CommonProfileTag(2, 1000u)) - .put(AnonymousTag, 1.1f) - .put(AnonymousTag, 134.2763f) - .put(AnonymousTag, -12345.87f) - .endArray() - .endStructure() - .validateTlv() - .getEncoded() - val json = - """ - { - "1000:ARRAY-FLOAT" : [ - 1.1, - 134.2763, - -12345.87 - ] - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertArray_string() { - // Array of Strings: ["ABC", "Options", "more"] - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .startArray(CommonProfileTag(4, 100000u)) - .put(AnonymousTag, "ABC") - .put(AnonymousTag, "Options") - .put(AnonymousTag, "more") - .endArray() - .endStructure() - .validateTlv() - .getEncoded() - val json = - """ - { - "100000:ARRAY-STRING" : [ - "ABC", - "Options", - "more" - ] - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertArray_boolean() { - // Array of Booleans: [true, false, false] - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .startArray(ContextSpecificTag(255)) - .put(AnonymousTag, true) - .put(AnonymousTag, false) - .put(AnonymousTag, false) - .endArray() - .endStructure() - .validateTlv() - .getEncoded() - val json = - """ - { - "255:ARRAY-BOOL" : [ - true, - false, - false - ] - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertArray_null() { - // Array of Nulls: [null, null] - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .startArray(ContextSpecificTag(1)) - .putNull(AnonymousTag) - .putNull(AnonymousTag) - .endArray() - .endStructure() - .validateTlv() - .getEncoded() - val json = - """ - { - "1:ARRAY-NULL" : [ - null, - null - ] - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertArray_boolean_throwsIllegalArgumentException() { - // Array of bools: error type doesn't match - val json = - """ - { - "value:1:ARRAY-BOOL" : [ - "yes", - "no" - ] - } - """ - - // Throws exception because subtype encoded in the Json key (Boolean) doesn't match the String - // type of the elements in the array - assertFailsWith { TlvWriter().fromJsonString(json) } - } - - @Test - fun convertArray_uint_throwsIllegalArgumentException() { - // Array of unsigned integers: error type doesn't match - val json = - """ - { - "value:1:ARRAY-UINT" : [ - "yes", - "no" - ] - } - """ - - // Throws exception because subtype encoded in the Json key (Boolean) doesn't match the String - // type of the elements in the array - assertFailsWith { TlvWriter().fromJsonString(json) } - } - - @Test - fun convertArray_float_throwsIllegalArgumentException() { - // Array of floats: error type doesn't match - val json = - """ - { - "1:ARRAY-FLOAT" : [ - { - "1" : 22, - "2" : 23 - } - ] - } - """ - - // Throws exception because subtype encoded in the Json key (Float) doesn't match the Structure - // type of the elements in the array - assertFailsWith { TlvWriter().fromJsonString(json) } - } - - @Test - fun convertArray_uint2_throwsIllegalArgumentException() { - // Array of unsigned integer: error type doesn't match - val json = """ - { - "2:ARRAY-UINT" : [ - null - ] - } - """ - - // Throws exception because subtype encoded in the Json key (UInt) doesn't match the Null - // type of the elements in the array - assertFailsWith { TlvWriter().fromJsonString(json) } - } - - @Test - fun convertByteStringArray_throwsIllegalArgumentException() { - // Anonymous Array of ByteString, [{00 01 02 03 04}, {FF}, {4A EF 88}] - val json = - """ - { - "value:ARRAY-BYTES": [ - "AA45ECAwQ=" - ] - } - """ - - // Throws exception because string is invalid base64 encoded value - assertFailsWith { TlvWriter().fromJsonString(json) } - } - - @Test - fun convertArray_mixedValues_throwsIllegalArgumentException() { - // Array of mixed elements: [42, -170000, {}, 17.9, "Hello!"] - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .startArray(ContextSpecificTag(0)) - .put(AnonymousTag, 42) - .put(AnonymousTag, -170000) - .startStructure(AnonymousTag) - .endStructure() - .put(AnonymousTag, 17.9) - .put(AnonymousTag, "Hello!") - .endArray() - .endStructure() - .validateTlv() - .getEncoded() - - // Throws exception because TLV Array Must have same type elements - assertFailsWith { TlvReader(encoding).toJsonString() } - } - - @Test - fun convertAnonymousTag_throwsIllegalArgumentException() { - // Anonymous tag, Unsigned Integer, 1-octet value, 42U - val json = """ - { - "value:UINT" : 42 - } - """ - - // Throws exception because element within structure cannot have anonymous tag - assertFailsWith { TlvWriter().fromJsonString(json) } - } - - @Test - fun convertKeyWithoutTag_throwsIllegalArgumentException2() { - // Anonymous tag, Unsigned Integer, 1-octet value, 42U - val json = """ - { - "UINT" : 42 - } - """ - - // Throws exception because Json key must have valid tag field - assertFailsWith { TlvWriter().fromJsonString(json) } - } - - @Test - fun convertContextTag_withinStructure() { - // Context tag 255 (max), Unsigned Integer, 1-octet value: {255 = 42U} - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .startStructure(ContextSpecificTag(0)) - .put(ContextSpecificTag(255), 42U) - .endStructure() - .endStructure() - .validateTlv() - .getEncoded() - val json = - """ - { - "value:0:STRUCT": { - "name:255:UINT" : 42 - } - } - """ - val expectedJson = - """ - { - "0:STRUCT": { - "255:UINT" : 42 - } - } - """ - - checkValidConversion(json, encoding, expectedJson) - } - - @Test - fun convertStructWithMixedTags() { - // Context and Common Profile tags, Unsigned Integer structure: {255 = 42, 256 = 17000, 65535 = - // 1, 65536 = 345678, 4294967295 = 500000000000} - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .startStructure(ContextSpecificTag(0)) - .put(ContextSpecificTag(UByte.MAX_VALUE.toInt()), 42U) - .put(CommonProfileTag(2, UByte.MAX_VALUE + 1U), 17000U) - .put(CommonProfileTag(2, UShort.MAX_VALUE.toUInt()), 1U) - .put(CommonProfileTag(4, UShort.MAX_VALUE + 1U), 345678U) - .put(CommonProfileTag(4, UInt.MAX_VALUE), 500000000000U) - .endStructure() - .endStructure() - .validateTlv() - .getEncoded() - val json = - """ - { - "0:STRUCT": { - "255:UINT" : 42, - "256:UINT" : 17000, - "65535:UINT" : 1, - "65536:UINT" : 345678, - "4294967295:UINT" : "500000000000" - } - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertContextTag_invalidContextTag_throwsIllegalArgumentException() { - // Context and Common Profile tags, Unsigned Integer structure: {255 = 42, 256 = 17000, 65535 = - // 1, 65536 = 345678, 4294967295 = 500000000000, , 4294967296 = 34} - val json = - """ - { - "0:STRUCT": { - "255:UINT" : 42, - "256:UINT" : 17000, - "65535:UINT" : 1, - "65536:UINT" : 345678, - "4294967295:UINT" : "500000000000", - "invalid:4294967296:UINT" : 34 - } - } - """ - - // 4294967296 exceeds valid context specific or common profile tag value of 32-bits - assertFailsWith { TlvWriter().fromJsonString(json) } - } - - @Test - fun convertCommonProfileTag2() { - // Common profile tag 1, Unsigned Integer, 1-octet value, Matter::1 = 42U - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(CommonProfileTag(2, 1000u), 42U) - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "1000:UINT" : 42 - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun encodeCommonProfileTag4() { - // Common profile tag 100000, Unsigned Integer, 1-octet value, Matter::100000 = 42U - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(CommonProfileTag(4, 100000u), 42U) - .endStructure() - .validateTlv() - .getEncoded() - val json = """ - { - "100000:UINT" : 42 - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertFullyQualifiedTag8_throwsIllegalArgumentException() { - // Fully qualified tag, Vendor ID 0xFFF1/65521, profile number 0xDEED/57069, 4-octet tag - // 0xAA55FEED/2857762541, Unsigned Integer, 1-octet value 42, 65521::57069:2857762541 = 42U - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(FullyQualifiedTag(8, 0xFFF1u, 0xDEEDu, 0xAA55FEEDu), 42U) - .endStructure() - .validateTlv() - .getEncoded() - - // Fully qualified tags are not supported - assertFailsWith { TlvReader(encoding).toJsonString() } - } - - @Test - fun convertFullyQualifiedTags_throwsIllegalArgumentException() { - // Structure with the fully qualified tag, Vendor ID 0xFFF1/65521, profile number 0xDEED/57069, - // 2-octet tag 1. The structure contains a single element labeled using a fully qualified tag - // under the same profile, with 2-octet tag 0xAA55/43605.65521::57069:1 = {65521::57069:43605 = - // 42U} - val value = 42U - val structTag = FullyQualifiedTag(6, 0xFFF1u, 0xDEEDu, 1u) - val valueTag = FullyQualifiedTag(6, 0xFFF1u, 57069u, 43605u) - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .startStructure(structTag) - .put(valueTag, value) - .endStructure() - .endStructure() - .validateTlv() - .getEncoded() - - // Fully qualified tags are not supported - assertFailsWith { TlvReader(encoding).toJsonString() } - } - - @Test - fun convertSignedLongArray() { - // Anonymous Array of Signed Integers: [42, -17, -170000, 40000000000] - val values = longArrayOf(42, -17, -170000, 40000000000) - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .putSignedLongArray(ContextSpecificTag(0), values) - .endStructure() - .validateTlv() - .getEncoded() - val json = - """ - { - "0:ARRAY-INT": [ - 42, - -17, - -170000, - "40000000000" - ] - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertUnsignedLongArray() { - // Anonymous Array of Unigned Integers: [42, 170000, 40000000000] - val values = longArrayOf(42, 170000, 40000000000) - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .putUnsignedLongArray(ContextSpecificTag(0), values) - .endStructure() - .validateTlv() - .getEncoded() - val json = - """ - { - "0:ARRAY-UINT": [ - 42, - 170000, - "40000000000" - ] - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertByteStringArray() { - // Anonymous Array of ByteString, [{00 01 02 03 04}, {FF}, {4A EF 88}] - val values = - listOf( - ByteString.fromHex("0001020304"), - ByteString.fromHex("FF"), - ByteString.fromHex("4AEF88") - ) - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .putByteStringArray(ContextSpecificTag(0), values) - .endStructure() - .validateTlv() - .getEncoded() - val json = - """ - { - "0:ARRAY-BYTES": [ - "AAECAwQ=", - "/w==", - "Su+I" - ] - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertStructure_Mixed() { - // Structure with mixed elements - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .startStructure(ContextSpecificTag(0)) - .put(ContextSpecificTag(0), 20.toLong()) - .put(ContextSpecificTag(1), true) - .put(ContextSpecificTag(2), 0.toULong()) - .put(ContextSpecificTag(3), "Test ByteString Value".toByteString()) - .put(ContextSpecificTag(4), "hello") - .put(ContextSpecificTag(5), -500000) - .put(ContextSpecificTag(6), 17.9) - .put(ContextSpecificTag(7), 17.9f) - .endStructure() - .endStructure() - .validateTlv() - .getEncoded() - val json = - """ - { - "0:STRUCT": { - "0:INT": 20, - "1:BOOL": true, - "2:UINT": 0, - "3:BYTES": "VGVzdCBCeXRlU3RyaW5nIFZhbHVl", - "4:STRING": "hello", - "5:INT": -500000, - "6:DOUBLE": 17.9, - "7:FLOAT": 17.9 - } - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertArrayofStructureWithMixedElements() { - // Array of structures with mixed elements - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .startArray(CommonProfileTag(2, 1000U)) - .startStructure(AnonymousTag) - .put(ContextSpecificTag(0), 20) - .put(ContextSpecificTag(1), true) - .put(ContextSpecificTag(2), 0.toULong()) - .put(ContextSpecificTag(3), "Test ByteString Value 1".toByteString()) - .put(ContextSpecificTag(4), "hello1") - .put(ContextSpecificTag(5), -500000) - .put(ContextSpecificTag(6), 17.9) - .put(ContextSpecificTag(7), 17.9f) - .endStructure() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(0), -10) - .put(ContextSpecificTag(1), false) - .put(ContextSpecificTag(2), 128.toULong()) - .put(ContextSpecificTag(3), "Test ByteString Value 2".toByteString()) - .put(ContextSpecificTag(4), "hello2") - .put(ContextSpecificTag(5), 40000000000) - .put(ContextSpecificTag(6), -1754.923) - .put(ContextSpecificTag(7), 97.945f) - .endStructure() - .endArray() - .endStructure() - .validateTlv() - .getEncoded() - val json = - """ - { - "1000:ARRAY-STRUCT": [ - { - "0:INT": 20, - "1:BOOL": true, - "2:UINT": 0, - "3:BYTES": "VGVzdCBCeXRlU3RyaW5nIFZhbHVlIDE=", - "4:STRING": "hello1", - "5:INT": -500000, - "6:DOUBLE": 17.9, - "7:FLOAT": 17.9 - }, - { - "0:INT": -10, - "1:BOOL": false, - "2:UINT": 128, - "3:BYTES": "VGVzdCBCeXRlU3RyaW5nIFZhbHVlIDI=", - "4:STRING": "hello2", - "5:INT": "40000000000", - "6:DOUBLE": -1754.923, - "7:FLOAT": 97.945 - } - ] - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertingStructureWithMixedElementsAndNames() { - // Array of structures with mixed elements - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .startStructure(CommonProfileTag(4, 444444U)) - .startStructure(ContextSpecificTag(0)) - .put(ContextSpecificTag(0), "Test String Element #0") - .put(ContextSpecificTag(1), 1) - .put(ContextSpecificTag(2), true) - .endStructure() - .put(ContextSpecificTag(1), 17.4f) - .startStructure(ContextSpecificTag(2)) - .put(ContextSpecificTag(0), "Test String Element #2") - .put(ContextSpecificTag(3), "Test ByteString Element #3".toByteString()) - .endStructure() - .endStructure() - .endStructure() - .validateTlv() - .getEncoded() - val json = - """ - { - "value_name:444444:STRUCT": { - "0:STRUCT": { - "name0:0:STRING": "Test String Element #0", - "name1:1:INT": 1, - "name2:2:BOOL": true - }, - "name2:1:FLOAT": 17.4, - "2:STRUCT": { - "name0:0:STRING": "Test String Element #2", - "3:BYTES": "VGVzdCBCeXRlU3RyaW5nIEVsZW1lbnQgIzM=" - } - } - } - """ - val expectedJson = - """ - { - "444444:STRUCT": { - "0:STRUCT": { - "0:STRING": "Test String Element #0", - "1:INT": 1, - "2:BOOL": true - }, - "1:FLOAT": 17.4, - "2:STRUCT": { - "0:STRING": "Test String Element #2", - "3:BYTES": "VGVzdCBCeXRlU3RyaW5nIEVsZW1lbnQgIzM=" - } - } - } - """ - - checkValidConversion(json, encoding, expectedJson) - } - - @Test - fun convertArrayOfStrings() { - // Array of String elements - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .startArray(ContextSpecificTag(0)) - .put(AnonymousTag, "Test array member 0") - .put(AnonymousTag, "Test array member 1") - .put(AnonymousTag, "Test array member 2") - .put(AnonymousTag, "Test array member 3") - .endArray() - .endStructure() - .validateTlv() - .getEncoded() - val json = - """ - { - "0:ARRAY-STRING": [ - "Test array member 0", - "Test array member 1", - "Test array member 2", - "Test array member 3" - ] - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertArrayOfByteStrings() { - // Array of ByteString elements - val values = - listOf( - "Test array member 0".toByteString(), - "Test array member 1".toByteString(), - "Test array member 2".toByteString(), - "Test array member 3".toByteString(), - ) - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .putByteStringArray(ContextSpecificTag(0), values) - .endStructure() - .validateTlv() - .getEncoded() - val json = - """ - { - "0:ARRAY-BYTES": [ - "VGVzdCBhcnJheSBtZW1iZXIgMA==", - "VGVzdCBhcnJheSBtZW1iZXIgMQ==", - "VGVzdCBhcnJheSBtZW1iZXIgMg==", - "VGVzdCBhcnJheSBtZW1iZXIgMw==" - ] - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertTopLevelMixedValues() { - // Top level elements with mixed values - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(0), 42) - .put(ContextSpecificTag(1), "Test array member 0".toByteString()) - .put(ContextSpecificTag(2), 156.398) - .put(ContextSpecificTag(3), 73709551615U) - .put(ContextSpecificTag(4), true) - .putNull(ContextSpecificTag(5)) - .startStructure(ContextSpecificTag(6)) - .put(ContextSpecificTag(1), "John") - .put(ContextSpecificTag(2), 34U) - .put(ContextSpecificTag(3), true) - .startArray(ContextSpecificTag(4)) - .put(AnonymousTag, 5) - .put(AnonymousTag, 9) - .put(AnonymousTag, 10) - .endArray() - .startArray(ContextSpecificTag(5)) - .put(AnonymousTag, "Ammy") - .put(AnonymousTag, "David") - .put(AnonymousTag, "Larry") - .endArray() - .startArray(ContextSpecificTag(6)) - .put(AnonymousTag, true) - .put(AnonymousTag, false) - .put(AnonymousTag, true) - .endArray() - .endStructure() - .put(ContextSpecificTag(7), 0.0f) - .endStructure() - .validateTlv() - .getEncoded() - val json = - """ - { - "value:0:INT": 42, - "value:1:BYTES": "VGVzdCBhcnJheSBtZW1iZXIgMA==", - "value:2:DOUBLE": 156.398, - "value:3:UINT": "73709551615", - "value:4:BOOL": true, - "value:5:NULL": null, - "value:6:STRUCT": { - "name:1:STRING": "John", - "age:2:UINT": 34, - "approved:3:BOOL": true, - "kids:4:ARRAY-INT": [ - 5, - 9, - 10 - ], - "names:5:ARRAY-STRING": [ - "Ammy", - "David", - "Larry" - ], - "6:ARRAY-BOOL": [ - true, - false, - true - ] - }, - "value:7:FLOAT": 0.0 - } - """ - val expectedJson = - """ - { - "0:INT": 42, - "1:BYTES": "VGVzdCBhcnJheSBtZW1iZXIgMA==", - "2:DOUBLE": 156.398, - "3:UINT": "73709551615", - "4:BOOL": true, - "5:NULL": null, - "6:STRUCT": { - "1:STRING": "John", - "2:UINT": 34, - "3:BOOL": true, - "4:ARRAY-INT": [ - 5, - 9, - 10 - ], - "5:ARRAY-STRING": [ - "Ammy", - "David", - "Larry" - ], - "6:ARRAY-BOOL": [ - true, - false, - true - ] - }, - "7:FLOAT": 0.0 - } - """ - - checkValidConversion(json, encoding, expectedJson) - } - - @Test - fun convertArray_UIntMinMax() { - // Array of Unsigned Integers, where each element represents MAX possible value for unsigned - // integere - // types UByte, UShort, UInt, and ULong: [0xFF, 0xFFFF, 0xFFFFFFFF, 0xFFFFFFFF_FFFFFFFF] - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .startArray(ContextSpecificTag(0)) - .put(AnonymousTag, UByte.MAX_VALUE) - .put(AnonymousTag, UShort.MAX_VALUE) - .put(AnonymousTag, UInt.MAX_VALUE) - .put(AnonymousTag, ULong.MAX_VALUE) - .endArray() - .endStructure() - .validateTlv() - .getEncoded() - val json = - """ - { - "0:ARRAY-UINT": [ - 255, - 65535, - 4294967295, - "18446744073709551615" - ] - } - """ - - checkValidConversion(json, encoding) - } - - @Test - fun convertArray_IntMinMax() { - // Array of Integers, where each element represents MIN or MAX possible value for integere - // types Byte, Short, Int, and Long - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .startArray(ContextSpecificTag(0)) - .put(AnonymousTag, Byte.MIN_VALUE) - .put(AnonymousTag, Byte.MAX_VALUE) - .put(AnonymousTag, Short.MIN_VALUE) - .put(AnonymousTag, Short.MAX_VALUE) - .put(AnonymousTag, Int.MIN_VALUE) - .put(AnonymousTag, Int.MAX_VALUE) - .put(AnonymousTag, Long.MIN_VALUE) - .put(AnonymousTag, Long.MAX_VALUE) - .endArray() - .endStructure() - .validateTlv() - .getEncoded() - val json = - """ - { - "0:ARRAY-INT": [ - -128, - 127, - -32768, - 32767, - -2147483648, - 2147483647, - "-9223372036854775808", - "9223372036854775807" - ] - } - """ - - checkValidConversion(json, encoding) - } -} diff --git a/third_party/java_deps/BUILD.gn b/third_party/java_deps/BUILD.gn index 58260d6d84ceb5..a5e7c0629d94be 100644 --- a/third_party/java_deps/BUILD.gn +++ b/third_party/java_deps/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2022-2023 Project CHIP Authors +# Copyright (c) 2022 Project CHIP Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -44,7 +44,3 @@ java_prebuilt("truth") { java_prebuilt("junit-4") { jar_path = "artifacts/junit-4.13.2.jar" } - -java_prebuilt("gson") { - jar_path = "artifacts/gson-2.9.1.jar" -} diff --git a/third_party/java_deps/set_up_java_deps.sh b/third_party/java_deps/set_up_java_deps.sh index d49ec170129494..911a53a638708d 100755 --- a/third_party/java_deps/set_up_java_deps.sh +++ b/third_party/java_deps/set_up_java_deps.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # -# Copyright (c) 2022-2023 Project CHIP Authors +# Copyright (c) 2022 Project CHIP Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -24,4 +24,3 @@ curl --fail --location --silent --show-error https://repo1.maven.org/maven2/org/ curl --fail --location --silent --show-error https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java/3.22.0/protobuf-java-3.22.0.jar -o third_party/java_deps/artifacts/protobuf-java-3.22.0.jar curl --fail --location --silent --show-error https://repo1.maven.org/maven2/com/google/truth/truth/1.1.3/truth-1.1.3.jar -o third_party/java_deps/artifacts/truth-1.1.3.jar curl --fail --location --silent --show-error https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar -o third_party/java_deps/artifacts/junit-4.13.2.jar -curl --fail --location --silent --show-error https://repo1.maven.org/maven2/com/google/code/gson/gson/2.9.1/gson-2.9.1.jar -o third_party/java_deps/artifacts/gson-2.9.1.jar