diff options
Diffstat (limited to 'libccnx-common/ccnx/common/codec/schema_v1/test')
22 files changed, 7621 insertions, 0 deletions
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/.gitignore b/libccnx-common/ccnx/common/codec/schema_v1/test/.gitignore new file mode 100644 index 00000000..ffeaadf8 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/.gitignore @@ -0,0 +1,19 @@ +*.gcno +*.log +*.trs +*.o +test_ccnxCodecSchemaV1_CryptoSuite +test_ccnxCodecSchemaV1_FixedHeaderDecoder +test_ccnxCodecSchemaV1_FixedHeaderEncoder +test_ccnxCodecSchemaV1_LinkCodec +test_ccnxCodecSchemaV1_MessageDecoder +test_ccnxCodecSchemaV1_MessageEncoder +test_ccnxCodecSchemaV1_NameCodec +test_ccnxCodecSchemaV1_NameSegmentCodec +test_ccnxCodecSchemaV1_OptionalHeadersDecoder +test_ccnxCodecSchemaV1_OptionalHeadersEncoder +test_ccnxCodecSchemaV1_PacketDecoder +test_ccnxCodecSchemaV1_PacketEncoder +test_ccnxCodecSchemaV1_TlvDictionary +test_ccnxCodecSchemaV1_ValidationDecoder +test_ccnxCodecSchemaV1_ValidationEncoder diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/CMakeLists.txt b/libccnx-common/ccnx/common/codec/schema_v1/test/CMakeLists.txt new file mode 100644 index 00000000..c827a36e --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/CMakeLists.txt @@ -0,0 +1,29 @@ +# Enable gcov output for the tests +add_definitions(--coverage) +set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage") + +set(TestsExpectedToPass + test_ccnxCodecSchemaV1_CryptoSuite + test_ccnxCodecSchemaV1_FixedHeaderDecoder + test_ccnxCodecSchemaV1_FixedHeaderEncoder + test_ccnxCodecSchemaV1_HashCodec + test_ccnxCodecSchemaV1_LinkCodec + test_ccnxCodecSchemaV1_ManifestDecoder + test_ccnxCodecSchemaV1_ManifestEncoder + test_ccnxCodecSchemaV1_MessageDecoder + test_ccnxCodecSchemaV1_MessageEncoder + test_ccnxCodecSchemaV1_NameCodec + test_ccnxCodecSchemaV1_NameSegmentCodec + test_ccnxCodecSchemaV1_OptionalHeadersDecoder + test_ccnxCodecSchemaV1_OptionalHeadersEncoder + test_ccnxCodecSchemaV1_PacketDecoder + test_ccnxCodecSchemaV1_PacketEncoder + test_ccnxCodecSchemaV1_TlvDictionary + test_ccnxCodecSchemaV1_ValidationDecoder + test_ccnxCodecSchemaV1_ValidationEncoder +) + + +foreach(test ${TestsExpectedToPass}) + AddTest(${test}) +endforeach() diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_CryptoSuite.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_CryptoSuite.c new file mode 100644 index 00000000..10bc24d2 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_CryptoSuite.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_CryptoSuite.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include <stdio.h> + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_CryptoSuite) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_CryptoSuite) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_CryptoSuite) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_ParcToTlv); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_TlvToParc); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_SignAndHashToTlv); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_ParcToTlv) +{ + struct test_vector { + PARCCryptoSuite input; + CCNxCodecSchemaV1TlvDictionary_CryptoSuite output; + bool success; + bool sentinel; + } vectors[] = { + { .input = PARCCryptoSuite_RSA_SHA256, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256, .success = true, .sentinel = false }, + { .input = PARCCryptoSuite_HMAC_SHA256, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256, .success = true, .sentinel = false }, + { .input = PARCCryptoSuite_NULL_CRC32C, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C, .success = true, .sentinel = false }, + { .input = PARCCryptoSuite_DSA_SHA256, .output = 0, .success = false, .sentinel = false }, + { .input = PARCCryptoSuite_RSA_SHA512, .output = 0, .success = false, .sentinel = false }, + { .input = PARCCryptoSuite_HMAC_SHA512, .output = 0, .success = false, .sentinel = false }, + { .input = 13579, .output = 0, .success = false, .sentinel = false }, + { .input = 0, .output = 0, .success = false, .sentinel = true }, + }; + + for (int i = 0; !vectors[i].sentinel; i++) { + unsigned output; + bool success = ccnxCodecSchemaV1CryptoSuite_ParcToTlv(vectors[i].input, &output); + assertTrue(success == vectors[i].success, "Wrong return value, index %d expected %d got %d", i, vectors[i].success, success); + if (success) { + assertTrue(output == vectors[i].output, "Wrong output, index %d expected %u got %u", i, vectors[i].output, output); + } + } +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_TlvToParc) +{ + struct test_vector { + PARCCryptoSuite output; + CCNxCodecSchemaV1TlvDictionary_CryptoSuite input; + bool success; + bool sentinel; + } vectors[] = { + { .input = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256, .output = PARCCryptoSuite_RSA_SHA256, .success = true, .sentinel = false }, + { .input = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256, .output = PARCCryptoSuite_HMAC_SHA256, .success = true, .sentinel = false }, + { .input = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C, .output = PARCCryptoSuite_NULL_CRC32C, .success = true, .sentinel = false }, + { .input = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_EcSecp256K1, .output = 0, .success = false, .sentinel = false }, + { .input = 13579, .output = 0, .success = false, .sentinel = false }, + { .input = 0, .output = 0, .success = false, .sentinel = true }, + }; + + for (int i = 0; !vectors[i].sentinel; i++) { + unsigned output; + bool success = ccnxCodecSchemaV1CryptoSuite_TlvToParc(vectors[i].input, &output); + assertTrue(success == vectors[i].success, "Wrong return value, index %d expected %d got %d", i, vectors[i].success, success); + if (success) { + assertTrue(output == vectors[i].output, "Wrong output, index %d expected %u got %u", i, vectors[i].output, output); + } + } +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_SignAndHashToTlv) +{ + struct test_vector { + PARCSigningAlgorithm signAlg; + PARCCryptoHashType hashType; + CCNxCodecSchemaV1TlvDictionary_CryptoSuite output; + bool success; + bool sentinel; + } vectors[] = { + { .signAlg = PARCSigningAlgorithm_RSA, .hashType = PARCCryptoHashType_SHA256, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256, .success = true, .sentinel = false }, + { .signAlg = PARCSigningAlgorithm_HMAC, .hashType = PARCCryptoHashType_SHA256, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256, .success = true, .sentinel = false }, + { .signAlg = PARCSigningAlgortihm_NULL, .hashType = PARCCryptoHashType_CRC32C, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C, .success = true, .sentinel = false }, + { .signAlg = PARCSigningAlgorithm_RSA, .hashType = 12345, .output = 0, .success = false, .sentinel = false }, + { .signAlg = PARCSigningAlgorithm_HMAC, .hashType = 12345, .output = 0, .success = false, .sentinel = false }, + { .signAlg = PARCSigningAlgortihm_NULL, .hashType = 12345, .output = 0, .success = false, .sentinel = false }, + { .signAlg = 12345, .hashType = 12345, .output = 0, .success = false, .sentinel = false }, + { .signAlg = 0, .hashType = 0, .output = 0, .success = false, .sentinel = true }, + }; + + for (int i = 0; !vectors[i].sentinel; i++) { + unsigned output; + bool success = ccnxCodecSchemaV1CryptoSuite_SignAndHashToTlv(vectors[i].signAlg, vectors[i].hashType, &output); + assertTrue(success == vectors[i].success, "Wrong return value, index %d expected %d got %d", i, vectors[i].success, success); + if (success) { + assertTrue(output == vectors[i].output, "Wrong output, index %d expected %u got %u", i, vectors[i].output, output); + } + } +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_CryptoSuite); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderDecoder.c new file mode 100644 index 00000000..7a889b58 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderDecoder.c @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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. + */ + +/** + */ + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_FixedHeaderDecoder.c" +#include <parc/algol/parc_SafeMemory.h> + +#include <LongBow/unit-test.h> + +typedef struct test_data { + uint8_t *packet; + PARCBuffer *fixedHeader; + CCNxCodecTlvDecoder *decoder; + CCNxTlvDictionary *dictionary; + + // truth table + uint8_t version; + uint8_t packetType; + uint16_t packetLength; + uint8_t hopLimit; + uint8_t returnCode; + uint8_t flags; + uint8_t headerLength; +} TestData; + +static TestData * +_commonSetup(void) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + data->packet = parcMemory_Allocate(8); + assertNotNull(data->packet, "parcMemory_Allocate(%d) returned NULL", 8); + memcpy(data->packet, &((uint8_t[]) { 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x08 }), 8); + + data->fixedHeader = parcBuffer_Wrap(data->packet, 8, 0, 8); + data->version = 0; + data->packetType = 1; + data->packetLength = 0x0102; + data->hopLimit = 3; + data->returnCode = 4; + data->flags = 5; + data->headerLength = 8; + data->decoder = ccnxCodecTlvDecoder_Create(data->fixedHeader); + data->dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END); + + return data; +} + +static void +_commonTeardown(TestData *data) +{ +// TestData *data = longBowTestCase_GetClipBoardData(testCase); + + ccnxTlvDictionary_Release(&data->dictionary); + ccnxCodecTlvDecoder_Destroy(&data->decoder); + parcBuffer_Release(&data->fixedHeader); + parcMemory_Deallocate((void **) &(data->packet)); + parcMemory_Deallocate((void **) &data); +} + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_FixedHeaderDecoder) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_FixedHeaderDecoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_FixedHeaderDecoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_Decode_Underrun); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHopLimit); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetReturnCode); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetFlags); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength_Missing); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType_Missing); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength_Missing); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion_Missing); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_PacketLengthTooShort); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_HeaderLengthTooShort); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_PacketLengthLessHeaderLength); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + longBowTestCase_SetClipBoardData(testCase, _commonSetup()); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + _commonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +/** + * Successful decode is tested in all the _GetX functions. We only test + * when the buffer is too small here + */ +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_Decode_Underrun) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + // advance the buffer so its too small + ccnxCodecTlvDecoder_Advance(data->decoder, 1); + + size_t beforePosition = ccnxCodecTlvDecoder_Position(data->decoder); + bool success = ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary); + size_t afterPosition = ccnxCodecTlvDecoder_Position(data->decoder); + + assertFalse(success, "Should have failed with too small a buffer"); + assertTrue(beforePosition == afterPosition, "Wrong postion, got %zu expected %zu", afterPosition, beforePosition); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary); + int headerLength = ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength(data->dictionary); + assertTrue(headerLength == data->headerLength, "Wrong headerLength, got %d expected %d", headerLength, + data->headerLength); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary); + int packetType = ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType(data->dictionary); + assertTrue(packetType == data->packetType, "Wrong packetType, got %d expected %d", packetType, data->packetType); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary); + int packetLength = ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength(data->dictionary); + assertTrue(packetLength == data->packetLength, "Wrong payloadLength, got %d expected %d", packetLength, + data->packetLength); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary); + int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion(data->dictionary); + assertTrue(version == data->version, "Wrong version, got %d expected %d", version, data->version); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHopLimit) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary); + int hopLimit = ccnxCodecSchemaV1FixedHeaderDecoder_GetHopLimit(data->dictionary); + assertTrue(hopLimit == data->hopLimit, "Wrong hopLimit, got %d expected %d", hopLimit, data->hopLimit); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetReturnCode) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary); + int returnCode = ccnxCodecSchemaV1FixedHeaderDecoder_GetReturnCode(data->dictionary); + assertTrue(returnCode == data->returnCode, "Wrong returnCode, got %d expected %d", returnCode, data->returnCode); + + // Check that the InterestReturnCode was set in the fast array, too. + uint8_t test = + ccnxTlvDictionary_GetInteger(data->dictionary, + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestReturnCode); + assertTrue(test == data->returnCode, "Expected the dictionary to have the return code set"); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetFlags) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary); + int flags = ccnxCodecSchemaV1FixedHeaderDecoder_GetFlags(data->dictionary); + assertTrue(flags == data->flags, "Wrong flags, got %d expected %d", flags, data->flags); +} + + +// ============================== +// Tests for missing values + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + // don't decode the buffer, so we're operating with an empty dictionary + int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength(data->dictionary); + assertTrue(version == -1, "Wrong HeaderLength, got %d expected %d", version, -1); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + // don't decode the buffer, so we're operating with an empty dictionary + int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType(data->dictionary); + assertTrue(version == -1, "Wrong PacketType, got %d expected %d", version, -1); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + // don't decode the buffer, so we're operating with an empty dictionary + int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength(data->dictionary); + assertTrue(version == -1, "Wrong payloadLength, got %d expected %d", version, -1); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + // don't decode the buffer, so we're operating with an empty dictionary + int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion(data->dictionary); + assertTrue(version == -1, "Wrong version, got %d expected %d", version, -1); +} + + +/** + * Packet length must be at least 8 bytes + */ +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_PacketLengthTooShort) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxCodecSchemaV1InterestHeader header = { + .version = 1, + .packetType = CCNxCodecSchemaV1Types_PacketType_Interest, + .packetLength = htons(3), + .hopLimit = 4, + .returnCode = 7, + .flags = 8, + .headerLength = 9, + }; + + PARCBuffer *fixedHeader = parcBuffer_Wrap(&header, 8, 0, 8); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(fixedHeader); + + bool success = ccnxCodecSchemaV1FixedHeaderDecoder_Decode(decoder, data->dictionary); + assertFalse(success, "Did not fail on packet length too short"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&fixedHeader); +} + +/** + * Header length must be at least 8 bytes + */ +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_HeaderLengthTooShort) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxCodecSchemaV1InterestHeader header = { + .version = 1, + .packetType = CCNxCodecSchemaV1Types_PacketType_Interest, + .packetLength = htons(12), + .hopLimit = 4, + .returnCode = 7, + .flags = 8, + .headerLength = 6, + }; + + PARCBuffer *fixedHeader = parcBuffer_Wrap(&header, 8, 0, 8); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(fixedHeader); + + bool success = ccnxCodecSchemaV1FixedHeaderDecoder_Decode(decoder, data->dictionary); + assertFalse(success, "Did not fail on header length too short"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&fixedHeader); +} + +/** + * Packet length must be no less than Header Length + */ +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_PacketLengthLessHeaderLength) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxCodecSchemaV1InterestHeader header = { + .version = 1, + .packetType = CCNxCodecSchemaV1Types_PacketType_Interest, + .packetLength = htons(12), + .hopLimit = 4, + .returnCode = 7, + .flags = 8, + .headerLength = 18, + }; + + PARCBuffer *fixedHeader = parcBuffer_Wrap(&header, 8, 0, 8); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(fixedHeader); + + bool success = ccnxCodecSchemaV1FixedHeaderDecoder_Decode(decoder, data->dictionary); + assertFalse(success, "Did not fail on packet length less than header length"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&fixedHeader); +} + +// ====================== + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_FixedHeaderDecoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderEncoder.c new file mode 100755 index 00000000..4f479090 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderEncoder.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_FixedHeaderEncoder.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include <ccnx/common/codec/test/testrig_Compare.c> + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV0_FixedHeaderEncoder) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV0_FixedHeaderEncoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV0_FixedHeaderEncoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeInterest); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeContentObject); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeInterestReturn); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeInterest) +{ + uint16_t packetLength = 0x0102; + + CCNxCodecSchemaV1InterestHeader header = { + .version = 1, + .packetType = CCNxCodecSchemaV1Types_PacketType_Interest, + .packetLength = packetLength, + .hopLimit = 4, + .returnCode = 7, // will be set to 0 + .flags = 8, + .headerLength = 9, + }; + + CCNxCodecSchemaV1InterestHeader truth = { + .version = 1, + .packetType = CCNxCodecSchemaV1Types_PacketType_Interest, + .packetLength = htons(packetLength), + .hopLimit = 4, + .returnCode = 0, + .flags = 8, + .headerLength = 9, + }; + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + ssize_t length = ccnxCodecSchemaV1FixedHeaderEncoder_EncodeHeader(encoder, (CCNxCodecSchemaV1FixedHeader *) &header); + assertTrue(length == 8, "Wrong length, got %zd expected %d", length, 8); + + testCompareEncoderToLinearMemory(encoder, length, (uint8_t *) &truth); + + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeContentObject) +{ + uint16_t packetLength = 0x0102; + + CCNxCodecSchemaV1InterestHeader header = { + .version = 1, + .packetType = CCNxCodecSchemaV1Types_PacketType_ContentObject, + .packetLength = packetLength, + .hopLimit = 4, // will be set to 0 + .returnCode = 7, // will be set to 0 + .flags = 8, // will be set to 0 + .headerLength = 9, + }; + + CCNxCodecSchemaV1InterestHeader truth = { + .version = 1, + .packetType = CCNxCodecSchemaV1Types_PacketType_ContentObject, + .packetLength = htons(packetLength), + .hopLimit = 0, + .returnCode = 0, + .flags = 0, + .headerLength = 9, + }; + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + ssize_t length = ccnxCodecSchemaV1FixedHeaderEncoder_EncodeHeader(encoder, (CCNxCodecSchemaV1FixedHeader *) &header); + assertTrue(length == 8, "Wrong length, got %zd expected %d", length, 8); + + testCompareEncoderToLinearMemory(encoder, length, (uint8_t *) &truth); + + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeInterestReturn) +{ + uint16_t packetLength = 0x0102; + + CCNxCodecSchemaV1InterestHeader header = { + .version = 1, + .packetType = CCNxCodecSchemaV1Types_PacketType_InterestReturn, + .packetLength = packetLength, + .hopLimit = 4, + .returnCode = 7, + .flags = 8, + .headerLength = 9, + }; + + CCNxCodecSchemaV1InterestHeader truth = { + .version = 1, + .packetType = CCNxCodecSchemaV1Types_PacketType_InterestReturn, + .packetLength = htons(packetLength), + .hopLimit = 4, + .returnCode = 7, + .flags = 8, + .headerLength = 9, + }; + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + ssize_t length = ccnxCodecSchemaV1FixedHeaderEncoder_EncodeHeader(encoder, (CCNxCodecSchemaV1FixedHeader *) &header); + assertTrue(length == 8, "Wrong length, got %zd expected %d", length, 8); + + testCompareEncoderToLinearMemory(encoder, length, (uint8_t *) &truth); + + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV0_FixedHeaderEncoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_HashCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_HashCodec.c new file mode 100644 index 00000000..9d03ca2e --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_HashCodec.c @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_HashCodec.c" + +#include <stdio.h> + +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include <ccnx/common/codec/ccnxCodec_Error.h> + +LONGBOW_TEST_RUNNER(ccnxTlvCodec_Hash) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxTlvCodec_Hash) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxTlvCodec_Hash) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidHash); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_SHA256); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_SHA512); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_App); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1HashCodec_Encode); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1HashCodec_Encode_InvalidLength); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue) +{ + // -- 32-byte hash + uint8_t encoded[] = { + 0x00, CCNxCodecSchemaV1Types_HashType_SHA256, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + }; + + PARCBuffer *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + PARCBuffer *payloadBuffer = parcBuffer_Wrap(encoded + 4, sizeof(encoded) - 4, 0, sizeof(encoded) - 4); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer); + PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, sizeof(encoded)); + assertNotNull(hash, "got non-NULL hash when it should have been an error (null)"); + + assertTrue(parcCryptoHash_GetDigestType(hash) == PARCCryptoHashType_SHA256, "Expected to decode the correct hash type."); + assertTrue(parcBuffer_Equals(payloadBuffer, parcCryptoHash_GetDigest(hash)), "Expected the digest to match."); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNull(error, "Got null error when it should have been set"); + + parcCryptoHash_Release(&hash); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&tlvBuffer); + parcBuffer_Release(&payloadBuffer); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidHash) +{ + // -- 32-byte hash + uint8_t encoded[] = { + 0x00, 0xFF, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + }; + + PARCBuffer *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer); + PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, sizeof(encoded)); + assertNull(hash, "Should not have decoded an incorrect hash digest"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&tlvBuffer); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_SHA256) +{ + // -- 32-byte hash + uint8_t encoded[] = { + 0x00, CCNxCodecSchemaV1Types_HashType_SHA256, 0x00, 0x18, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + }; + + PARCBuffer *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer); + PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, sizeof(encoded)); + assertNull(hash, "Should not have decoded a SHA256 hash digest with an incorrect length"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&tlvBuffer); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_SHA512) +{ + // -- 32-byte hash + uint8_t encoded[] = { + 0x00, CCNxCodecSchemaV1Types_HashType_SHA512, 0x00, 0x18, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + }; + + PARCBuffer *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer); + PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, sizeof(encoded)); + assertNull(hash, "Should not have decoded a SHA512 hash digest with an incorrect length"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&tlvBuffer); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_App) +{ + // -- 32-byte hash + uint8_t encoded[] = { + 0x00, CCNxCodecSchemaV1Types_HashType_App, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00,0x00,0x00, 0x00, 0x00 + }; + + PARCBuffer *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer); + PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, sizeof(encoded)); + assertNotNull(hash, "Should have decoded an application hash digest with an arbitrary length"); + + parcCryptoHash_Release(&hash); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&tlvBuffer); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1HashCodec_Encode) +{ + uint8_t encoded[] = { + 0x00, CCNxCodecSchemaV1Types_HashType_SHA256, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + }; + + PARCBuffer *trueEncoding = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + // Create the hash + PARCBuffer *payloadBuffer = parcBuffer_Allocate(0x20); + PARCCryptoHash *expectedHash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, payloadBuffer); + + // Encode it + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1HashCodec_Encode(encoder, expectedHash); + assertFalse(length < 0, "Got error on encode: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + assertTrue(length == sizeof(encoded), "Wrong length, expected %zd got %zd", sizeof(encoded), length); + + // Check for equality + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *testEncoding = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(trueEncoding, testEncoding), "The hash was encoded incorrectly.") + { + printf("Expected\n"); + parcBuffer_Display(trueEncoding, 3); + printf("Got\n"); + parcBuffer_Display(testEncoding, 3); + } + + parcBuffer_Release(&testEncoding); + parcBuffer_Release(&trueEncoding); + + parcCryptoHash_Release(&expectedHash); + parcBuffer_Release(&payloadBuffer); + + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1HashCodec_Encode_InvalidLength) +{ +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxTlvCodec_Hash); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_LinkCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_LinkCodec.c new file mode 100755 index 00000000..599e3a5a --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_LinkCodec.c @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_LinkCodec.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include <ccnx/common/codec/ccnxCodec_Error.h> + +LONGBOW_TEST_RUNNER(ccnxTlvCodec_Name) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxTlvCodec_Name) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxTlvCodec_Name) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_NameOnly); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_AllFields); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_NoName); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_ExtraField); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupName); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupKeyId); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupHash); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_FieldOverrun); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_Underrun); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1LinkCodec_Encode); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_NameOnly) +{ + CCNxName *truth = ccnxName_CreateFromCString("lci:/3=rope"); + + uint8_t encoded[] = { + 0x00, 0x00, 0x00, 8, + 0x00, 0x03, 0x00, 4, + 'r', 'o', 'p', 'e' + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded)); + assertNotNull(link, "got null link: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + const CCNxName *test = ccnxLink_GetName(link); + assertTrue(ccnxName_Equals(truth, test), "Wrong name") + { + printf("Expected\n"); + ccnxName_Display(truth, 3); + printf("Got\n"); + ccnxName_Display(test, 3); + } + + PARCBuffer *testKeyid = ccnxLink_GetKeyID(link); + assertNull(testKeyid, "Got a keyid without the wire encoding for it"); + + PARCBuffer *testHash = ccnxLink_GetContentObjectHash(link); + assertNull(testHash, "got a hash without the wire encoding for it"); + + ccnxLink_Release(&link); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); + ccnxName_Release(&truth); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_AllFields) +{ + CCNxName *truth = ccnxName_CreateFromCString("lci:/3=rope"); + + uint8_t encoded[] = { + // -- name + 0x00, 0x00, 0x00, 8, + 0x00, 0x03, 0x00, 4, + 'r', 'o', 'p', 'e', + // -- keyid + 0x00, 0x01, 0x00, 8, + 0xa0, 0xa1, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, + // -- hash + 0x00, 0x02, 0x00, 16, + 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded)); + assertNotNull(link, "got null link: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + const CCNxName *test = ccnxLink_GetName(link); + assertTrue(ccnxName_Equals(truth, test), "Wrong name") + { + printf("Expected\n"); + ccnxName_Display(truth, 3); + printf("Got\n"); + ccnxName_Display(test, 3); + } + + PARCBuffer *keyid = parcBuffer_Wrap(encoded, sizeof(encoded), 16, 24); + PARCBuffer *testKeyid = ccnxLink_GetKeyID(link); + assertTrue(parcBuffer_Equals(keyid, testKeyid), "Wrong keyid") + { + printf("Expected\n"); + parcBuffer_Display(keyid, 3); + printf("Got\n"); + parcBuffer_Display(testKeyid, 3); + } + + PARCBuffer *hash = parcBuffer_Wrap(encoded, sizeof(encoded), 28, 44); + PARCBuffer *testHash = ccnxLink_GetContentObjectHash(link); + assertTrue(parcBuffer_Equals(hash, testHash), "Wrong hash") + { + printf("Expected\n"); + parcBuffer_Display(hash, 3); + printf("Got\n"); + parcBuffer_Display(testHash, 3); + } + + parcBuffer_Release(&hash); + parcBuffer_Release(&keyid); + + ccnxLink_Release(&link); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); + ccnxName_Release(&truth); +} + +/* + * wire format missing name + */ +LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_NoName) +{ + uint8_t encoded[] = { + // -- keyid + 0x00, 0x01, 0x00, 8, + 0xa0, 0xa1, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, + // -- hash + 0x00, 0x02, 0x00, 16, + 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded)); + assertNull(link, "got non-null link when it should have been an error (null)"); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNotNull(error, "Got null error when it should have been set"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +/* + * Wire format has an extra TLV in it that's not part of the spec + */ +LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_ExtraField) +{ + uint8_t encoded[] = { + // -- name + 0x00, 0x00, 0x00, 8, + 0x00, 0x03, 0x00, 4, + 'r', 'o', 'p', 'e', + // -- keyid + 0x00, 0x01, 0x00, 8, + 0xa0, 0xa1, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, + // -- hash + 0x00, 0x02, 0x00, 16, + 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, + // -- extra + 0x00, 0xFF, 0x00, 4, + 0xc0, 0xc1, 0xc2, 0xc3, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded)); + assertNull(link, "got non-null link when it should have been an error (null)"); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNotNull(error, "Got null error when it should have been set"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupName) +{ + uint8_t encoded[] = { + // -- name + 0x00, 0x00, 0x00, 8, + 0x00, 0x03, 0x00, 4, + 'r', 'o', 'p', 'e', + // -- keyid + 0x00, 0x01, 0x00, 8, + 0xa0, 0xa1, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, + // -- hash + 0x00, 0x02, 0x00, 16, + 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, + // -- name + 0x00, 0x00, 0x00, 8, + 0x00, 0x03, 0x00, 4, + 'r', 'o', 'p', 'e', + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded)); + assertNull(link, "got non-null link when it should have been an error (null)"); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNotNull(error, "Got null error when it should have been set"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupKeyId) +{ + uint8_t encoded[] = { + // -- name + 0x00, 0x00, 0x00, 8, + 0x00, 0x03, 0x00, 4, + 'r', 'o', 'p', 'e', + // -- keyid + 0x00, 0x01, 0x00, 8, + 0xa0, 0xa1, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, + // -- hash + 0x00, 0x02, 0x00, 16, + 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, + // -- keyid + 0x00, 0x01, 0x00, 8, + 0xa0, 0xa1, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded)); + assertNull(link, "got non-null link when it should have been an error (null)"); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNotNull(error, "Got null error when it should have been set"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupHash) +{ + uint8_t encoded[] = { + // -- name + 0x00, 0x00, 0x00, 8, + 0x00, 0x03, 0x00, 4, + 'r', 'o', 'p', 'e', + // -- keyid + 0x00, 0x01, 0x00, 8, + 0xa0, 0xa1, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, + // -- hash + 0x00, 0x02, 0x00, 16, + 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, + // -- hash + 0x00, 0x02, 0x00, 16, + 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded)); + assertNull(link, "got non-null link when it should have been an error (null)"); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNotNull(error, "Got null error when it should have been set"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_FieldOverrun) +{ + // name length is beyond end of fragment + uint8_t encoded[] = { + 0x00, 0x00, 0x00, 30, + 0x00, 0x03, 0x00, 4, + 'r', 'o', 'p', 'e' + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded)); + assertNull(link, "got non-null link when it should have been an error (null)"); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNotNull(error, "Got null error when it should have been set"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_Underrun) +{ + // buffer is too short to even parse the T and L + uint8_t encoded[] = { + 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + // the "2" makes it too short to parse + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, 2); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded)); + assertNull(link, "got non-null link when it should have been an error (null)"); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNotNull(error, "Got null error when it should have been set"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +// ============ + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1LinkCodec_Encode) +{ + uint8_t encoded[] = { + // -- name + 0x00, 0x00, 0x00, 8, + 0x00, 0x03, 0x00, 4, + 'r', 'o', 'p', 'e', + // -- keyid + 0x00, 0x01, 0x00, 8, + 0xa0, 0xa1, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, + // -- hash + 0x00, 0x02, 0x00, 16, + 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, + }; + + CCNxName *trueName = ccnxName_CreateFromCString("lci:/3=rope"); + PARCBuffer *trueKeyId = parcBuffer_Wrap(encoded, sizeof(encoded), 16, 24); + PARCBuffer *trueHash = parcBuffer_Wrap(encoded, sizeof(encoded), 28, 44); + PARCBuffer *trueEncoding = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxLink *link = ccnxLink_Create(trueName, trueKeyId, trueHash); + + // now encode it and compare the the trueEncoding + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + ssize_t length = ccnxCodecSchemaV1LinkCodec_Encode(encoder, link); + assertFalse(length < 0, "Got error on encode: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + assertTrue(length == sizeof(encoded), "Wrong length, expected %zd got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *testEncoding = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(trueEncoding, testEncoding), "Wrong hash") + { + printf("Expected\n"); + parcBuffer_Display(trueEncoding, 3); + printf("Got\n"); + parcBuffer_Display(testEncoding, 3); + } + + parcBuffer_Release(&testEncoding); + parcBuffer_Release(&trueEncoding); + parcBuffer_Release(&trueHash); + parcBuffer_Release(&trueKeyId); + ccnxName_Release(&trueName); + + ccnxLink_Release(&link); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxTlvCodec_Name); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestDecoder.c new file mode 100755 index 00000000..3c1609ab --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestDecoder.c @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_ManifestDecoder.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include "testrig_encoder.c" + +#include <ccnx/common/ccnx_Manifest.h> + +// ========================================================================= + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_ManifestDecoder) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_ManifestDecoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_ManifestDecoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_Decode); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeType); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeHashGroup); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeHashGroupMetadata); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_Decode) +{ + uint8_t rawManifest[40] = { 0x00, 0x07, 0x00, 0x24, + 0x00, 0x02, 0x00, 0x20, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46 }; + PARCBuffer *wireFormat = parcBuffer_Flip(parcBuffer_CreateFromArray(rawManifest, 40)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(wireFormat); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateManifest(); + + bool result = ccnxCodecSchemaV1ManifestDecoder_Decode(decoder, dict); + assertTrue(result, "Expected the manifest to be decoded correctly"); + + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&wireFormat); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeType) +{ + uint8_t rawManifest[40] = { 0x00, 0x07, 0x00, 0x24, + 0x00, 0x02, 0x00, 0x20, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46 }; + PARCBuffer *wireFormat = parcBuffer_Flip(parcBuffer_CreateFromArray(rawManifest, 40)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(wireFormat); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateManifest(); + + uint16_t type = ccnxCodecTlvDecoder_GetType(decoder); + uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder); + + bool result = _decodeType(decoder, dict, type, length); + assertTrue(result, "Expected the manifest type to be correctly decoded at the top level"); + + ccnxManifest_Release(&dict); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&wireFormat); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeHashGroup) +{ + uint8_t rawManifest[40] = { 0x00, 0x07, 0x00, 0x24, + 0x00, 0x02, 0x00, 0x20, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46 }; + PARCBuffer *wireFormat = parcBuffer_Flip(parcBuffer_CreateFromArray(rawManifest, 40)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(wireFormat); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateManifest(); + + ccnxCodecTlvDecoder_GetType(decoder); // swallow type + uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder); + + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + bool result = _decodeHashGroup(decoder, dict, group, length); + assertTrue(result, "Expected hash group to be decoded correctly."); + + PARCBuffer *expectedPointer = parcBuffer_AllocateCString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + CCNxManifestHashGroupPointer *pointer = ccnxManifestHashGroup_GetPointerAtIndex(group, 0); + const PARCBuffer *actualPointer = ccnxManifestHashGroupPointer_GetDigest(pointer); + assertTrue(parcBuffer_Equals(expectedPointer, actualPointer), "Expected decoded pointer to equal %s, got %s", parcBuffer_ToHexString(expectedPointer), parcBuffer_ToHexString(actualPointer)); + + parcBuffer_Release(&expectedPointer); + + ccnxManifestHashGroup_Release(&group); + ccnxManifest_Release(&dict); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&wireFormat); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeHashGroupMetadata) +{ + // Re-build the expected metadata from the manifest + CCNxName *groupLocator = ccnxName_CreateFromCString("ccnx:/locator"); + PARCBuffer *digest = parcBuffer_Allocate(16); + for (size_t i = 0; i < parcBuffer_Limit(digest); i++) { + parcBuffer_PutUint8(digest, 0); + } + parcBuffer_Flip(digest); + size_t entrySize = 1; + size_t dataSize = 2; + size_t blockSize = 3; + size_t treeHeight = 4; + + // Compute the expected size of this metadata group. + size_t metadataSize = 4 * (4 + 8) + 4 + parcBuffer_Limit(digest) + 4 + strlen("ccnx:/locator"); + + // See test_ccnxCodecSchemaV1_ManifestEncoder.c for the packet construction details. + uint8_t rawMetadata[89] = { 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_Metadata, + 0x00, metadataSize, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_Locator, + 0x00, strlen("ccnx:/locator"), + 'c', 'c', + 'n', 'x', + ':', '/', + 'l', 'o', + 'c', 'a', + 't', 'o', + 'r', + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_DataSize, + 0x00, 0x08, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, dataSize, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_BlockSize, + 0x00, 0x08, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, blockSize, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_EntrySize, + 0x00, 0x08, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, entrySize, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_TreeHeight, + 0x00, 0x08, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, treeHeight, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_OverallDataSha256, + 0x00, parcBuffer_Remaining(digest), + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00 }; + PARCBuffer *wireFormat = parcBuffer_Flip(parcBuffer_CreateFromArray(rawMetadata, sizeof(rawMetadata))); + + // Create the encoder and swallow the top level container + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(wireFormat); + ccnxCodecTlvDecoder_GetType(decoder); // swallow type + uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder); + + // Decode the metadata + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + bool result = _decodeHashGroupMetadata(decoder, group, length); + assertTrue(result, "Expected hash group metadata to be decoded correctly."); + + const CCNxName *actualLocator = ccnxManifestHashGroup_GetLocator(group); + size_t actualEntrySize = ccnxManifestHashGroup_GetEntrySize(group); + size_t actualDataSize = ccnxManifestHashGroup_GetDataSize(group); + size_t actualBlockSize = ccnxManifestHashGroup_GetBlockSize(group); + size_t actualTreeHeight = ccnxManifestHashGroup_GetTreeHeight(group); + const PARCBuffer *actualDigest = ccnxManifestHashGroup_GetOverallDataDigest(group); + + assertTrue(ccnxName_Equals(groupLocator, actualLocator), "Expected decoded locator to equal %s, got %s", ccnxName_ToString(groupLocator), ccnxName_ToString(actualLocator)); + assertTrue(entrySize == actualEntrySize, "Expected %zu entry size, got %zu", entrySize, actualEntrySize); + assertTrue(dataSize == actualDataSize, "Expected %zu data size, got %zu", dataSize, actualDataSize); + assertTrue(blockSize == actualBlockSize, "Expected %zu block size, got %zu", blockSize, actualBlockSize); + assertTrue(treeHeight == actualTreeHeight, "Expected %zu tree height, got %zu", treeHeight, actualTreeHeight); + assertTrue(parcBuffer_Equals(digest, actualDigest), "Expected %s digest, got %s", parcBuffer_ToHexString(digest), parcBuffer_ToHexString(actualDigest)); + + parcBuffer_Release(&digest); + ccnxName_Release(&groupLocator); + + ccnxManifestHashGroup_Release(&group); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&wireFormat); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_ManifestDecoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestEncoder.c new file mode 100755 index 00000000..a0e36abf --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestEncoder.c @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_ManifestEncoder.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include "testrig_encoder.c" + +#include <ccnx/common/ccnx_Manifest.h> + +// ========================================================================= + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_ManifestEncoder) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_ManifestEncoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_ManifestEncoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeEmpty); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeSingleHashGroup); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeSingleHashGroup_WithMetadata); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_AddPointer); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeEmpty) +{ + CCNxName *locator = ccnxName_CreateFromCString("lci:/name"); + CCNxManifest *manifest = ccnxManifest_Create(locator); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + size_t result = ccnxCodecSchemaV1ManifestEncoder_Encode(encoder, manifest); + + assertTrue(result == 0, "Expected an empty Manifest to be encoded to size 0, got %zu", result); + + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxManifest_Release(&manifest); + ccnxName_Release(&locator); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_AddPointer) +{ + CCNxName *locator = ccnxName_CreateFromCString("ccnx:/name"); + CCNxManifest *manifest = ccnxManifest_Create(locator); + + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + PARCBuffer *pointer = parcBuffer_Flip(parcBuffer_ParseHexString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")); + ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, pointer); + + ccnxManifest_AddHashGroup(manifest, group); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + size_t result = ccnxCodecSchemaV1ManifestEncoder_Encode(encoder, manifest); + size_t expected = 4 + 4 + parcBuffer_Remaining(pointer); // hash group TL, pointer TL, pointer V + + assertTrue(result == expected, "Expected an empty Manifest to be encoded to size %zu, got %zu", expected, result); + + CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvEncoder_CreateIoVec(encoder); + const struct iovec *vector = ccnxCodecNetworkBufferIoVec_GetArray(iovec); + + assertTrue(vector->iov_len == expected, "Expected the IO vector to contain the encoded manifest"); + assertTrue(memcmp(vector->iov_base + 8, parcBuffer_Overlay(pointer, parcBuffer_Remaining(pointer)), vector->iov_len - 8) == 0, "Expected the same pointer to be encoded"); + + uint16_t expectedType = CCNxCodecSchemaV1Types_CCNxManifestHashGroup_DataPointer; + uint8_t *base = (uint8_t *) vector->iov_base; + uint16_t actualType = (base[4] << 8) | base[5]; + assertTrue(expectedType == actualType, "Expected the type to be written correctly as CCNxCodecSchemaV1Types_CCNxManifestHashGroup_DataPointer"); + + ccnxCodecNetworkBufferIoVec_Release(&iovec); + + // Cleanup + parcBuffer_Release(&pointer); + ccnxManifestHashGroup_Release(&group); + + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxManifest_Release(&manifest); + ccnxName_Release(&locator); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeSingleHashGroup) +{ + CCNxName *locator = ccnxName_CreateFromCString("ccnx:/name"); + CCNxManifest *manifest = ccnxManifest_Create(locator); + + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + PARCBuffer *pointer = parcBuffer_Flip(parcBuffer_ParseHexString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")); + ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, pointer); + + ccnxManifest_AddHashGroup(manifest, group); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + size_t result = ccnxCodecSchemaV1ManifestEncoder_Encode(encoder, manifest); + size_t expected = 4 + 4 + parcBuffer_Remaining(pointer); // hash group TL, pointer TL, pointer V + + assertTrue(result == expected, "Expected an empty Manifest to be encoded to size %zu, got %zu", expected, result); + + CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvEncoder_CreateIoVec(encoder); + const struct iovec *vector = ccnxCodecNetworkBufferIoVec_GetArray(iovec); + + uint8_t expectedVector[24] = { 0x00, 0x07, 0x00, 0x14, + 0x00, 0x02, 0x00, 0x10, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF }; + assertTrue(vector->iov_len == expected, "Expected the IO vector to contain the encoded manifest"); + assertTrue(memcmp(vector->iov_base, expectedVector, vector->iov_len) == 0, "Expected the same pointer to be encoded"); + + ccnxCodecNetworkBufferIoVec_Release(&iovec); + + // Cleanup + parcBuffer_Release(&pointer); + ccnxManifestHashGroup_Release(&group); + + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxManifest_Release(&manifest); + ccnxName_Release(&locator); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeSingleHashGroup_WithMetadata) +{ + CCNxName *locator = ccnxName_CreateFromCString("ccnx:/name"); + CCNxManifest *manifest = ccnxManifest_Create(locator); + + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + PARCBuffer *pointer = parcBuffer_Flip(parcBuffer_ParseHexString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")); + ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, pointer); + + // Set the metadata now + CCNxName *groupLocator = ccnxName_CreateFromCString("ccnx:/locator"); + ccnxManifestHashGroup_SetLocator(group, groupLocator); + + PARCBuffer *digest = parcBuffer_Allocate(16); + for (size_t i = 0; i < parcBuffer_Limit(digest); i++) { + parcBuffer_PutUint8(digest, 0); + } + parcBuffer_Flip(digest); + ccnxManifestHashGroup_SetOverallDataDigest(group, digest); + + size_t entrySize = 1; + ccnxManifestHashGroup_SetEntrySize(group, entrySize); + + size_t dataSize = 2; + ccnxManifestHashGroup_SetDataSize(group, dataSize); + + size_t blockSize = 3; + ccnxManifestHashGroup_SetBlockSize(group, blockSize); + + size_t treeHeight = 4; + ccnxManifestHashGroup_SetTreeHeight(group, treeHeight); + + // Add the hash group to the manifest + ccnxManifest_AddHashGroup(manifest, group); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + size_t result = ccnxCodecSchemaV1ManifestEncoder_Encode(encoder, manifest); + + // Compute the expected size with all of the metadata. + // This packet was crafted by hand. + size_t expected = 4; // hash group TL + expected += 4 + parcBuffer_Remaining(pointer); // pointer TL, pointer V + expected += 4; // metadata TL + expected += 4 * (4 + 8); // 64-bit integer property TLs, Vs + expected += 4 + parcBuffer_Remaining(digest); // digest T and V + expected += 4 + strlen("ccnx:/locator"); // name TL, segment TL, and segment V + + // Compute only the size of the metadata + size_t metadataSize = expected; + metadataSize -= 4; // top-level TL container + metadataSize -= (4 + parcBuffer_Remaining(pointer)); // pointer TLV + metadataSize -= 4; // metadata TL container + + assertTrue(result == expected, "Expected an empty Manifest to be encoded to size %zu, got %zu", expected, result); + + // Now do the encoding + CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvEncoder_CreateIoVec(encoder); + const struct iovec *vector = ccnxCodecNetworkBufferIoVec_GetArray(iovec); + + uint8_t expectedVector[129] = { 0x00, 0x07, + 0x00, expected - 4, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_Metadata, + 0x00, metadataSize, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_Locator, + 0x00, strlen("ccnx:/locator"), + 'c', 'c', + 'n', 'x', + ':', '/', + 'l', 'o', + 'c', 'a', + 't', 'o', + 'r', + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_DataSize, + 0x00, 0x08, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, dataSize, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_BlockSize, + 0x00, 0x08, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, blockSize, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_EntrySize, + 0x00, 0x08, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, entrySize, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_TreeHeight, + 0x00, 0x08, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, treeHeight, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_OverallDataSha256, + 0x00, parcBuffer_Remaining(digest), + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_DataPointer, + 0x00, parcBuffer_Remaining(pointer), + 0xFF, 0xFF, + 0xFF, 0xFF, + 0xFF, 0xFF, + 0xFF, 0xFF, + 0xFF, 0xFF, + 0xFF, 0xFF, + 0xFF, 0xFF, + 0xFF, 0xFF }; + assertTrue(vector->iov_len == expected, "Expected the IO vector to contain the encoded manifest"); + assertTrue(memcmp(vector->iov_base, expectedVector, vector->iov_len) == 0, "Expected the same HashGroup to be encoded"); + + ccnxCodecNetworkBufferIoVec_Release(&iovec); + + // Cleanup + parcBuffer_Release(&pointer); + parcBuffer_Release(&digest); + ccnxManifestHashGroup_Release(&group); + ccnxName_Release(&groupLocator); + + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxManifest_Release(&manifest); + ccnxName_Release(&locator); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_ManifestEncoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageDecoder.c new file mode 100644 index 00000000..ab339fc1 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageDecoder.c @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_MessageDecoder.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h> + +#include "testrig_packetwrapper.c" + + +// ========================================================================= + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_MessageDecoder) +{ + LONGBOW_RUN_TEST_FIXTURE(ContentObject); + LONGBOW_RUN_TEST_FIXTURE(Interest); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_MessageDecoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_MessageDecoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ========================================================================= +// Utility functions to get a field in the format we expect for the testrig. +// We cannot use the facades because those try to assert a type on the dictionary which +// is not part of the MessageDecoder. + +static CCNxName * +_getName(CCNxTlvDictionary *contentObjectDictionary) +{ + return ccnxTlvDictionary_GetName(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME); +} + +static PARCBuffer * +_getPayload(const CCNxTlvDictionary *contentObjectDictionary) +{ + return ccnxTlvDictionary_GetBuffer(contentObjectDictionary, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD); +} + +static int64_t +_getPayloadType(CCNxTlvDictionary *contentObjectDictionary) +{ + return (int64_t) ccnxTlvDictionary_GetInteger(contentObjectDictionary, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE); +} + +static int64_t +_getExpiryTime(CCNxTlvDictionary *contentObjectDictionary) +{ + return (int64_t) ccnxTlvDictionary_GetInteger(contentObjectDictionary, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME); +} + +static int64_t +_getEndChunkNumber(CCNxTlvDictionary *contentObjectDictionary) +{ + return (int64_t) ccnxTlvDictionary_GetInteger(contentObjectDictionary, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT); +} + +static PARCCryptoHash * +_getKeyIdRestriction(CCNxTlvDictionary *messageDictionary) +{ + return (PARCCryptoHash *) ccnxTlvDictionary_GetObject(messageDictionary, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION); +} + +static PARCCryptoHash * +_getHashRestriction(CCNxTlvDictionary *messageDictionary) +{ + return (PARCCryptoHash *) ccnxTlvDictionary_GetObject(messageDictionary, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION); +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(ContentObject) +{ + LONGBOW_RUN_TEST_CASE(ContentObject, Name); + LONGBOW_RUN_TEST_CASE(ContentObject, Payload); + LONGBOW_RUN_TEST_CASE(ContentObject, PayloadType); + LONGBOW_RUN_TEST_CASE(ContentObject, ExpiryTime); + LONGBOW_RUN_TEST_CASE(ContentObject, EndChunkNumber); +} + +LONGBOW_TEST_FIXTURE_SETUP(ContentObject) +{ + longBowTestCase_SetClipBoardData(testCase, + commonSetup(v1_content_nameA_keyid1_rsasha256, + sizeof(v1_content_nameA_keyid1_rsasha256), + v1_content_nameA_keyid1_rsasha256_truthTableEntries, + V1_MANIFEST_OBJ_CONTENTOBJECT)); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(ContentObject) +{ + commonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(ContentObject, Name) +{ +// TestData *data = longBowTestCase_GetClipBoardData(testCase); +// testNameGetter(data, V1_MANIFEST_OBJ_NAME, ccnxCodecSchemaV1MessageDecoder_Decode, _getName); +} + +LONGBOW_TEST_CASE(ContentObject, Payload) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + testBufferGetter(data, V1_MANIFEST_OBJ_PAYLOAD, ccnxCodecSchemaV1MessageDecoder_Decode, _getPayload); +} + +LONGBOW_TEST_CASE(ContentObject, PayloadType) +{ + // The payload type is translated from the wire format value to the CCNxPayloadType value, + // so this test cannot use the automated framework as the value in the dictionary will not + // be the same as the value in the wire format + + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + bool decodeSuccess = ccnxCodecSchemaV1MessageDecoder_Decode(data->decoder, data->dictionary); + assertTrue(decodeSuccess, "failure on ccnxCodecSchemaV1MessageDecoder_Decode"); + + CCNxPayloadType testPayloadType = (CCNxPayloadType) _getPayloadType(data->dictionary); + + // look up the true name buffer from the truth table + TlvExtent extent = getTruthTableExtent(data->truthTable, V1_MANIFEST_OBJ_PAYLOADTYPE); + + PARCBuffer + *truthbuffer = parcBuffer_Wrap(data->packet, data->packetLength, extent.offset, extent.offset + extent.length); + uint64_t truthvalue = -2; + ccnxCodecTlvUtilities_GetVarInt(truthbuffer, parcBuffer_Remaining(truthbuffer), &truthvalue); + + CCNxPayloadType truthPayloadType = -1; + bool success = + _translateWirePayloadTypeToCCNxPayloadType((CCNxCodecSchemaV1Types_PayloadType) truthvalue, &truthPayloadType); + assertTrue(success, "failure in _translateWirePayloadTypeToCCNxPayloadType for wireFormatValue %" + PRId64, truthvalue); + + parcBuffer_Release(&truthbuffer); + + assertTrue(truthPayloadType == testPayloadType, "Wrong value, got %d expected %d", testPayloadType, + truthPayloadType); +} + +LONGBOW_TEST_CASE(ContentObject, ExpiryTime) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + testInt64Getter(data, V1_MANIFEST_OBJ_EXPIRY_TIME, ccnxCodecSchemaV1MessageDecoder_Decode, _getExpiryTime); +} + +LONGBOW_TEST_CASE(ContentObject, EndChunkNumber) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + testInt64Getter(data, V1_MANIFEST_OBJ_ENDSEGMENT, ccnxCodecSchemaV1MessageDecoder_Decode, _getEndChunkNumber); +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Interest) +{ + LONGBOW_RUN_TEST_CASE(Interest, Name); + LONGBOW_RUN_TEST_CASE(Interest, Payload); + LONGBOW_RUN_TEST_CASE(Interest, KeyIdRestriction); + LONGBOW_RUN_TEST_CASE(Interest, HashRestriction); +} + +LONGBOW_TEST_FIXTURE_SETUP(Interest) +{ + longBowTestCase_SetClipBoardData(testCase, + commonSetup(v1_interest_all_fields, + sizeof(v1_interest_all_fields), + TRUTHTABLENAME(v1_interest_all_fields), + V1_MANIFEST_INT_INTEREST)); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Interest) +{ + commonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Interest, Name) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + testNameGetter(data, V1_MANIFEST_INT_NAME, ccnxCodecSchemaV1MessageDecoder_Decode, _getName); +} + +LONGBOW_TEST_CASE(Interest, Payload) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + testBufferGetter(data, V1_MANIFEST_INT_PAYLOAD, ccnxCodecSchemaV1MessageDecoder_Decode, _getPayload); +} + +LONGBOW_TEST_CASE(Interest, KeyIdRestriction) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + testHashGetter(data, V1_MANIFEST_INT_KEYID, ccnxCodecSchemaV1MessageDecoder_Decode, _getKeyIdRestriction); +} + +LONGBOW_TEST_CASE(Interest, HashRestriction) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + testHashGetter(data, V1_MANIFEST_INT_OBJHASH, ccnxCodecSchemaV1MessageDecoder_Decode, _getHashRestriction); +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, _translateWirePayloadTypeToCCNxPayloadType); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, _translateWirePayloadTypeToCCNxPayloadType) +{ + uint32_t sentinel = 0xFFFF; + + struct { + CCNxCodecSchemaV1Types_PayloadType wire; + CCNxPayloadType payloadType; + bool success; + } vectors[] = { + { .wire = CCNxCodecSchemaV1Types_PayloadType_Data, .payloadType = CCNxPayloadType_DATA, .success = true }, + { .wire = CCNxCodecSchemaV1Types_PayloadType_Key, .payloadType = CCNxPayloadType_KEY, .success = true }, + { .wire = CCNxCodecSchemaV1Types_PayloadType_Link, .payloadType = CCNxPayloadType_LINK, .success = true }, + { .wire = -2, .payloadType = -2, .success = false }, + { .wire = sentinel, .payloadType = sentinel } + }; + + for (int i = 0; vectors[i].wire != sentinel; i++) { + CCNxPayloadType payloadType = -1; + bool success = _translateWirePayloadTypeToCCNxPayloadType(vectors[i].wire, &payloadType); + assertTrue(success == vectors[i].success, "Incorrect return index %d, expected %d got %d", i, + vectors[i].success, success); + + if (success) { + assertTrue(payloadType == vectors[i].payloadType, "Wrong payloadType index %d, expected %d got %d", i, + vectors[i].payloadType, payloadType); + } + } +} + +// ========================================================================= + + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_MessageDecoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageEncoder.c new file mode 100644 index 00000000..49452626 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageEncoder.c @@ -0,0 +1,644 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_MessageEncoder.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameless_nosig.h> + +#include "testrig_encoder.c" + +#include <ccnx/common/ccnx_ContentObject.h> +#include <ccnx/common/ccnx_Interest.h> + +#include <ccnx/common/internal/ccnx_InterestDefault.h> + +// ========================================================================= + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_MessageEncoder) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); + LONGBOW_RUN_TEST_FIXTURE(UnknownType); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_MessageEncoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_MessageEncoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(ContentObject, Interest); + LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject); + LONGBOW_RUN_TEST_CASE(ContentObject, ContentObjectNameless); + LONGBOW_RUN_TEST_CASE(InterestReturn, InterestReturn); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(ContentObject, Interest) +{ + // create an Interest that replicates v1_interest_all_fields + TlvExtent keyidExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_KEYID); + TlvExtent hashExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_OBJHASH); + TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_PAYLOAD); + TlvExtent interestExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_INTEREST); + + CCNxName *name = ccnxName_CreateFromCString("lci:/3=cool"); + uint32_t lifetime = CCNxInterestDefault_LifetimeMilliseconds; + uint32_t hoplimit = CCNxInterestDefault_HopLimit; + + printf("%d %d\n", keyidExtent.offset + 4, keyidExtent.offset + keyidExtent.length - 4); + PARCBuffer *keyid = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), keyidExtent.offset + 4, keyidExtent.offset + keyidExtent.length); + PARCBuffer *hash = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), hashExtent.offset + 4, hashExtent.offset + hashExtent.length); + PARCBuffer *payload = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), payloadExtent.offset, payloadExtent.offset + payloadExtent.length); + + CCNxTlvDictionary *interest = + ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation, + name, lifetime, keyid, hash, hoplimit); + + ccnxInterest_SetPayloadAndId(interest, payload); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecSchemaV1MessageEncoder_Encode(encoder, interest); + + PARCBuffer *truth = parcBuffer_Wrap(v1_interest_all_fields, + sizeof(v1_interest_all_fields), + interestExtent.offset, + interestExtent.offset + interestExtent.length); + + testCompareEncoderToBuffer(encoder, truth); + + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); + parcBuffer_Release(&payload); + parcBuffer_Release(&hash); + parcBuffer_Release(&keyid); + ccnxName_Release(&name); + ccnxTlvDictionary_Release(&interest); +} + +LONGBOW_TEST_CASE(InterestReturn, InterestReturn) +{ + // create an Interest that replicates v1_interest_all_fields + TlvExtent keyidExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_KEYID); + TlvExtent hashExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_OBJHASH); + TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_PAYLOAD); + TlvExtent interestExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_INTEREST); + + CCNxName *name = ccnxName_CreateFromCString("lci:/3=cool"); + uint32_t lifetime = CCNxInterestDefault_LifetimeMilliseconds; + uint32_t hoplimit = CCNxInterestDefault_HopLimit; + + PARCBuffer *keyid = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), keyidExtent.offset + 4, keyidExtent.offset + keyidExtent.length); + PARCBuffer *hash = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), hashExtent.offset + 4, hashExtent.offset + hashExtent.length); + PARCBuffer *payload = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), payloadExtent.offset, payloadExtent.offset + payloadExtent.length); + + CCNxTlvDictionary *interest = + ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation, + name, lifetime, keyid, hash, hoplimit); + parcBuffer_Release(&hash); + parcBuffer_Release(&keyid); + ccnxName_Release(&name); + + ccnxInterest_SetPayloadAndId(interest, payload); + parcBuffer_Release(&payload); + + CCNxInterestReturn *interestReturn = + ccnxInterestReturn_Create(interest, CCNxInterestReturn_ReturnCode_HopLimitExceeded); + ccnxTlvDictionary_Release(&interest); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecSchemaV1MessageEncoder_Encode(encoder, interestReturn); + + size_t packetSize = sizeof(v1_interest_all_fields); + uint8_t *testPacket = (uint8_t *) parcSafeMemory_Allocate(packetSize); + memcpy(testPacket, v1_interest_all_fields, packetSize); + testPacket[1] = 0x02; //InterestReturn + testPacket[5] = CCNxInterestReturn_ReturnCode_HopLimitExceeded; + + PARCBuffer *truth = parcBuffer_Wrap(testPacket, packetSize, + interestExtent.offset, + interestExtent.offset + interestExtent.length); + + testCompareEncoderToBuffer(encoder, truth); + + parcSafeMemory_Deallocate((void **) &testPacket); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); + ccnxInterestReturn_Release(&interestReturn); +} + +LONGBOW_TEST_CASE(ContentObject, ContentObjectNameless) +{ + // create a Content Object that replicates v1_content_nameA_keyid1_rsasha256 + TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameless_nosig), V1_MANIFEST_OBJ_PAYLOAD); + TlvExtent contentObjectExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameless_nosig), V1_MANIFEST_OBJ_CONTENTOBJECT); + + PARCBuffer *payload = parcBuffer_Wrap(v1_content_nameless_nosig, sizeof(v1_content_nameless_nosig), payloadExtent.offset, payloadExtent.offset + payloadExtent.length); + + CCNxTlvDictionary *contentobject = + ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation, + NULL, CCNxPayloadType_KEY, payload); + + ccnxContentObject_SetExpiryTime(contentobject, 0x01434B198400ULL); + ccnxContentObject_SetFinalChunkNumber(contentobject, 0x06050403); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecSchemaV1MessageEncoder_Encode(encoder, contentobject); + + PARCBuffer *truth = parcBuffer_Wrap(v1_content_nameless_nosig, sizeof(v1_content_nameless_nosig), contentObjectExtent.offset, contentObjectExtent.offset + contentObjectExtent.length); + + testCompareEncoderToBuffer(encoder, truth); + + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); + parcBuffer_Release(&payload); + ccnxTlvDictionary_Release(&contentobject); +} + +LONGBOW_TEST_CASE(ContentObject, ContentObject) +{ + // create a Content Object that replicates v1_content_nameA_keyid1_rsasha256 + TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_PAYLOAD); + TlvExtent contentObjectExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_CONTENTOBJECT); + + CCNxName *name = ccnxName_CreateFromCString("lci:/3=hello/0xf000=ouch"); + + PARCBuffer *payload = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), payloadExtent.offset, payloadExtent.offset + payloadExtent.length); + + CCNxTlvDictionary *contentobject = + ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation, + name, CCNxPayloadType_KEY, payload); + + ccnxContentObject_SetExpiryTime(contentobject, 0x01434B198400ULL); + ccnxContentObject_SetFinalChunkNumber(contentobject, 0x06050403); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecSchemaV1MessageEncoder_Encode(encoder, contentobject); + + PARCBuffer *truth = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), contentObjectExtent.offset, contentObjectExtent.offset + contentObjectExtent.length); + + testCompareEncoderToBuffer(encoder, truth); + + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); + parcBuffer_Release(&payload); + ccnxName_Release(&name); + ccnxTlvDictionary_Release(&contentobject); +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Interest) +{ + LONGBOW_RUN_TEST_CASE(Interest, ccnxCodecSchemaV1MessageEncoder_Encode); +} + +LONGBOW_TEST_FIXTURE_SETUP(Interest) +{ + longBowTestCase_SetClipBoardData(testCase, + commonSetup(v1_interest_all_fields, + sizeof(v1_interest_all_fields), + TRUTHTABLENAME(v1_interest_all_fields), + V1_MANIFEST_INT_INTEREST)); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Interest) +{ + testrigencoder_CommonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Interest, ccnxCodecSchemaV1MessageEncoder_Encode) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1MessageEncoder_Encode(data->encoder, data->dictionary); + + testCompareEncoderToBuffer(data->encoder, data->memoryRegion); +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(InterestReturn) +{ + LONGBOW_RUN_TEST_CASE(InterestReturn, ccnxCodecSchemaV1MessageEncoder_Encode); +} + +LONGBOW_TEST_FIXTURE_SETUP(InterestReturn) +{ + size_t packetSize = sizeof(v1_interest_all_fields); + uint8_t *testPacket = (uint8_t *) parcSafeMemory_Allocate(packetSize); + memcpy(testPacket, v1_interest_all_fields, packetSize); + testPacket[1] = 0x02; //InterestReturn + testPacket[5] = CCNxInterestReturn_ReturnCode_HopLimitExceeded; + + longBowTestCase_SetClipBoardData(testCase, + commonSetup(v1_interest_all_fields, + sizeof(v1_interest_all_fields), + TRUTHTABLENAME(v1_interest_all_fields), + V1_MANIFEST_INT_INTEREST)); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(InterestReturn) +{ + testrigencoder_CommonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(InterestReturn, ccnxCodecSchemaV1MessageEncoder_Encode) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1MessageEncoder_Encode(data->encoder, data->dictionary); + + testCompareEncoderToBuffer(data->encoder, data->memoryRegion); +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, _encodeName); + LONGBOW_RUN_TEST_CASE(Local, _encodePayload); + LONGBOW_RUN_TEST_CASE(Local, _encodePayloadType); + LONGBOW_RUN_TEST_CASE(Local, _encodeExpiryTime); + LONGBOW_RUN_TEST_CASE(Local, _encodeEndChunkNumber); + LONGBOW_RUN_TEST_CASE(Local, _encodeKeyIdRestriction); + LONGBOW_RUN_TEST_CASE(Local, _encodeContentObjectHashRestriction); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h> +#include <parc/algol/parc_Varint.h> + +LONGBOW_TEST_CASE(Local, _encodeName) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/0xf001=foot/0xf002=toe/0xf003=nail"); + uint8_t encoded[] = { + 0x00, 0x00, 0x00, 23, + 0xF0, 0x01, 0x00, 4, + 'f', 'o', 'o', 't', + 0xF0, 0x02, 0x00, 3, + 't', 'o', 'e', + 0xF0, 0x03, 0x00, 4, + 'n', 'a', 'i', 'l' + }; + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + ccnxTlvDictionary_PutName(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME, name); + + _encodeName(encoder, dictionary); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + assertTrue(parcBuffer_Equals(truth, test), "buffers do not match") + { + printf("Expected:\n"); + parcBuffer_Display(truth, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxName_Release(&name); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Local, _encodePayload) +{ + uint8_t payload[] = { 0xf1, 0xf2, 0xf3 }; + uint8_t encoded[] = { + 0x00, 0x01, 0x00, 3, + 0xf1, 0xf2, 0xf3 + }; + + PARCBuffer *buffer = parcBuffer_Wrap(payload, sizeof(payload), 0, sizeof(payload)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + ccnxTlvDictionary_PutBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, buffer); + + _encodePayload(encoder, dictionary); + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "buffers do not match") + { + printf("Expected:\n"); + parcBuffer_Display(truth, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + parcBuffer_Release(&buffer); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Local, _encodePayloadType) +{ + CCNxPayloadType type = CCNxPayloadType_LINK; + + uint8_t encoded[] = { + 0x00, 0x05, 0x00, 1, + CCNxCodecSchemaV1Types_PayloadType_Link + }; + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE, type); + + _encodePayloadType(encoder, dictionary); + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "buffers do not match") + { + printf("Expected:\n"); + parcBuffer_Display(truth, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Local, _encodeExpiryTime) +{ + uint64_t expiry = 0x123456789ABCDEF0ULL; + uint8_t encoded[] = { + 0x00, 0x06, 0x00, 8, + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, 0xDE, 0xF0 + }; + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME, expiry); + + _encodeExpiryTime(encoder, dictionary); + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "buffers do not match") + { + printf("Expected:\n"); + parcBuffer_Display(truth, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Local, _encodeEndChunkNumber) +{ + uint64_t endChunkNumber = 0x818283ULL; + uint8_t encoded[] = { + 0x00, 0x19, 0x00, 3, + 0x81, 0x82, 0x83 + }; + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT, endChunkNumber); + + _encodeEndChunkNumber(encoder, dictionary); + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "buffers do not match") + { + printf("Expected:\n"); + parcBuffer_Display(truth, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Local, _encodeKeyIdRestriction) +{ + uint8_t encoded[] = { + 0x00, 0x02, 0x00, 0x24, + 0x00, 0x01, 0x00, 0x20, + 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 8, sizeof(encoded)); + PARCCryptoHash *hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + ccnxTlvDictionary_PutObject(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION, hash); + + _encodeKeyIdRestriction(encoder, dictionary); + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "buffers do not match") + { + printf("Expected:\n"); + parcBuffer_Display(truth, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + parcBuffer_Release(&buffer); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&dictionary); + parcCryptoHash_Release(&hash); +} + +LONGBOW_TEST_CASE(Local, _encodeContentObjectHashRestriction) +{ + uint8_t encoded[] = { + 0x00, 0x03, 0x00, 0x24, + 0x00, 0x01, 0x00, 0x20, + 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 8, sizeof(encoded)); + PARCCryptoHash *hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + ccnxTlvDictionary_PutObject(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION, hash); + + _encodeContentObjectHashRestriction(encoder, dictionary); + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "buffers do not match") + { + printf("Expected:\n"); + parcBuffer_Display(truth, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + parcBuffer_Release(&buffer); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&dictionary); + parcCryptoHash_Release(&hash); +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(UnknownType) +{ + LONGBOW_RUN_TEST_CASE(UnknownType, Unknown); +} + +LONGBOW_TEST_FIXTURE_SETUP(UnknownType) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(UnknownType) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(UnknownType, Unknown) +{ + CCNxTlvDictionary *unknown = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, 1); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1MessageEncoder_Encode(encoder, unknown); + assertTrue(length < 0, "Did not get error return when encoding unknown type"); + + CCNxCodecError *error = ccnxCodecTlvEncoder_GetError(encoder); + assertNotNull(error, "encoder did not set the error"); + + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&unknown); +} + +// ================================================================================== + + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_MessageEncoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameCodec.c new file mode 100755 index 00000000..8a33a0e2 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameCodec.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_NameCodec.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(ccnxTlvCodec_Name) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxTlvCodec_Name) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxTlvCodec_Name) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecName_Decode_RightType); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecName_Decode_WrongType); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecName_Encode); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecName_Decode_RightType) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("brandywine"); + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer); + CCNxName *truth = ccnxName_Append(ccnxName_Create(), segment); + ccnxNameSegment_Release(&segment); + parcBuffer_Release(&buffer); + + uint8_t decodeBytes[] = { 0x10, 0x20, 0x00, 0x0E, 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' }; + PARCBuffer *decodeBuffer = parcBuffer_Wrap(decodeBytes, sizeof(decodeBytes), 0, sizeof(decodeBytes)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(decodeBuffer); + CCNxName *test = ccnxCodecSchemaV1NameCodec_Decode(decoder, 0x1020); + + assertTrue(ccnxName_Equals(truth, test), "Name segments do not match"); + + ccnxName_Release(&test); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&decodeBuffer); + ccnxName_Release(&truth); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecName_Decode_WrongType) +{ + uint8_t decodeBytes[] = { 0x10, 0x20, 0x00, 0x0E, 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' }; + PARCBuffer *decodeBuffer = parcBuffer_Wrap(decodeBytes, sizeof(decodeBytes), 0, sizeof(decodeBytes)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(decodeBuffer); + CCNxName *test = ccnxCodecSchemaV1NameCodec_Decode(decoder, 0xFFFF); + + assertNull(test, "Name should have returned NULL because the name type does not match"); + assertTrue(ccnxCodecTlvDecoder_Position(decoder) == 0, "Position should not have moved, expected 0, got %zu", ccnxCodecTlvDecoder_Position(decoder)); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&decodeBuffer); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecName_Encode) +{ + uint8_t truthBytes[] = { 0x10, 0x20, 0x00, 0x0E, 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' }; + PARCBuffer *truth = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(encoder); + + PARCBuffer *buffer = parcBuffer_WrapCString("brandywine"); + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer); + + CCNxName *name = ccnxName_Append(ccnxName_Create(), segment); + ccnxNameSegment_Release(&segment); + parcBuffer_Release(&buffer); + + ccnxCodecSchemaV1NameCodec_Encode(encoder, 0x1020, name); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + + if (!parcBuffer_Equals(truth, test)) { + printf("Buffers do not match\n"); + printf("Excpected:\n"); + parcBuffer_Display(truth, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + assertTrue(parcBuffer_Equals(truth, test), "Buffers do not match"); + } + + ccnxName_Release(&name); + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxTlvCodec_Name); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameSegmentCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameSegmentCodec.c new file mode 100755 index 00000000..77800055 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameSegmentCodec.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_NameSegmentCodec.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h> + +LONGBOW_TEST_RUNNER(ccnxTlvCodec_Name) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxTlvCodec_Name) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxTlvCodec_Name) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode_TLShort); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode_VShort); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecNameSegment_Encode); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("brandywine"); + CCNxNameSegment *truth = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer); + parcBuffer_Release(&buffer); + + uint8_t decodeBytes[] = { 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' }; + PARCBuffer *decodeBuffer = parcBuffer_Wrap(decodeBytes, sizeof(decodeBytes), 0, sizeof(decodeBytes)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(decodeBuffer); + CCNxNameSegment *test = ccnxCodecSchemaV1NameSegmentCodec_Decode(decoder); + + assertTrue(ccnxNameSegment_Equals(truth, test), "Name segments do not match"); + + ccnxNameSegment_Release(&test); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&decodeBuffer); + ccnxNameSegment_Release(&truth); +} + +/** + * In this case, there are not enough bytes in the buffer to decode the T and L + */ +LONGBOW_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode_TLShort) +{ + uint8_t decodeBytes[] = { 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a' }; + PARCBuffer *decodeBuffer = parcBuffer_Wrap(decodeBytes, sizeof(decodeBytes), 0, sizeof(decodeBytes)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(decodeBuffer); + CCNxNameSegment *test = ccnxCodecSchemaV1NameSegmentCodec_Decode(decoder); + + assertNull(test, "Name segments should have been null because there are not enough bytes in buffer"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&decodeBuffer); +} + +/** + * In this case, we decode the T and L, but there are not enough bytes for the V + */ +LONGBOW_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode_VShort) +{ + uint8_t decodeBytes[] = { 0x00, CCNxNameLabelType_NAME, 0x00 }; + PARCBuffer *decodeBuffer = parcBuffer_Wrap(decodeBytes, sizeof(decodeBytes), 0, sizeof(decodeBytes)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(decodeBuffer); + CCNxNameSegment *test = ccnxCodecSchemaV1NameSegmentCodec_Decode(decoder); + + assertNull(test, "Name segments should have been null because there are not enough bytes in buffer"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&decodeBuffer); +} + + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecNameSegment_Encode) +{ + uint8_t truthBytes[] = { 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' }; + PARCBuffer *truth = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(encoder); + + PARCBuffer *buffer = parcBuffer_WrapCString("brandywine"); + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer); + parcBuffer_Release(&buffer); + + ccnxCodecSchemaV1NameSegmentCodec_Encode(encoder, segment); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "Buffers do not match"); + + parcBuffer_Release(&test); + ccnxNameSegment_Release(&segment); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxTlvCodec_Name); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersDecoder.c new file mode 100644 index 00000000..abe47608 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersDecoder.c @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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. + */ + +/** + */ + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_OptionalHeadersDecoder.c" +#include <parc/algol/parc_SafeMemory.h> + +#include <inttypes.h> + +#include <LongBow/unit-test.h> + +typedef struct test_data { + PARCBuffer *optionalHeader; + CCNxCodecTlvDecoder *decoder; + CCNxTlvDictionary *dictionary; + + // truth table + PARCBuffer *interestLifetime; + PARCBuffer *cacheTime; + PARCBuffer *interestFrag; + PARCBuffer *objectFrag; + PARCBuffer *customHeader; + + // the key for the customHeader + uint16_t customHeaderType; +} TestData; + +/** + * A packet with all the defined optional headers plus one custom header + * This is not actually a packet one would see in real life as it has + * headers from both an Interest and a Content Object + */ +static uint8_t packet_with_headers[] = { + 0x01, 0x01, 0x00, 120, // ver = 1, type = interest, length = 120 + 0x01, 0x00, 0x00, 88, // hopLimit = 1, reserved = 0, header length = 88 + // ------------------------ + // byte 8 + 0x00, 0x01, 0x00, 0x08, // Interest Lifetime (type 1) + 0x20, 0x30, 0x40, 0x50, // 0x2030405060708090 + 0x60, 0x70, 0x80, 0x90, + // ------------------------ + // byte 20 + 0x00, 0x02, 0x00, 0x08, // Recommended Cache Time (type 2) + 0x21, 0x31, 0x41, 0x51, // 0x2030405060708090 + 0x61, 0x71, 0x81, 0x91, + // ------------------------ + // byte 32 + 0x00, 0x03, 0x00, 0x0C, // Interest Fragment (type 3) + 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, // fragment 0x0102030405060708 + 0x05, 0xDC, 0x04, 0x00, // MTU 1500, fragcnt 4, fragnum 0 + // ------------------------ + // byte 48 + 0x00, 0x04, 0x00, 20, // ContentObject Fragment (type 4) + 0xC1, 0xC2, 0xC3, 0xC4, + 0xC5, 0xC6, 0xC7, 0xC8, // fragment 0xC1C2C3C4C5C6C7C8 + 0x05, 0xDC, 0x04, 0x00, // MTU 1500, fragcnt 4, fragnum 0 + 0xD1, 0xD2, 0xD3, 0xD4, + 0xD5, 0xD6, 0xD7, 0xD8, // fragment 0xD1D2D3D4D5D6D7D8 + // ------------------------ + // byte 72 + 0x01, 0x00, 0x00, 12, // Custom header (type 256), length 12 + 0xA0, 0xA1, 0xA2, 0xA3, + 0xA4, 0xA5, 0xA6, 0xA7, + 0xA8, 0xA9, 0xAA, 0xAB, + // ------------------------ + // byte 88 + 0x00, 0x01, 0x00, 29, // type = interest, length = 29 + // ------------------------ + 0x00, 0x00, 0x00, 0x10, // type = name, length = 16 + 0x00, 0x02, 0x00, 0x04, // type = binary, length = 5 + 'h', 'e', 'l', 'l', // "hello" + 0xF0, 0x00, 0x00, 0x04, // type = app, length = 4 + 'o', 'u', 'c', 'h', // "ouch" + // ------------------------ + 0x00, 0x01, 0x00, 0x04, // type = keyid, length = 4 + 0xA0, 0xB0, 0xC0, 0xD0, // 0xA0B0C0D0 + // ------------------------ + // byte 120 +}; + +static TestData * +_commonSetup(void) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + // setup the decoder and decode the optional headers + data->optionalHeader = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 8, 88); + data->decoder = ccnxCodecTlvDecoder_Create(data->optionalHeader); + data->dictionary = ccnxTlvDictionary_Create(10, 5); + + // setup the truth values + data->interestLifetime = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 12, 20); + data->cacheTime = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 24, 32); + + data->interestFrag = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 36, 48); + data->objectFrag = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 52, 72); + + data->customHeader = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 76, 88); + data->customHeaderType = 0x0100; + + return data; +} + +static void +_commonTeardown(TestData *data) +{ + ccnxTlvDictionary_Release(&data->dictionary); + ccnxCodecTlvDecoder_Destroy(&data->decoder); + parcBuffer_Release(&data->optionalHeader); + + parcBuffer_Release(&data->interestLifetime); + parcBuffer_Release(&data->cacheTime); + parcBuffer_Release(&data->interestFrag); + parcBuffer_Release(&data->objectFrag); + parcBuffer_Release(&data->customHeader); + + parcMemory_Deallocate((void **) &data); +} + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_OptionalHeadersDecoder) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_OptionalHeadersDecoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_OptionalHeadersDecoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_Decode_TooLong); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomHeader); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader_Missing); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader_Missing); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader_Missing); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader_Missing); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomHeader_Missing); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + longBowTestCase_SetClipBoardData(testCase, _commonSetup()); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + _commonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +/** + * One of the TLVs will extend beyond the end of the buffer. Should fail. + */ +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_Decode_TooLong) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + // Make one of the fields 255 bytes + uint8_t original = packet_with_headers[10]; + packet_with_headers[10] = 0xFF; + bool success = ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary); + + // now set it back + packet_with_headers[10] = original; + + assertFalse(success, "Should have failed to parse when a TLV exceeds bounary"); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary); + PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader(data->dictionary); + assertTrue(parcBuffer_Equals(test, data->objectFrag), "Wrong value") + { + printf("Expected: \n"); + parcBuffer_Display(data->objectFrag, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary); + PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader(data->dictionary); + assertTrue(parcBuffer_Equals(test, data->interestFrag), "Wrong value") + { + printf("Expected: \n"); + parcBuffer_Display(data->interestFrag, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary); + uint64_t lifetime = ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader(data->dictionary); + + uint64_t trueLifetime = 0; + ccnxCodecTlvUtilities_GetVarInt(data->interestLifetime, parcBuffer_Remaining(data->interestLifetime), &trueLifetime); + + assertTrue(trueLifetime == lifetime, "wrong value, expected %" PRIx64 " got %" PRIx64, trueLifetime, lifetime); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary); + uint64_t cachetime = ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader(data->dictionary); + + uint64_t trueCachetime = 0; + ccnxCodecTlvUtilities_GetVarInt(data->cacheTime, parcBuffer_Remaining(data->cacheTime), &trueCachetime); + + assertTrue(trueCachetime == cachetime, "wrong value, expected %" PRIx64 " got %" PRIx64, trueCachetime, cachetime); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomHeader) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary); + PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomType(data->dictionary, data->customHeaderType); + assertTrue(parcBuffer_Equals(test, data->customHeader), "Wrong value for header type %02X", data->customHeaderType) + { + printf("Expected: \n"); + parcBuffer_Display(data->customHeader, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } +} + +// ======== +// test for missing values + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader(data->dictionary); + assertNull(test, "Did not get null buffer for missing field, got %p", (void *) test); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader(data->dictionary); + assertNull(test, "Did not get null buffer for missing field, got %p", (void *) test); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + bool exists = ccnxTlvDictionary_IsValueInteger(data->dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime); + assertFalse(exists, "Dictionary reports it has a missing field"); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + bool exists = ccnxTlvDictionary_IsValueInteger(data->dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime); + assertFalse(exists, "Dictionary reports it has a missing field"); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomHeader_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomType(data->dictionary, data->customHeaderType); + assertNull(test, "Did not get null buffer for missing field, got %p", (void *) test); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_OptionalHeadersDecoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersEncoder.c new file mode 100644 index 00000000..1950eef2 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersEncoder.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_OptionalHeadersEncoder.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include <ccnx/common/codec/schema_v1/testdata/v1_interest_nameA.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_crc32c.h> + +#include "testrig_encoder.c" + +static TruthTableEntry +TRUTHTABLENAME(interest_optional_headers)[] = +{ + { .wellKnownType = false, .indexOrKey = V1_MANIFEST_INT_OPTHEAD, .bodyManifest = true, .extent = { 8, 28 } }, // index = 0 + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_E2EFRAG, .bodyManifest = false, .extent = { 12, 12 } }, // index = 1 + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_LIFETIME, .bodyManifest = false, .extent = { 28, 8 } }, // index = 2 + { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } }, +}; + +static TruthTableEntry +TRUTHTABLENAME(contentobject_optional_headers)[] = +{ + { .wellKnownType = false, .indexOrKey = V1_MANIFEST_OBJ_OPTHEAD, .bodyManifest = true, .extent = { 8, 36 } }, // 0 + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_E2EFRAG, .bodyManifest = false, .extent = { 12, 20 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_RecommendedCacheTime, .bodyManifest = false, .extent = { 36, 8 } }, + { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } }, +}; + + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV0_OptionalHeadersEncoder) +{ + LONGBOW_RUN_TEST_FIXTURE(Interest); + LONGBOW_RUN_TEST_FIXTURE(ContentObject); + LONGBOW_RUN_TEST_FIXTURE(UnknownType); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV0_OptionalHeadersEncoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV0_OptionalHeadersEncoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ================================================================================== + +LONGBOW_TEST_FIXTURE(Interest) +{ + LONGBOW_RUN_TEST_CASE(Interest, ccnxCodecSchemaV1OptionalHeadersEncoder_Encode); +} + +LONGBOW_TEST_FIXTURE_SETUP(Interest) +{ + longBowTestCase_SetClipBoardData(testCase, + commonSetup(v1_interest_nameA, + sizeof(v1_interest_nameA), + TRUTHTABLENAME(interest_optional_headers), + V1_MANIFEST_INT_OPTHEAD)); + + // commonSetup will not add headers... + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + addBuffer(data, data->dictionary, TRUTHTABLENAME(interest_optional_headers)[1].extent.offset, TRUTHTABLENAME(interest_optional_headers)[1].extent.offset + TRUTHTABLENAME(interest_optional_headers)[1].extent.length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG); + + addBuffer(data, data->dictionary, TRUTHTABLENAME(interest_optional_headers)[2].extent.offset, TRUTHTABLENAME(interest_optional_headers)[2].extent.offset + TRUTHTABLENAME(interest_optional_headers)[2].extent.length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Interest) +{ + testrigencoder_CommonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Interest, ccnxCodecSchemaV1OptionalHeadersEncoder_Encode) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ssize_t length = ccnxCodecSchemaV1OptionalHeadersEncoder_Encode(data->encoder, data->dictionary); + assertTrue(length >= 0, "Error on Encode: length %zd", length); + testCompareEncoderToBuffer(data->encoder, data->memoryRegion); +} + +// ================================================================================== + +LONGBOW_TEST_FIXTURE(ContentObject) +{ + LONGBOW_RUN_TEST_CASE(ContentObject, ccnxCodecSchemaV1OptionalHeadersEncoder_Encode); +} + +LONGBOW_TEST_FIXTURE_SETUP(ContentObject) +{ + longBowTestCase_SetClipBoardData(testCase, + commonSetup(v1_content_nameA_crc32c, + sizeof(v1_content_nameA_crc32c), + TRUTHTABLENAME(contentobject_optional_headers), + V1_MANIFEST_OBJ_OPTHEAD)); + + // commonSetup will not add headers... + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + addBuffer(data, data->dictionary, TRUTHTABLENAME(contentobject_optional_headers)[1].extent.offset, TRUTHTABLENAME(contentobject_optional_headers)[1].extent.offset + TRUTHTABLENAME(contentobject_optional_headers)[1].extent.length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG); + + addBuffer(data, data->dictionary, TRUTHTABLENAME(contentobject_optional_headers)[2].extent.offset, TRUTHTABLENAME(contentobject_optional_headers)[2].extent.offset + TRUTHTABLENAME(contentobject_optional_headers)[2].extent.length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime); + + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(ContentObject) +{ + testrigencoder_CommonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(ContentObject, ccnxCodecSchemaV1OptionalHeadersEncoder_Encode) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ssize_t length = ccnxCodecSchemaV1OptionalHeadersEncoder_Encode(data->encoder, data->dictionary); + assertTrue(length >= 0, "Error on Encode: length %zd", length); + testCompareEncoderToBuffer(data->encoder, data->memoryRegion); +} + +// ================================================================================== + +LONGBOW_TEST_FIXTURE(UnknownType) +{ + LONGBOW_RUN_TEST_CASE(UnknownType, Unknown); +} + +LONGBOW_TEST_FIXTURE_SETUP(UnknownType) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(UnknownType) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(UnknownType, Unknown) +{ + CCNxTlvDictionary *unknown = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, 1); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1OptionalHeadersEncoder_Encode(encoder, unknown); + assertTrue(length < 0, "Did not get error return when encoding unknown type"); + + CCNxCodecError *error = ccnxCodecTlvEncoder_GetError(encoder); + assertNotNull(error, "encoder did not set the error"); + + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&unknown); +} + +// ================================================================================== + + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV0_OptionalHeadersEncoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketDecoder.c new file mode 100755 index 00000000..42d5be41 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketDecoder.c @@ -0,0 +1,684 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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. + */ + +/** + * Decode whole packets then spot-check that fields from each section appear. We don't need + * to exhastively test here, as the individual decoders are exhaustively tested. + * + */ +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_PacketDecoder.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_content_zero_payload.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_content_no_payload.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_crc32c.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_interest_bad_message_length.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_interest_bad_validation_alg.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_interest_validation_alg_overrun.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route_crc32c.h> + +#include "testrig_packetwrapper.c" + +#include <ccnx/common/internal/ccnx_ContentObjectFacadeV1.h> +#include <ccnx/common/internal/ccnx_ValidationFacadeV1.h> + +// ========================================================================= + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_PacketDecoder) +{ + LONGBOW_RUN_TEST_FIXTURE(ContentObject); + LONGBOW_RUN_TEST_FIXTURE(Control); + LONGBOW_RUN_TEST_FIXTURE(Interest); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_PacketDecoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_PacketDecoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(ContentObject) +{ + LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_RsaSha256_FixedHeader); + LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_RsaSha256_Name); + LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_RsaSha256_ExpiryTime); + LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_RsaSha256_ValidationAlg_KeyId); + LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_RsaSha256_ValidationPayload); + LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_zero_payload); + LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_no_payload); +} + +LONGBOW_TEST_FIXTURE_SETUP(ContentObject) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(ContentObject) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(ContentObject, ContentObject_RsaSha256_FixedHeader) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), 0, sizeof(v1_content_nameA_keyid1_rsasha256)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader); + + // leave the FixedHeader buffer at position 0 + parcBuffer_Rewind(fixedHeader); + + PARCBuffer *trueFixedHeader = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, 8, 0, 8); + assertTrue(parcBuffer_Equals(fixedHeader, trueFixedHeader), "Buffers not equal") + { + printf("Expected\n"); + parcBuffer_Display(trueFixedHeader, 3); + printf("Got\n"); + parcBuffer_Display(fixedHeader, 3); + } + + parcBuffer_Release(&trueFixedHeader); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(ContentObject, ContentObject_RsaSha256_Name) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, + sizeof(v1_content_nameA_keyid1_rsasha256), + 0, + sizeof(v1_content_nameA_keyid1_rsasha256)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + CCNxName *name = ccnxTlvDictionary_GetName(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME); + CCNxName *trueName = ccnxName_CreateFromCString(v1_content_nameA_keyid1_rsasha256_URI); + + assertTrue(ccnxName_Equals(name, trueName), "Buffers not equal") + { + printf("Expected\n"); + ccnxName_Display(trueName, 3); + printf("Got\n"); + ccnxName_Display(name, 3); + } + + ccnxName_Release(&trueName); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(ContentObject, ContentObject_RsaSha256_ExpiryTime) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), 0, sizeof(v1_content_nameA_keyid1_rsasha256)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + uint64_t expiryTime = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME); + + TlvExtent expiryExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_EXPIRY_TIME); + + parcBuffer_SetPosition(packetBuffer, expiryExtent.offset); + uint64_t trueTime; + ccnxCodecTlvUtilities_GetVarInt(packetBuffer, expiryExtent.length, &trueTime); + + assertTrue(expiryTime == trueTime, "Wrong time, expected %" PRIx64 " got %" PRIx64, trueTime, expiryTime); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(ContentObject, ContentObject_RsaSha256_ValidationAlg_KeyId) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), 0, sizeof(v1_content_nameA_keyid1_rsasha256)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *keyid = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID); + + TlvExtent keyidExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_KEYID); + PARCBuffer *trueKeyid = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), keyidExtent.offset, keyidExtent.offset + keyidExtent.length); + + assertTrue(parcBuffer_Equals(keyid, trueKeyid), "Buffers not equal") + { + printf("Expected\n"); + parcBuffer_Display(trueKeyid, 3); + printf("Got\n"); + parcBuffer_Display(keyid, 3); + } + + parcBuffer_Release(&trueKeyid); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(ContentObject, ContentObject_RsaSha256_ValidationPayload) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), 0, sizeof(v1_content_nameA_keyid1_rsasha256)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *validationPayload = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD); + + TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_SIGBITS); + PARCBuffer *truePayload = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), payloadExtent.offset, payloadExtent.offset + payloadExtent.length); + + assertTrue(parcBuffer_Equals(validationPayload, truePayload), "Buffers not equal") + { + printf("Expected\n"); + parcBuffer_Display(truePayload, 3); + printf("Got\n"); + parcBuffer_Display(validationPayload, 3); + } + + parcBuffer_Release(&truePayload); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(ContentObject, ContentObject_zero_payload) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_zero_payload, sizeof(v1_content_zero_payload), 0, sizeof(v1_content_zero_payload)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + CCNxName *testName = CCNxContentObjectFacadeV1_Implementation.getName(dictionary); + assertNotNull(testName, "Got null name on decode"); + + PARCBuffer *testPayload = CCNxContentObjectFacadeV1_Implementation.getPayload(dictionary); + assertNotNull(testPayload, "got null payload") + assertTrue(parcBuffer_Remaining(testPayload) == 0, "Wrong length, expected 0 got %zu", parcBuffer_Remaining(testPayload)); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(ContentObject, ContentObject_no_payload) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_no_payload, sizeof(v1_content_no_payload), 0, sizeof(v1_content_no_payload)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + CCNxName *test = CCNxContentObjectFacadeV1_Implementation.getName(dictionary); + assertNotNull(test, "Got null name on decode"); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Control) +{ + LONGBOW_RUN_TEST_CASE(Control, CPIAddRoute_Crc32c_FixedHeader); + LONGBOW_RUN_TEST_CASE(Control, CPIAddRoute_Crc32c_Payload); + LONGBOW_RUN_TEST_CASE(Control, CPIAddRoute_Crc32c_ValidationAlg_CryptoSuite); + LONGBOW_RUN_TEST_CASE(Control, CPIAddRoute_Crc32c_ValidationPayload); +} + +LONGBOW_TEST_FIXTURE_SETUP(Control) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Control) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Control, CPIAddRoute_Crc32c_FixedHeader) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), 0, sizeof(v1_cpi_add_route_crc32c)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader); + + // leave the FixedHeader buffer at position 0 + parcBuffer_Rewind(fixedHeader); + + PARCBuffer *trueFixedHeader = parcBuffer_Wrap(v1_cpi_add_route_crc32c, 8, 0, 8); + assertTrue(parcBuffer_Equals(fixedHeader, trueFixedHeader), "Buffers not equal") + { + printf("Expected\n"); + parcBuffer_Display(trueFixedHeader, 3); + printf("Got\n"); + parcBuffer_Display(fixedHeader, 3); + } + + parcBuffer_Release(&trueFixedHeader); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(Control, CPIAddRoute_Crc32c_Payload) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), 0, sizeof(v1_cpi_add_route_crc32c)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD); + + TlvExtent validationPayloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_cpi_add_route_crc32c), V1_MANIFEST_CPI_SIGBITS); + PARCBuffer *trueValidationPayload = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), validationPayloadExtent.offset, validationPayloadExtent.offset + validationPayloadExtent.length); + + assertTrue(parcBuffer_Equals(test, trueValidationPayload), "Buffers not equal") + { + printf("Expected\n"); + parcBuffer_Display(trueValidationPayload, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&trueValidationPayload); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(Control, CPIAddRoute_Crc32c_ValidationAlg_CryptoSuite) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), 0, sizeof(v1_cpi_add_route_crc32c)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCCryptoSuite test = (PARCCryptoSuite) ccnxValidationFacadeV1_GetCryptoSuite(dictionary); + PARCCryptoSuite trueCryptoSuite = PARCCryptoSuite_NULL_CRC32C; + + assertTrue(test == trueCryptoSuite, "Wrong crypto suite, expected %d got %d", trueCryptoSuite, test); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(Control, CPIAddRoute_Crc32c_ValidationPayload) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), 0, sizeof(v1_cpi_add_route_crc32c)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *validationPayload = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD); + + TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_cpi_add_route_crc32c), V1_MANIFEST_CPI_SIGBITS); + PARCBuffer *truePayload = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), payloadExtent.offset, payloadExtent.offset + payloadExtent.length); + + assertTrue(parcBuffer_Equals(validationPayload, truePayload), "Buffers not equal") + { + printf("Expected\n"); + parcBuffer_Display(truePayload, 3); + printf("Got\n"); + parcBuffer_Display(validationPayload, 3); + } + + parcBuffer_Release(&truePayload); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Interest) +{ + LONGBOW_RUN_TEST_CASE(Interest, interest_bad_message_length); + LONGBOW_RUN_TEST_CASE(Interest, interest_all_fields_FixedHeader); + LONGBOW_RUN_TEST_CASE(Interest, interest_all_fields_Lifetime); + LONGBOW_RUN_TEST_CASE(Interest, interest_all_fields_Name); + LONGBOW_RUN_TEST_CASE(Interest, interest_all_fields_ValidationAlg_KeyId); + LONGBOW_RUN_TEST_CASE(Interest, interest_all_fields_ValidationPayload); + LONGBOW_RUN_TEST_CASE(Interest, interest_nameA_crc32c_ValidationAlg_CryptoSuite); + LONGBOW_RUN_TEST_CASE(Interest, interest_nameA_crc32c_ValidationPayload); + LONGBOW_RUN_TEST_CASE(Interest, ccnxCodecSchemaV1PacketDecoder_BufferDecode); + LONGBOW_RUN_TEST_CASE(Interest, interest_bad_validation_alg); + LONGBOW_RUN_TEST_CASE(Interest, interest_validation_alg_overrun); +} + +LONGBOW_TEST_FIXTURE_SETUP(Interest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Interest) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Interest, interest_bad_message_length) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_bad_message_length, sizeof(v1_interest_bad_message_length), 0, sizeof(v1_interest_bad_message_length)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertFalse(success, "Should have seen and error on decode"); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNotNull(error, "Error not set when bad decode"); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(Interest, interest_all_fields_FixedHeader) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader); + + // leave the FixedHeader buffer at position 0 + parcBuffer_Rewind(fixedHeader); + + PARCBuffer *trueFixedHeader = parcBuffer_Wrap(v1_interest_all_fields, 8, 0, 8); + assertTrue(parcBuffer_Equals(fixedHeader, trueFixedHeader), "Buffers not equal") + { + printf("Expected\n"); + parcBuffer_Display(trueFixedHeader, 3); + printf("Got\n"); + parcBuffer_Display(fixedHeader, 3); + } + + parcBuffer_Release(&trueFixedHeader); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(Interest, interest_all_fields_Lifetime) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + uint64_t lifetime = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime); + + TlvExtent lifetimeExtent = getTruthTableHeaderExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_LIFETIME); + + parcBuffer_SetPosition(packetBuffer, lifetimeExtent.offset); + uint64_t trueTime; + ccnxCodecTlvUtilities_GetVarInt(packetBuffer, lifetimeExtent.length, &trueTime); + + assertTrue(lifetime == trueTime, "Wrong time, expected %" PRIx64 " got %" PRIx64, trueTime, lifetime); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(Interest, interest_all_fields_Name) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + CCNxName *name = ccnxTlvDictionary_GetName(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME); + CCNxName *trueName = ccnxName_CreateFromCString(v1_interest_all_fields_URI); + + assertTrue(ccnxName_Equals(name, trueName), "Buffers not equal") + { + printf("Expected\n"); + ccnxName_Display(trueName, 3); + printf("Got\n"); + ccnxName_Display(name, 3); + } + + ccnxName_Release(&trueName); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +/* + * This packet does not have a validation section, so the test is that its missing + */ +LONGBOW_TEST_CASE(Interest, interest_all_fields_ValidationAlg_KeyId) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *keyid = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID); + assertNull(keyid, "Got a non-null keyid from a packet without one"); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +/* + * Packet does not have validation, test for missing + */ +LONGBOW_TEST_CASE(Interest, interest_all_fields_ValidationPayload) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *payload = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD); + assertNull(payload, "Got a non-null validation payload from a packet without one"); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(Interest, interest_nameA_crc32c_ValidationAlg_CryptoSuite) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), 0, sizeof(v1_interest_nameA_crc32c)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCCryptoSuite suite = (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE); + PARCCryptoSuite trueSuite = PARCCryptoSuite_NULL_CRC32C; + + assertTrue(suite == trueSuite, "Wrong crypto suite, expected %d got %d", trueSuite, suite); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(Interest, interest_nameA_crc32c_ValidationPayload) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), 0, sizeof(v1_interest_nameA_crc32c)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *validationPayload = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD); + + TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_ValidationPayload); + PARCBuffer *truePayload = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), payloadExtent.offset, payloadExtent.offset + payloadExtent.length); + + assertTrue(parcBuffer_Equals(validationPayload, truePayload), "Buffers not equal") + { + printf("Expected\n"); + parcBuffer_Display(truePayload, 3); + printf("Got\n"); + parcBuffer_Display(validationPayload, 3); + } + + parcBuffer_Release(&truePayload); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(Interest, ccnxCodecSchemaV1PacketDecoder_BufferDecode) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), 0, sizeof(v1_interest_nameA_crc32c)); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecSchemaV1PacketDecoder_BufferDecode(packetBuffer, dictionary); + assertTrue(success, "Error on decode"); + + PARCBuffer *validationPayload = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD); + + TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_ValidationPayload); + PARCBuffer *truePayload = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), payloadExtent.offset, payloadExtent.offset + payloadExtent.length); + + assertTrue(parcBuffer_Equals(validationPayload, truePayload), "Buffers not equal") + { + printf("Expected\n"); + parcBuffer_Display(truePayload, 3); + printf("Got\n"); + parcBuffer_Display(validationPayload, 3); + } + + parcBuffer_Release(&truePayload); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Interest, interest_bad_validation_alg) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_bad_validation_alg, sizeof(v1_interest_bad_validation_alg), 0, sizeof(v1_interest_bad_validation_alg)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertFalse(success, "Should have seen and error on decode"); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNotNull(error, "Error not set when bad decode"); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(Interest, interest_validation_alg_overrun) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_validation_alg_overrun, sizeof(v1_interest_validation_alg_overrun), 0, sizeof(v1_interest_validation_alg_overrun)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertFalse(success, "Should have seen and error on decode"); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNotNull(error, "Error not set when bad decode"); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +// ========================================================================= + + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_PacketDecoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketEncoder.c new file mode 100755 index 00000000..eb79502e --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketEncoder.c @@ -0,0 +1,1054 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_PacketEncoder.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_crc32c.h> + +#include "testrig_encoder.c" + +#include <ccnx/common/ccnx_Interest.h> +#include <ccnx/common/ccnx_InterestReturn.h> +#include <ccnx/common/ccnx_ContentObject.h> + +#include <ccnx/common/validation/ccnxValidation_CRC32C.h> + + +// ========================================================================= + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_PacketEncoder) +{ + LONGBOW_RUN_TEST_FIXTURE(ContentObject); + LONGBOW_RUN_TEST_FIXTURE(Interest); + LONGBOW_RUN_TEST_FIXTURE(InterestReturn); + LONGBOW_RUN_TEST_FIXTURE(Control); + LONGBOW_RUN_TEST_FIXTURE(UnknownType); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_PacketEncoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_PacketEncoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(ContentObject) +{ + LONGBOW_RUN_TEST_CASE(ContentObject, v1_content_nameA_keyid1_rsasha256); + LONGBOW_RUN_TEST_CASE(ContentObject, zero_length_payload); + LONGBOW_RUN_TEST_CASE(ContentObject, null_payload); + LONGBOW_RUN_TEST_CASE(ContentObject, no_cryptosuite); +} + +LONGBOW_TEST_FIXTURE_SETUP(ContentObject) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(ContentObject) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +/* + * Make a dictionary equivalent to v1_content_nameA_keyid1_rsasha256 and encode it then compare + */ +LONGBOW_TEST_CASE(ContentObject, v1_content_nameA_keyid1_rsasha256) +{ + CCNxName *name = ccnxName_CreateFromCString(v1_content_nameA_keyid1_rsasha256_URI); + + TlvExtent payloadExtent = + getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_PAYLOAD); + PARCBuffer *payload = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, + sizeof(v1_content_nameA_keyid1_rsasha256), + payloadExtent.offset, + payloadExtent.offset + payloadExtent.length); + + CCNxTlvDictionary *message = + ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation, + name, CCNxPayloadType_KEY, payload); + + TlvExtent fragmentExtent = + getTruthTableHeaderExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_E2EFRAG); + PARCBuffer *fragment = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, + sizeof(v1_content_nameA_keyid1_rsasha256), + fragmentExtent.offset, + fragmentExtent.offset + fragmentExtent.length); + ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG, fragment); + + uint64_t expiryTime = 1388534400000ULL; + ccnxContentObject_SetExpiryTime(message, expiryTime); + + uint64_t endChunkNumber = 0x06050403; + ccnxContentObject_SetFinalChunkNumber(message, endChunkNumber); + + TlvExtent keyIdExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_KEYID); + PARCBuffer *keyid = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, + sizeof(v1_content_nameA_keyid1_rsasha256), + keyIdExtent.offset, + keyIdExtent.offset + keyIdExtent.length); + + TlvExtent keyExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_PUBKEY); + PARCBuffer *key = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, + sizeof(v1_content_nameA_keyid1_rsasha256), + keyExtent.offset, + keyExtent.offset + keyExtent.length); + + ccnxValidationFacadeV1_SetCryptoSuite(message, PARCCryptoSuite_RSA_SHA256); + ccnxValidationFacadeV1_SetKeyId(message, keyid); + ccnxValidationFacadeV1_SetPublicKey(message, key); + + TlvExtent sigExtent = + getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_SIGBITS); + PARCBuffer *sig = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, + sizeof(v1_content_nameA_keyid1_rsasha256), + sigExtent.offset, + sigExtent.offset + sigExtent.length); + + ccnxValidationFacadeV1_SetPayload(message, sig); + + // encode + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message); + assertFalse(length < 0, "Got encoding error: %s", + ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + assertTrue(length == sizeof(v1_content_nameA_keyid1_rsasha256), + "Wrong length, expected %zu got %zd", sizeof(v1_content_nameA_keyid1_rsasha256), length); + + // verify + PARCBuffer *truth = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, + sizeof(v1_content_nameA_keyid1_rsasha256), + 0, + sizeof(v1_content_nameA_keyid1_rsasha256)); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + + uint8_t *truthOverlay = parcBuffer_Overlay(truth, 0); + uint8_t *testOverlay = parcBuffer_Overlay(test, 0); + + for (ssize_t i = 0; i < length; i++) { + if (truthOverlay[i] != testOverlay[i]) { + printf("Buffers differ at byte %zd, expected 0x%02x got 0x%02x\n", i, truthOverlay[i], testOverlay[i]); + break; + } + } + } + + // cleanup + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&sig); + parcBuffer_Release(&key); + parcBuffer_Release(&keyid); + parcBuffer_Release(&payload); + parcBuffer_Release(&fragment); + ccnxName_Release(&name); + ccnxTlvDictionary_Release(&message); +} + + +LONGBOW_TEST_CASE(ContentObject, zero_length_payload) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/no/payload"); + PARCBuffer *payload = parcBuffer_Allocate(0); + + CCNxTlvDictionary *message = + ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation, + name, CCNxPayloadType_DATA, payload); + + // encode + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message); + assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertNotNull(encoded, "got null output buffer"); + + parcBuffer_Display(encoded, 3); + + parcBuffer_Release(&encoded); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&message); + parcBuffer_Release(&payload); + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(ContentObject, null_payload) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/no/payload"); + + CCNxTlvDictionary *message = + ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation, + name, CCNxPayloadType_DATA, NULL); + // encode + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message); + assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertNotNull(encoded, "got null output buffer"); + + parcBuffer_Release(&encoded); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&message); + ccnxName_Release(&name); +} + +/* + * A content object without a cryptosuite should not be signed + */ +LONGBOW_TEST_CASE(ContentObject, no_cryptosuite) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/no/payload"); + + CCNxTlvDictionary *message = + ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation, + name, CCNxPayloadType_DATA, NULL); + // encode + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message); + assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertNotNull(encoded, "got null output buffer"); + + // it should be 33 bytes without a signature + assertTrue(parcBuffer_Remaining(encoded) == 33, "Wrong length exepcted 33 got %zu", parcBuffer_Remaining(encoded)); + + parcBuffer_Release(&encoded); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&message); + ccnxName_Release(&name); +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Interest) +{ + LONGBOW_RUN_TEST_CASE(Interest, v1_interest_nameA_crc32c); + LONGBOW_RUN_TEST_CASE(Interest, v1_interest_nameA_crc32c_IoVec); +} + +LONGBOW_TEST_FIXTURE_SETUP(Interest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Interest) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +/* + * Make an interest equivalent to v1_interest_nameA_crc32c and encode it + */ +LONGBOW_TEST_CASE(Interest, v1_interest_nameA_crc32c) +{ + CCNxName *name = ccnxName_CreateFromCString(v1_interest_nameA_crc32c_URI); + + CCNxTlvDictionary *message = + ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation, + name, CCNxInterestDefault_LifetimeMilliseconds, NULL, NULL, 32); + + TlvExtent fragmentExtent = getTruthTableHeaderExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_E2EFRAG); + PARCBuffer *fragment = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), fragmentExtent.offset, fragmentExtent.offset + fragmentExtent.length); + ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG, fragment); + + ccnxValidationFacadeV1_SetCryptoSuite(message, PARCCryptoSuite_NULL_CRC32C); + + TlvExtent sigExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_ValidationPayload); + PARCBuffer *sig = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), sigExtent.offset, sigExtent.offset + sigExtent.length); + + ccnxValidationFacadeV1_SetPayload(message, sig); + + // encode + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message); + assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + assertTrue(length == sizeof(v1_interest_nameA_crc32c), "Wrong length, expected %zu got %zd", sizeof(v1_interest_nameA_crc32c), length); + + // verify + PARCBuffer *truth = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), 0, sizeof(v1_interest_nameA_crc32c)); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + + uint8_t *truthOverlay = parcBuffer_Overlay(truth, 0); + uint8_t *testOverlay = parcBuffer_Overlay(test, 0); + + for (ssize_t i = 0; i < length; i++) { + if (truthOverlay[i] != testOverlay[i]) { + printf("Buffers differ at byte %zd, expected 0x%02x got 0x%02x", i, truthOverlay[i], testOverlay[i]); + break; + } + } + } + + // cleanup + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&sig); + parcBuffer_Release(&fragment); + ccnxName_Release(&name); + ccnxTlvDictionary_Release(&message); +} + +/* + * Make an interest equivalent to v1_interest_nameA_crc32c and encode it + */ +LONGBOW_TEST_CASE(Interest, v1_interest_nameA_crc32c_IoVec) +{ + CCNxName *name = ccnxName_CreateFromCString(v1_interest_nameA_crc32c_URI); + + CCNxTlvDictionary *message = + ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation, + name, CCNxInterestDefault_LifetimeMilliseconds, NULL, NULL, 32); + + TlvExtent fragmentExtent = getTruthTableHeaderExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_E2EFRAG); + PARCBuffer *fragment = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), fragmentExtent.offset, fragmentExtent.offset + fragmentExtent.length); + ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG, fragment); + + ccnxValidationFacadeV1_SetCryptoSuite(message, PARCCryptoSuite_NULL_CRC32C); + + TlvExtent sigExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_ValidationPayload); + PARCBuffer *sig = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), sigExtent.offset, sigExtent.offset + sigExtent.length); + + ccnxValidationFacadeV1_SetPayload(message, sig); + + // encode + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecSchemaV1PacketEncoder_DictionaryEncode(message, NULL); + assertNotNull(iovec, "Got null iovec from ccnxCodecSchemaV1PacketEncoder_DictionaryEncode"); + + size_t length = ccnxCodecNetworkBufferIoVec_Length(iovec); + assertTrue(length == sizeof(v1_interest_nameA_crc32c), "Wrong length, expected %zu got %zd", sizeof(v1_interest_nameA_crc32c), length); + + // verify + PARCBuffer *truth = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), 0, sizeof(v1_interest_nameA_crc32c)); + + int iovecCount = ccnxCodecNetworkBufferIoVec_GetCount(iovec); + PARCBuffer *test = parcBuffer_Allocate(length); + const struct iovec *array = ccnxCodecNetworkBufferIoVec_GetArray(iovec); + for (int i = 0; i < iovecCount; i++) { + parcBuffer_PutArray(test, array[i].iov_len, array[i].iov_base); + } + parcBuffer_Flip(test); + + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + + uint8_t *truthOverlay = parcBuffer_Overlay(truth, 0); + uint8_t *testOverlay = parcBuffer_Overlay(test, 0); + + for (ssize_t i = 0; i < length; i++) { + if (truthOverlay[i] != testOverlay[i]) { + printf("Buffers differ at byte %zd, expected 0x%02x got 0x%02x", i, truthOverlay[i], testOverlay[i]); + break; + } + } + } + + // cleanup + ccnxCodecNetworkBufferIoVec_Release(&iovec); + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&sig); + parcBuffer_Release(&fragment); + ccnxName_Release(&name); + ccnxTlvDictionary_Release(&message); +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(InterestReturn) +{ + LONGBOW_RUN_TEST_CASE(InterestReturn, v1_interest_return); +} + +LONGBOW_TEST_FIXTURE_SETUP(InterestReturn) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(InterestReturn) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +/* + * Make an interest return and encode it + */ +LONGBOW_TEST_CASE(InterestReturn, v1_interest_return) +{ + CCNxName *name = ccnxName_CreateFromCString(v1_interest_nameA_crc32c_URI); + + CCNxInterest *interest = + ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation, + name, CCNxInterestDefault_LifetimeMilliseconds, NULL, NULL, 32); + ccnxName_Release(&name); + + TlvExtent fragmentExtent = getTruthTableHeaderExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_E2EFRAG); + PARCBuffer *fragment = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), fragmentExtent.offset, fragmentExtent.offset + fragmentExtent.length); + ccnxTlvDictionary_PutBuffer(interest, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG, fragment); + parcBuffer_Release(&fragment); + + ccnxValidationFacadeV1_SetCryptoSuite(interest, PARCCryptoSuite_NULL_CRC32C); + + TlvExtent sigExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_ValidationPayload); + PARCBuffer *sig = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), sigExtent.offset, sigExtent.offset + sigExtent.length); + + ccnxValidationFacadeV1_SetPayload(interest, sig); + parcBuffer_Release(&sig); + + CCNxTlvDictionary *message = + ccnxInterestReturn_Create(interest, CCNxInterestReturn_ReturnCode_NoResources); + ccnxInterest_Release(&interest); + + // encode + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message); + ssize_t expectedLength = sizeof(v1_interest_nameA_crc32c); + assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + assertTrue(length == expectedLength, "Wrong length, expected %zu got %zd", expectedLength, length); + + // verify + PARCBuffer *truth = parcBuffer_Wrap(v1_interest_nameA_crc32c_returned, sizeof(v1_interest_nameA_crc32c_returned), 0, sizeof(v1_interest_nameA_crc32c_returned)); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + + uint8_t *truthOverlay = parcBuffer_Overlay(truth, 0); + uint8_t *testOverlay = parcBuffer_Overlay(test, 0); + + for (ssize_t i = 0; i < length; i++) { + if (truthOverlay[i] != testOverlay[i]) { + printf("Buffers differ at byte %zd, expected 0x%02x got 0x%02x\n", i, truthOverlay[i], testOverlay[i]); + } + } + } + + // cleanup + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&message); +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Control) +{ + LONGBOW_RUN_TEST_CASE(Control, payload); + LONGBOW_RUN_TEST_CASE(Control, cryptosuite); +} + +LONGBOW_TEST_FIXTURE_SETUP(Control) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Control) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Control, payload) +{ + uint8_t encoded[] = { + 0x01, 0xa4, 0x00, 0x22, + 0x00, 0x00, 0x00, 0x08, + + 0xbe, 0xef, 0x00, 0x16, // control message + + 0x7b, 0x22, 0x74, 0x68, // {"th + 0x69, 0x73, 0x20, 0x69, // is i + 0x73, 0x22, 0x3a, 0x22, // s":" + 0x61, 0x6e, 0x6e, 0x6f, // anno + 0x79, 0x69, 0x6e, 0x67, // ying + 0x22, 0x7d // "} + }; + + + CCNxTlvDictionary *message = ccnxCodecSchemaV1TlvDictionary_CreateControl(); + + PARCJSON *json = parcJSON_Create(); + parcJSON_AddString(json, "this is", "annoying"); + + ccnxTlvDictionary_PutJson(message, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, json); + parcJSON_Release(&json); + + // encode + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message); + + assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length); + + // verify + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + + uint8_t *truthOverlay = parcBuffer_Overlay(truth, 0); + uint8_t *testOverlay = parcBuffer_Overlay(test, 0); + + for (ssize_t i = 0; i < length; i++) { + if (truthOverlay[i] != testOverlay[i]) { + printf("Buffers differ at byte %zd, expected 0x%02x got 0x%02x", i, truthOverlay[i], testOverlay[i]); + break; + } + } + } + + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&message); + parcBuffer_Release(&truth); +} + +LONGBOW_TEST_CASE(Control, cryptosuite) +{ + uint8_t encoded[] = { + 0x01, 0xA4, 0x00, 16, + 0x00, 0x00, 0x00, 8, + 0xBE, 0xEF, 0x00, 4, + 'a', 'b', 'c', 'd', + 0x00, 0x03, 0x00, 4, + 0x00, 0x02, 0x00, 0 + }; + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + PARCBuffer *payload = parcBuffer_Wrap(encoded, sizeof(encoded), 12, 16); + + CCNxTlvDictionary *message = ccnxCodecSchemaV1TlvDictionary_CreateControl(); + ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, payload); + ccnxValidationCRC32C_Set(message); + + ccnxValidationCRC32C_Set(message); + + // encode + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + PARCSigner *signer = ccnxValidationCRC32C_CreateSigner(); + ccnxCodecTlvEncoder_SetSigner(encoder, signer); + + ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message); + assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertNotNull(test, "Got null buffer from encoder"); + uint8_t testSuite = parcBuffer_GetAtIndex(test, 21); + assertTrue(testSuite == 2, "Wrong cryptosuite, expected 2 got %u", testSuite); + + parcSigner_Release(&signer); + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&message); + parcBuffer_Release(&payload); + parcBuffer_Release(&truth); +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(UnknownType) +{ + LONGBOW_RUN_TEST_CASE(UnknownType, unknown); +} + +LONGBOW_TEST_FIXTURE_SETUP(UnknownType) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(UnknownType) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +/* + * try to encode a message with unknown message type + */ +LONGBOW_TEST_CASE(UnknownType, unknown) +{ + // this initializes the dictionary to unknown type + CCNxTlvDictionary *message = ccnxTlvDictionary_Create(20, 20); + + // encode + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message); + assertTrue(length < 0, "Did not get error condition for unknown type"); + + CCNxCodecError *error = ccnxCodecTlvEncoder_GetError(encoder); + assertNotNull(error, "Did not get an error for invalid encoding"); + + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&message); +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, _getHopLimit_Present); + LONGBOW_RUN_TEST_CASE(Local, _getHopLimit_Missing); + LONGBOW_RUN_TEST_CASE(Local, _encodeFixedHeader_ContentObject); + LONGBOW_RUN_TEST_CASE(Local, _encodeFixedHeader_Interest); + LONGBOW_RUN_TEST_CASE(Local, _encodeOptionalHeaders); + LONGBOW_RUN_TEST_CASE(Local, _encodeMessage_Interest); + LONGBOW_RUN_TEST_CASE(Local, _encodeMessage_ContentObject); + LONGBOW_RUN_TEST_CASE(Local, _encodeCPI); + LONGBOW_RUN_TEST_CASE(Local, _encodeMessage_Unknown); + LONGBOW_RUN_TEST_CASE(Local, _encodeValidationAlg_Present); + LONGBOW_RUN_TEST_CASE(Local, _encodeValidationAlg_Missing); + LONGBOW_RUN_TEST_CASE(Local, _encodeValidationPayload_Present); + LONGBOW_RUN_TEST_CASE(Local, _encodeValidationPayload_Missing); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, _getHopLimit_Present) +{ + uint8_t hoplimit = 77; + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + ccnxTlvDictionary_PutInteger(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT, hoplimit); + + uint8_t test = _getHopLimit(dict); + assertTrue(test == hoplimit, "Got wrong hoplimit, expected %u got %u", hoplimit, test); + ccnxTlvDictionary_Release(&dict); +} + +LONGBOW_TEST_CASE(Local, _getHopLimit_Missing) +{ + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + uint8_t test = _getHopLimit(dict); + assertTrue(test == CCNxInterestDefault_HopLimit, "Got wrong hoplimit, expected %u got %u", CCNxInterestDefault_HopLimit, test); + ccnxTlvDictionary_Release(&dict); +} + +LONGBOW_TEST_CASE(Local, _encodeFixedHeader_ContentObject) +{ + uint8_t encoded[] = { + 0x01, 0x01, 0x00, 100, // ver = 1, type = content object, length = 100 + 0x00, 0x00, 0x00, 14, // reserved = 0x0000000, header length = 14 + }; + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = _encodeFixedHeader(encoder, dict, CCNxCodecSchemaV1Types_PacketType_ContentObject, 14, 100); + assertTrue(length == 8, "wrong length, expected %d got %zd", 8, length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Local, _encodeFixedHeader_Interest) +{ + uint8_t encoded[] = { + 0x01, 0x00, 0x00, 100, // ver = 1, type = interest, length = 100 + 0x1f, 0x00, 0x00, 14, // hoplimit = 31, reserved = 0x0000, header length = 14 + }; + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + ccnxTlvDictionary_PutInteger(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT, 31); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = _encodeFixedHeader(encoder, dict, CCNxCodecSchemaV1Types_PacketType_Interest, 14, 100); + assertTrue(length == 8, "wrong length, expected %d got %zd", 8, length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Local, _encodeOptionalHeaders) +{ + uint8_t encoded[] = { + 0x00, 0x01, 0x00, 2, // Interest Lifetime (2 bytes) + 0xEA, 0xEB, + }; + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + ccnxTlvDictionary_PutInteger(dict, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime, 0xEAEB); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = _encodeOptionalHeaders(encoder, dict); + assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Local, _encodeMessage_Interest) +{ + uint8_t encoded[] = { + 0x00, 0x01, 0x00, 13, + 0x00, 0x00, 0x00, 9, + 0x00, CCNxNameLabelType_NAME, 0x00, 5, + 'p', 'o', 'p', 'p', 'y' + }; + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxName *name = ccnxName_CreateFromCString("lci:/poppy"); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + ccnxTlvDictionary_PutName(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME, name); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxCodecSchemaV1Types_PacketType packetType; + ssize_t length = _encodeMessage(encoder, dict, &packetType); + assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length); + assertTrue(packetType == CCNxCodecSchemaV1Types_PacketType_Interest, "Wrong packet type, expected %d got %d", + CCNxCodecSchemaV1Types_PacketType_Interest, packetType); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxName_Release(&name); + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Local, _encodeMessage_ContentObject) +{ + uint8_t encoded[] = { + 0x00, 0x02, 0x00, 13, + 0x00, 0x00, 0x00, 9, + 0x00, CCNxNameLabelType_NAME, 0x00, 5, + 'p', 'o', 'p', 'p', 'y' + }; + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxName *name = ccnxName_CreateFromCString("lci:/poppy"); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ccnxTlvDictionary_PutName(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME, name); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxCodecSchemaV1Types_PacketType packetType; + ssize_t length = _encodeMessage(encoder, dict, &packetType); + assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length); + assertTrue(packetType == CCNxCodecSchemaV1Types_PacketType_ContentObject, "Wrong packet type, expected %d got %d", + CCNxCodecSchemaV1Types_PacketType_ContentObject, packetType); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxName_Release(&name); + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Local, _encodeCPI) +{ + uint8_t encoded [] = { + 0x00, 0x02, 0x03, 0x99, // + }; + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + ccnxValidationCRC32C_Set(dict); + ccnxTlvDictionary_PutBuffer(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, truth); + + ssize_t length = _encodeCPI(encoder, dict); + assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +/* + * This test requires that we set the message type to some unknown value, which we get if + * we create a dictionary with ccnxTlvDictionary_Create() and dont call anything to set + * the message type. It will be "CCNxTlvDictionary_Unknown". + */ +LONGBOW_TEST_CASE(Local, _encodeMessage_Unknown) +{ + CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(20, 20); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxCodecSchemaV1Types_PacketType packetType; + ssize_t length = _encodeMessage(encoder, dict, &packetType); + assertTrue(length < 0, "wrong length, expected negative got %zd", length); + + CCNxCodecError *error = ccnxCodecTlvEncoder_GetError(encoder); + assertNotNull(error, "Got null error when an error condition should have been set"); + + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Local, _encodeValidationAlg_Present) +{ + uint8_t encoded [] = { + 0x00, 0x03, 0x00, 4, // validation alg, length = 4 + 0x00, 0x02, 0x00, 0x00, // CRC32C + }; + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + PARCBuffer *truePayload = parcBuffer_Wrap(encoded, sizeof(encoded), 4, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + ccnxValidationCRC32C_Set(dict); + ccnxTlvDictionary_PutBuffer(dict, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD, truePayload); + + ssize_t length = _encodeValidationAlg(encoder, dict); + assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&truePayload); + parcBuffer_Release(&test); + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Local, _encodeValidationAlg_Missing) +{ + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + ssize_t length = _encodeValidationAlg(encoder, dict); + assertTrue(length == 0, "wrong length, expected %d got %zd", 0, length); + + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Local, _encodeValidationPayload_Present) +{ + uint8_t encoded [] = { + 0x00, 0x04, 0x00, 4, // validation payload, length = 4 + 0x00, 0x02, 0x03, 0x99, // + }; + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + PARCBuffer *truePayload = parcBuffer_Wrap(encoded, sizeof(encoded), 4, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + ccnxValidationCRC32C_Set(dict); + ccnxTlvDictionary_PutBuffer(dict, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD, truePayload); + + ssize_t length = _encodeValidationPayload(encoder, dict); + assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&truePayload); + parcBuffer_Release(&test); + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Local, _encodeValidationPayload_Missing) +{ + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + ssize_t length = _encodeValidationPayload(encoder, dict); + assertTrue(length == 0, "wrong length, expected %d got %zd", 0, length); + + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + + +// ================================================================================== + + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_PacketEncoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_TlvDictionary.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_TlvDictionary.c new file mode 100755 index 00000000..ccaa8b13 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_TlvDictionary.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_TlvDictionary.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_TlvDictionary) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_TlvDictionary) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_TlvDictionary) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateInterest); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateContentObject); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateControl); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateInterest) +{ + CCNxTlvDictionary *test = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + assertNotNull(test, "Got null return from ccnxCodecSchemaV1TlvDictionary_CreateInterest"); + assertTrue(ccnxTlvDictionary_IsInterest(test), "Dictionary is not an interest"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == CCNxTlvDictionary_SchemaVersion_V1, + "Wrong schema version, expected %d got %d", + CCNxTlvDictionary_SchemaVersion_V1, + ccnxTlvDictionary_GetSchemaVersion(test)); + ccnxTlvDictionary_Release(&test); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn) +{ + CCNxTlvDictionary *test = ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn(); + assertNotNull(test, "Got null return from ccnxCodecSchemaV1TlvDictionary_CreateInterest"); + assertTrue(ccnxTlvDictionary_IsInterestReturn(test), "Dictionary is not an interest"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == CCNxTlvDictionary_SchemaVersion_V1, + "Wrong schema version, expected %d got %d", + CCNxTlvDictionary_SchemaVersion_V1, + ccnxTlvDictionary_GetSchemaVersion(test)); + ccnxTlvDictionary_Release(&test); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateContentObject) +{ + CCNxTlvDictionary *test = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + assertNotNull(test, "Got null return from ccnxCodecSchemaV1TlvDictionary_CreateContentObject"); + assertTrue(ccnxTlvDictionary_IsContentObject(test), "Dictionary is not a content object"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == CCNxTlvDictionary_SchemaVersion_V1, + "Wrong schema version, expected %d got %d", + CCNxTlvDictionary_SchemaVersion_V1, + ccnxTlvDictionary_GetSchemaVersion(test)); + ccnxTlvDictionary_Release(&test); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateControl) +{ + CCNxTlvDictionary *test = ccnxCodecSchemaV1TlvDictionary_CreateControl(); + assertNotNull(test, "Got null return from ccnxCodecSchemaV1TlvDictionary_CreateControl"); + assertTrue(ccnxTlvDictionary_IsControl(test), "Dictionary is not a control"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == CCNxTlvDictionary_SchemaVersion_V1, + "Wrong schema version, expected %d got %d", + CCNxTlvDictionary_SchemaVersion_V1, + ccnxTlvDictionary_GetSchemaVersion(test)); + ccnxTlvDictionary_Release(&test); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_TlvDictionary); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationDecoder.c new file mode 100755 index 00000000..82cf69d1 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationDecoder.c @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_ValidationDecoder.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h> + +#include "testrig_packetwrapper.c" + +// ========================================================================= + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_ValidationDecoder) +{ + LONGBOW_RUN_TEST_FIXTURE(DecodeAlg); + LONGBOW_RUN_TEST_FIXTURE(DecodePayload); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_ValidationDecoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_ValidationDecoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(DecodeAlg) +{ + LONGBOW_RUN_TEST_CASE(DecodeAlg, CRC32C); + LONGBOW_RUN_TEST_CASE(DecodeAlg, HMAC_SHA256); + LONGBOW_RUN_TEST_CASE(DecodeAlg, RSA_SHA256); + + LONGBOW_RUN_TEST_CASE(DecodeAlg, Cert); + LONGBOW_RUN_TEST_CASE(DecodeAlg, PublicKey); + LONGBOW_RUN_TEST_CASE(DecodeAlg, KeyId); + LONGBOW_RUN_TEST_CASE(DecodeAlg, KeyName); + LONGBOW_RUN_TEST_CASE(DecodeAlg, SigTime); + + LONGBOW_RUN_TEST_CASE(DecodeAlg, KeyName_Invalid); +} + +LONGBOW_TEST_FIXTURE_SETUP(DecodeAlg) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(DecodeAlg) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(DecodeAlg, CRC32C) +{ + CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C; + PARCCryptoSuite parcSuite = PARCCryptoSuite_NULL_CRC32C; + + uint8_t encoded[] = { + 0x00, tlvSuite, 0x00, 0, + 0x00, 0x00, 0x00, 0x00 + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary); + assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCCryptoSuite test = (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE); + assertTrue(test == parcSuite, "Got wrong suite, expected %d got %d", parcSuite, test); + + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(DecodeAlg, HMAC_SHA256) +{ + CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256; + PARCCryptoSuite parcSuite = PARCCryptoSuite_HMAC_SHA256; + + uint8_t encoded[] = { + 0x00, tlvSuite, 0x00, 0, + 0x00, 0x00, 0x00, 0x00 + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary); + assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCCryptoSuite test = (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE); + assertTrue(test == parcSuite, "Got wrong suite, expected %d got %d", parcSuite, test); + + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(DecodeAlg, RSA_SHA256) +{ + CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256; + PARCCryptoSuite parcSuite = PARCCryptoSuite_RSA_SHA256; + + uint8_t encoded[] = { + 0x00, tlvSuite, 0x00, 0, + 0x00, 0x00, 0x00, 0x00 + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary); + assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCCryptoSuite test = (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE); + assertTrue(test == parcSuite, "Got wrong suite, expected %d got %d", parcSuite, test); + + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(DecodeAlg, Cert) +{ + uint8_t encoded[] = { + 0x00, 0x06, 0x00, 10, + 0x00, 0x0C, 0x00, 6, + 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary); + assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 8, sizeof(encoded)); + PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT); + assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(DecodeAlg, PublicKey) +{ + uint8_t encoded[] = { + 0x00, 0x06, 0x00, 10, + 0x00, 0x0B, 0x00, 6, + 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary); + assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 8, sizeof(encoded)); + PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY); + assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(DecodeAlg, KeyId) +{ + uint8_t encoded[] = { + 0x00, 0x06, 0x00, 10, + 0x00, 0x09, 0x00, 6, + 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary); + assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 8, sizeof(encoded)); + PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID); + assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(DecodeAlg, KeyName) +{ + uint8_t encoded[] = { + 0x00, 0x06, 0x00, 44, + 0x00, 0x0E, 0x00, 40, + // --- name + 0x00, 0x00, 0x00, 16, + 0x00, 0x03, 0x00, 5, + 'a', 'p', 'p', 'l', + 'e', + 0x00, 0x03, 0x00, 3, + 'p', 'i', 'e', + // --- keyid + 0x00, 0x01, 0x00, 4, + 0xa1, 0xa2, 0xa3, 0xa4, + // --- hash + 0x00, 0x02, 0x00, 8, + 0xb1, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxName *name = ccnxName_CreateFromCString("lci:/3=apple/3=pie"); + PARCBuffer *keyid = parcBuffer_Wrap(encoded, sizeof(encoded), 32, 36); + PARCBuffer *hash = parcBuffer_Wrap(encoded, sizeof(encoded), 40, 48); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary); + assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + // now test the 3 decoded fields + CCNxName *testName = ccnxTlvDictionary_GetName(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME); + assertTrue(ccnxName_Equals(testName, name), "keynames do not match") + { + printf("Expected\n"); + ccnxName_Display(name, 3); + printf("Got\n"); + ccnxName_Display(testName, 3); + } + + PARCBuffer *testKeyid = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_KEYID); + assertTrue(parcBuffer_Equals(testKeyid, keyid), "keyid do not match") + { + printf("Expected\n"); + parcBuffer_Display(keyid, 3); + printf("Got\n"); + parcBuffer_Display(testKeyid, 3); + } + + PARCBuffer *testHash = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH); + assertTrue(parcBuffer_Equals(testHash, hash), "keyid do not match") + { + printf("Expected\n"); + parcBuffer_Display(hash, 3); + printf("Got\n"); + parcBuffer_Display(testHash, 3); + } + + parcBuffer_Release(&keyid); + parcBuffer_Release(&hash); + ccnxName_Release(&name); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(DecodeAlg, KeyName_Invalid) +{ + // link is missing the Name + uint8_t encoded[] = { + 0x00, 0x06, 0x00, 24, + 0x00, 0x0E, 0x00, 20, + // --- keyid + 0x00, 0x01, 0x00, 4, + 0xa1, 0xa2, 0xa3, 0xa4, + // --- hash + 0x00, 0x02, 0x00, 8, + 0xb1, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary); + assertFalse(success, "Should have failed decode as keyname is invalid"); + + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(DecodeAlg, SigTime) +{ + uint64_t sigtime = 0x1122334455667788ULL; + uint8_t encoded[] = { + 0x00, 0x06, 0x00, 12, + 0x00, 0x0F, 0x00, 8, + 0x11, 0x22, 0x33, 0x44, + 0x55, 0x66, 0x77, 0x88 + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary); + assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + uint64_t test = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME); + assertTrue(test == sigtime, "Wrong sig time, expected %" PRIx64 ", got %" PRIx64, sigtime, test); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(DecodePayload) +{ + LONGBOW_RUN_TEST_CASE(DecodePayload, payload); + LONGBOW_RUN_TEST_CASE(DecodePayload, payload_zero); +} + +LONGBOW_TEST_FIXTURE_SETUP(DecodePayload) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(DecodePayload) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(DecodePayload, payload) +{ + uint8_t encoded[] = { + 0x00, 0x04, 0x00, 8, + 0x11, 0x22, 0x33, 0x44, + 0x55, 0x66, 0x77, 0x88 + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + + // the caller has already parsed the T and L, so we point to just payload + ccnxCodecTlvDecoder_Advance(decoder, 4); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodePayload(decoder, dictionary); + assertTrue(success, "Failed to decode a valid payload: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 4, 12); + PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD); + assertTrue(parcBuffer_Equals(truth, test), "Buffer mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(DecodePayload, payload_zero) +{ + uint8_t encoded[] = { + 0x00, 0x04, 0x00, 0, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + + // the caller has already parsed the T and L, so we point to just payload + ccnxCodecTlvDecoder_Advance(decoder, 4); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodePayload(decoder, dictionary); + assertFalse(success, "Should have failed on 0-length payload"); + + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +// ========================================================================= + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_ValidationDecoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationEncoder.c new file mode 100755 index 00000000..8a4d951a --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationEncoder.c @@ -0,0 +1,565 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_ValidationEncoder.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_crc32c.h> + +#include "testrig_packetwrapper.c" + +#include <ccnx/common/internal/ccnx_ValidationFacadeV1.h> + +#include <ccnx/common/validation/ccnxValidation_CRC32C.h> +#include <ccnx/common/validation/ccnxValidation_HmacSha256.h> + +// ========================================================================= + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_ValidationDecoder) +{ + LONGBOW_RUN_TEST_FIXTURE(EncodeAlg); + LONGBOW_RUN_TEST_FIXTURE(EncodePayload); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_ValidationDecoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_ValidationDecoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(EncodeAlg) +{ + LONGBOW_RUN_TEST_CASE(EncodeAlg, CRC32C); + LONGBOW_RUN_TEST_CASE(EncodeAlg, HMAC_SHA256); + LONGBOW_RUN_TEST_CASE(EncodeAlg, RSA_SHA256); + LONGBOW_RUN_TEST_CASE(EncodeAlg, DeduceFromSigner); + + LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodeCertificate); + LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodePublicKey); + LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodeKeyId); + LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodeKeyName); + LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodeSignatureTime_Specified); + LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodeSignatureTime_Generated); +} + +LONGBOW_TEST_FIXTURE_SETUP(EncodeAlg) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(EncodeAlg) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(EncodeAlg, CRC32C) +{ + CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C; + PARCCryptoSuite suite = PARCCryptoSuite_NULL_CRC32C; + + uint8_t encoded[] = { + 0x00, tlvSuite, 0x00, 0, + }; + + PARCBuffer *trueEncoded = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, suite); + + ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(encoder, dictionary); + assertFalse(length < 0, "Error on encoding: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(trueEncoded, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(trueEncoded, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&trueEncoded); +} + +LONGBOW_TEST_CASE(EncodeAlg, HMAC_SHA256) +{ + CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256; + PARCCryptoSuite suite = PARCCryptoSuite_HMAC_SHA256; + + uint8_t encoded[] = { + 0x00, tlvSuite, 0x00, 0, + }; + + PARCBuffer *trueEncoded = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, suite); + + ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(encoder, dictionary); + assertFalse(length < 0, "Error on encoding: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(trueEncoded, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(trueEncoded, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&trueEncoded); +} + +LONGBOW_TEST_CASE(EncodeAlg, RSA_SHA256) +{ + CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256; + PARCCryptoSuite suite = PARCCryptoSuite_RSA_SHA256; + + uint8_t encoded[] = { + 0x00, tlvSuite, 0x00, 0, + }; + + PARCBuffer *trueEncoded = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, suite); + + ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(encoder, dictionary); + assertFalse(length < 0, "Error on encoding: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(trueEncoded, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(trueEncoded, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&trueEncoded); +} + +LONGBOW_TEST_CASE(EncodeAlg, DeduceFromSigner) +{ + PARCSigner *signer = ccnxValidationCRC32C_CreateSigner(); + CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvsuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C; + + uint8_t encoded[] = { + 0x00, tlvsuite, 0x00, 0, + }; + + PARCBuffer *trueEncoded = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_SetSigner(encoder, signer); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + + ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(encoder, dictionary); + assertFalse(length < 0, "Error on encoding: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(trueEncoded, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(trueEncoded, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&trueEncoded); + parcSigner_Release(&signer); +} + +// ======= + +LONGBOW_TEST_CASE(EncodeAlg, _encodeCertificate) +{ + uint8_t encoded[] = { + 0x00, 0x0C, 0x00, 6, + 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f + }; + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + PARCBuffer *cert = parcBuffer_Wrap(encoded, sizeof(encoded), 4, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ccnxValidationFacadeV1_SetCertificate(dictionary, cert); + + ssize_t length = _encodeCertificate(encoder, dictionary); + assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + parcBuffer_Release(&truth); + parcBuffer_Release(&cert); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + + +LONGBOW_TEST_CASE(EncodeAlg, _encodePublicKey) +{ + uint8_t encoded[] = { + 0x00, 0x0B, 0x00, 6, + 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f + }; + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + PARCBuffer *key = parcBuffer_Wrap(encoded, sizeof(encoded), 4, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ccnxValidationFacadeV1_SetPublicKey(dictionary, key); + + ssize_t length = _encodePublicKey(encoder, dictionary); + assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + parcBuffer_Release(&truth); + parcBuffer_Release(&key); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(EncodeAlg, _encodeKeyId) +{ + uint8_t encoded[] = { + 0x00, 0x09, 0x00, 6, + 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f + }; + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + PARCBuffer *keyid = parcBuffer_Wrap(encoded, sizeof(encoded), 4, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ccnxValidationFacadeV1_SetKeyId(dictionary, keyid); + + ssize_t length = _encodeKeyId(encoder, dictionary); + assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + parcBuffer_Release(&truth); + parcBuffer_Release(&keyid); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(EncodeAlg, _encodeKeyName) +{ + uint8_t encoded[] = { + 0x00, 0x0E, 0x00, 40, + // --- name + 0x00, 0x00, 0x00, 16, + 0x00, 0x03, 0x00, 5, + 'a', 'p', 'p', 'l', + 'e', + 0x00, 0x03, 0x00, 3, + 'p', 'i', 'e', + // --- keyid + 0x00, 0x01, 0x00, 4, + 0xa1, 0xa2, 0xa3, 0xa4, + // --- hash + 0x00, 0x02, 0x00, 8, + 0xb1, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, + }; + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + PARCBuffer *keyid = parcBuffer_Wrap(encoded, sizeof(encoded), 28, 32); + PARCBuffer *hash = parcBuffer_Wrap(encoded, sizeof(encoded), 36, 44); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxName *name = ccnxName_CreateFromCString("lci:/3=apple/3=pie"); + CCNxLink *link = ccnxLink_Create(name, keyid, hash); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ccnxValidationFacadeV1_SetKeyName(dictionary, link); + + ssize_t length = _encodeKeyName(encoder, dictionary); + assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + parcBuffer_Release(&truth); + parcBuffer_Release(&keyid); + parcBuffer_Release(&hash); + ccnxName_Release(&name); + ccnxLink_Release(&link); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(EncodeAlg, _encodeSignatureTime_Specified) +{ + uint64_t sigtime = 0x1122334455667788ULL; + uint8_t encoded[] = { + 0x00, 0x0F, 0x00, 8, + 0x11, 0x22, 0x33, 0x44, + 0x55, 0x66, 0x77, 0x88 + }; + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ccnxValidationFacadeV1_SetSigningTime(dictionary, sigtime); + + ssize_t length = _encodeSignatureTime(encoder, dictionary); + assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + parcBuffer_Release(&truth); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +/* + * Do not specify a signing time, but rather set a Signer and let the code + * create the time on its own + */ +LONGBOW_TEST_CASE(EncodeAlg, _encodeSignatureTime_Generated) +{ + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + PARCBuffer *password = parcBuffer_Wrap("password", 8, 0, 8); + PARCSigner *signer = ccnxValidationHmacSha256_CreateSigner(password); + ccnxCodecTlvEncoder_SetSigner(encoder, signer); + parcSigner_Release(&signer); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + + ssize_t length = _encodeSignatureTime(encoder, dictionary); + assertTrue(length == 12, "Wrong length, expected 12, got %zd", length); + + parcBuffer_Release(&password); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(EncodePayload) +{ + LONGBOW_RUN_TEST_CASE(EncodePayload, payload_Specified); + LONGBOW_RUN_TEST_CASE(EncodePayload, payload_Generated); +} + +LONGBOW_TEST_FIXTURE_SETUP(EncodePayload) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(EncodePayload) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(EncodePayload, payload_Specified) +{ + uint8_t encoded[] = { + 0x11, 0x22, 0x33, 0x44, + 0x55, 0x66, 0x77, 0x88 + }; + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ccnxValidationFacadeV1_SetPayload(dictionary, truth); + + ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodePayload(encoder, dictionary); + assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + parcBuffer_Release(&truth); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +/* + * Put the guts of v1_interest_nameA_crc32c in to the encoding buffer and mark it + * as the signature block. Generate the CRC and make sure we got the right thing. + */ +LONGBOW_TEST_CASE(EncodePayload, payload_Generated) +{ + TlvExtent interestExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_INTEREST); + + // This will test against the string (Interest, ValidationAlg, ValidationPayload) + PARCBuffer *truth = parcBuffer_Wrap(v1_interest_nameA_crc32c, + sizeof(v1_interest_nameA_crc32c), + interestExtent.offset, + sizeof(v1_interest_nameA_crc32c)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + PARCSigner *signer = ccnxValidationCRC32C_CreateSigner(); + ccnxCodecTlvEncoder_SetSigner(encoder, signer); + parcSigner_Release(&signer); + + // This will append from the beginning of the Interest message up to the end of the ValidationAlg + // This space is all marked as the "to-be-signed" section. + ccnxCodecTlvEncoder_MarkSignatureStart(encoder); + size_t signedInfoLenth = sizeof(v1_interest_nameA_crc32c) - 8 - interestExtent.offset; + ccnxCodecTlvEncoder_AppendRawArray(encoder, signedInfoLenth, v1_interest_nameA_crc32c + interestExtent.offset); + ccnxCodecTlvEncoder_MarkSignatureEnd(encoder); + + // add the validation payload container, then generate the signature + ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_MessageType_ValidationPayload, 4); + + // Do the actual encoding. This will calculate the signature on the fly. + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodePayload(encoder, dictionary); + assertTrue(length == 4, "Wrong length, expected 4 got %zd", length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + + // Tests that we got the right signature (CRC32c in this case) + assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); + parcBuffer_Release(&test); +} + +// ========================================================================= + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_ValidationDecoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_encoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_encoder.c new file mode 100644 index 00000000..f925dd28 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_encoder.c @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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. + */ + +/** + */ + +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h> +#include <ccnx/common/codec/ccnxCodec_EncodingBuffer.h> + +#include <ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h> + + +#include <ccnx/common/codec/schema_v1/testdata/v1_testrig_truthTable.h> +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h> +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h> + +#include <ccnx/common/codec/test/testrig_Compare.c> + +/** + * Finds a row in the truthtable where bodyManifest is TRUE and the + * indexOrKey equals 'key'. + */ +TlvExtent +getTruthTableExtent(TruthTableEntry *ttentry, int key) +{ + for (int i = 0; ttentry[i].indexOrKey != T_INVALID; i++) { + if (ttentry[i].bodyManifest && ttentry[i].indexOrKey == key) { + return ttentry[i].extent; + } + } + return (TlvExtent) { 0, 0 }; +} + +/** + * Finds a row in the truthtable where bodyManifest is FALSE and the + * indexOrKey equals 'key'. + */ +TlvExtent +getTruthTableHeaderExtent(TruthTableEntry *ttentry, int key) +{ + for (int i = 0; ttentry[i].indexOrKey != T_INVALID; i++) { + if (!ttentry[i].bodyManifest && ttentry[i].indexOrKey == key) { + return ttentry[i].extent; + } + } + return (TlvExtent) { 0, 0 }; +} + +typedef struct test_data { + // the memory region extracted from a Truth Table entry + PARCBuffer *memoryRegion; + + CCNxCodecTlvEncoder *encoder; + CCNxTlvDictionary *dictionary; + + uint8_t *packet; + size_t packetLength; + TruthTableEntry *truthTable; + + // If the user creates one of these, we'll destroy it. + PARCSigner *signer; +} TestData; + +static SchemaV1ManifestContentObjectBody manifestContentObjectContainerArray[] = { + V1_MANIFEST_OBJ_CONTENTOBJECT, + V1_MANIFEST_OBJ_NAMEAUTH, + V1_MANIFEST_OBJ_ValidationPayload, + V1_MANIFEST_OBJ_KEYNAME, + V1_MANIFEST_OBJ_METADATA, + V1_MANIFEST_OBJ_ValidationAlg, + V1_MANIFEST_OBJ_BODYEND +}; + +static bool +isContentObjectContainer(SchemaV1ManifestContentObjectBody value) +{ + for (int i = 0; manifestContentObjectContainerArray[i] != V1_MANIFEST_OBJ_BODYEND; i++) { + if (value == manifestContentObjectContainerArray[i]) { + return true; + } + } + return false; +} + +/** + * The testdata truth tables were written with the tlv_1.0 array indicies, so we + * need to translate those old indicies to the new indicies. + */ +static CCNxCodecSchemaV1TlvDictionary_MessageFastArray +translateTestDataManifestToSchemaKey(SchemaV1ManifestContentObjectBody oldKey) +{ + switch (oldKey) { + case V1_MANIFEST_INT_NAME: + // fallthrough + case V1_MANIFEST_OBJ_NAME: + return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME; + + case V1_MANIFEST_OBJ_PAYLOAD: + return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD; + + case V1_MANIFEST_OBJ_KEYID: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID; + + case V1_MANIFEST_OBJ_CRYPTO_SUITE: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE; + + case V1_MANIFEST_OBJ_KEY: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY; + + case V1_MANIFEST_OBJ_CERT: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT; + + case V1_MANIFEST_OBJ_KEYNAME_NAME: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME; + + case V1_MANIFEST_OBJ_KEYNAME_OBJHASH: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH; + + case V1_MANIFEST_OBJ_OBJ_TYPE: + return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE; + + case V1_MANIFEST_OBJ_SIGBITS: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD; + + case V1_MANIFEST_OBJ_SigningTime: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME; + + case V1_MANIFEST_OBJ_ENDSEGMENT: + return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT; + + case V1_MANIFEST_INT_KEYID: + return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION; + + case V1_MANIFEST_INT_OBJHASH: + return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION; + + default: + trapIllegalValue(oldKey, "Unexpected old manifest value: %d", oldKey); + break; + } + return -1; +} + +/** + * The testdata truth tables were written with the tlv_1.0 array indicies, so we + * need to translate those old indicies to the new indicies. + */ +static CCNxCodecSchemaV1TlvDictionary_HeadersFastArray +translateOldOptionalHeadersManifestToNewKey(CCNxTlvDictionary *packetDictionary, int oldKey) +{ + if (ccnxTlvDictionary_IsInterest(packetDictionary)) { + switch (oldKey) { + case V1_MANIFEST_INT_LIFETIME: + return CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime; + + case V1_MANIFEST_INT_E2EFRAG: + return CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG; + + default: + trapIllegalValue(oldKey, "Unexpected old manifest value: %d", oldKey); + break; + } + } else if (ccnxTlvDictionary_IsContentObject(packetDictionary)) { + switch (oldKey) { + case V1_MANIFEST_OBJ_E2EFRAG: + return CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG; + + default: + trapIllegalValue(oldKey, "Unexpected old manifest value: %d", oldKey); + break; + } + } + return -1; +} + +static void +addBuffer(TestData *data, CCNxTlvDictionary *packetDictionary, size_t item_start, size_t item_end, uint32_t translatedKey) +{ + PARCBuffer *itemBuffer = parcBuffer_Wrap(data->packet, data->packetLength, item_start, item_end); + ccnxTlvDictionary_PutBuffer(packetDictionary, translatedKey, itemBuffer); + parcBuffer_Release(&itemBuffer); +} + +/** + * The extent should be treated like a CCNxName, so decode it and add it as a CCNxName. + */ +static void +addName(TestData *data, CCNxTlvDictionary *packetDictionary, size_t item_start, size_t item_end, uint32_t translatedKey) +{ + // we need to backup 4 bytes to the the TLV container + PARCBuffer *itemBuffer = parcBuffer_Wrap(data->packet, data->packetLength, item_start - 4, item_end); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(itemBuffer); + CCNxName *name = ccnxCodecSchemaV1NameCodec_Decode(decoder, CCNxCodecSchemaV1Types_CCNxMessage_Name); + ccnxCodecTlvDecoder_Destroy(&decoder); + + ccnxTlvDictionary_PutName(packetDictionary, translatedKey, name); + ccnxName_Release(&name); + parcBuffer_Release(&itemBuffer); +} + + +/** + * Called on the body of a content object, does not include the fixed header or optional headers + * + * <#Paragraphs Of Explanation#> + * + * @param [<#in out in,out#>] <#name#> <#description#> + * + * @return <#value#> <#explanation#> + * + * Example: + * @code + * <#example#> + * @endcode + */ +static void +buildContentObjectDictionary(TestData *data, CCNxTlvDictionary *packetDictionary, TlvExtent extent) +{ + size_t start = extent.offset; + size_t end = start + extent.length; + + ccnxTlvDictionary_SetMessageType_ContentObject(packetDictionary, CCNxTlvDictionary_SchemaVersion_V1); + + for (int i = 0; data->truthTable[i].indexOrKey != T_INVALID; i++) { + size_t item_start = data->truthTable[i].extent.offset; + size_t item_end = item_start + data->truthTable[i].extent.length; + + // Is this item included in the given extent? + if (start < item_start && item_end <= end) { + // Is it a container or a nested dictionary? This check only applies to a ContentObject + if (!isContentObjectContainer(data->truthTable[i].indexOrKey)) { + uint32_t translatedKey = translateTestDataManifestToSchemaKey(data->truthTable[i].indexOrKey); + + if (data->truthTable[i].indexOrKey == V1_MANIFEST_OBJ_NAME) { + addName(data, packetDictionary, item_start, item_end, translatedKey); + } else { + addBuffer(data, packetDictionary, item_start, item_end, translatedKey); + } + } + } + } +} + +static void +buildInterestDictionary(TestData *data, CCNxTlvDictionary *packetDictionary, TlvExtent extent) +{ + size_t start = extent.offset; + size_t end = start + extent.length; + + ccnxTlvDictionary_SetMessageType_Interest(packetDictionary, CCNxTlvDictionary_SchemaVersion_V1); + + for (int i = 0; data->truthTable[i].indexOrKey != T_INVALID && data->truthTable[i].bodyManifest; i++) { + size_t item_start = data->truthTable[i].extent.offset; + size_t item_end = item_start + data->truthTable[i].extent.length; + + // Is this item included in the given extent? + if (start < item_start && item_end <= end) { + uint32_t translatedKey = translateTestDataManifestToSchemaKey(data->truthTable[i].indexOrKey); + + if (data->truthTable[i].indexOrKey == V1_MANIFEST_INT_NAME) { + addName(data, packetDictionary, item_start, item_end, translatedKey); + } else { + addBuffer(data, packetDictionary, item_start, item_end, translatedKey); + } + } + } +} + +/** + * Make a dictionary entry for everything inside the selected extent, not including it + * + * Use the truth table and for each listed item whose extent is within the given extent, + * add a dictionary entry + * + * @param [<#in out in,out#>] <#name#> <#description#> + * + * @return <#value#> <#explanation#> + * + * Example: + * @code + * <#example#> + * @endcode + */ +static void +buildMessageDictionary(TestData *data, CCNxTlvDictionary *dictionary, TlvExtent extent) +{ + uint8_t packetType = data->packet[1]; + switch (packetType) { + case CCNxCodecSchemaV1Types_PacketType_Interest: + buildInterestDictionary(data, dictionary, extent); + break; + + case CCNxCodecSchemaV1Types_PacketType_ContentObject: + buildContentObjectDictionary(data, dictionary, extent); + break; + + case CCNxCodecSchemaV1Types_PacketType_InterestReturn: + trapNotImplemented("not implemented"); + break; + + default: + trapIllegalValue(packetType, "Unknown PacketType"); + } +} + +static void +buildSetDictionaryType(TestData *data, CCNxTlvDictionary *dictionary) +{ + uint8_t packetType = data->packet[1]; + switch (packetType) { + case CCNxCodecSchemaV1Types_PacketType_Interest: + ccnxTlvDictionary_SetMessageType_Interest(dictionary, CCNxTlvDictionary_SchemaVersion_V1); + break; + + case CCNxCodecSchemaV1Types_PacketType_ContentObject: + ccnxTlvDictionary_SetMessageType_ContentObject(dictionary, CCNxTlvDictionary_SchemaVersion_V1); + break; + + case CCNxCodecSchemaV1Types_PacketType_InterestReturn: + trapNotImplemented("not implemented"); + break; + + default: + trapIllegalValue(packetType, "Unknown PacketType"); + } +} + +/** + * Builds a packet dictionary with OptionalHeaders and Message + * + * <#Paragraphs Of Explanation#> + * + * @param [<#in out in,out#>] <#name#> <#description#> + * + * @return <#value#> <#explanation#> + * + * Example: + * @code + * <#example#> + * @endcode + */ +static void +buildPacketDictionary(TestData *data, CCNxTlvDictionary *packetDictionary, TlvExtent extent) +{ + buildSetDictionaryType(data, packetDictionary); + + size_t start = extent.offset; + size_t end = start + extent.length; + + for (int i = 0; data->truthTable[i].indexOrKey != T_INVALID; i++) { + size_t item_start = data->truthTable[i].extent.offset; + size_t item_end = item_start + data->truthTable[i].extent.length; + + // Is this item included in the given extent? + if (start < item_start && item_end <= end) { + if (data->truthTable[i].bodyManifest == false) { + PARCBuffer *itemBuffer = parcBuffer_Wrap(data->packet, data->packetLength, item_start, item_end); + uint32_t translatedKey = translateOldOptionalHeadersManifestToNewKey(packetDictionary, data->truthTable[i].indexOrKey); + ccnxTlvDictionary_PutBuffer(packetDictionary, translatedKey, itemBuffer); + parcBuffer_Release(&itemBuffer); + } else { + buildMessageDictionary(data, packetDictionary, data->truthTable[i].extent); + } + + // advance start to skip over whatever we just included + start = item_end; + } + } +} + +/** + * Wraps the given (packet, length) in a PARCBuffer where the data->memoryRegion member will be set + * to a given extent within that PARCBuffer. The function will locate the truthTableKey in the truthTable and + * use it's extent as the bounds for the wrapped packet. + * + * For example, if the key V1_INT_NAME has the extent {32, 12}, then the PARCBuffer will wrap the packet + * memory and it will have and offset of 32 and a limit of 12. + */ +TestData * +commonSetup(uint8_t *packet, size_t length, TruthTableEntry *truthTable, int truthTableKey) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + TlvExtent extent = getTruthTableExtent(truthTable, truthTableKey); + + data->memoryRegion = parcBuffer_Wrap(packet, length, extent.offset, extent.offset + extent.length); + data->encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(data->encoder); + + // use the content object lenghts, they are the largest + data->dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END); + + data->packet = packet; + data->packetLength = length; + data->truthTable = truthTable; + + buildMessageDictionary(data, data->dictionary, extent); + return data; +} + +/** + * Wraps a packet like commonSetup, but will do the whole packet including headers not just + * the message body. This is used by the PacketEncoder tests. + */ +TestData * +testrigencoder_CommonSetupWholePacket(uint8_t *packet, size_t length, TruthTableEntry *truthTable) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + data->memoryRegion = parcBuffer_Wrap(packet, length, 0, length); + data->encoder = ccnxCodecTlvEncoder_Create(); + + // use the content object lenghts, they are the largest + data->dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END); + + data->packet = packet; + data->packetLength = length; + data->truthTable = truthTable; + + buildPacketDictionary(data, data->dictionary, (TlvExtent) { 0, length }); + + return data; +} + +void +testrigencoder_CommonTeardown(TestData *data) +{ + ccnxTlvDictionary_Release(&data->dictionary); + ccnxCodecTlvEncoder_Destroy(&data->encoder); + parcBuffer_Release(&data->memoryRegion); + + if (data->signer) { + parcSigner_Release(&data->signer); + } + + parcMemory_Deallocate((void **) &data); +} + +void +testDisplayIoVec(CCNxCodecEncodingBufferIOVec *vec) +{ + printf("Display iovec %p with %d elements\n", (void *) vec, vec->iovcnt); + size_t totalLength = 0; + for (int i = 0; i < vec->iovcnt; i++) { + totalLength += vec->iov[i].iov_len; + printf(" %3d: base %p length %4zu total length %4zu\n", i, (void *) vec->iov[i].iov_base, vec->iov[i].iov_len, totalLength); + } + printf("done\n\n"); +} + +void +testExecute(TestData *data, ssize_t (*encoderFunction)(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *dictionary)) +{ + encoderFunction(data->encoder, data->dictionary); + testCompareEncoderToBuffer(data->encoder, data->memoryRegion); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_packetwrapper.c b/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_packetwrapper.c new file mode 100644 index 00000000..9a213b13 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_packetwrapper.c @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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. + */ + +/** + * This test rig sets up test data to wrap a packet and prepare it for use in a decoder + * + * A hand-encoded packet, such as from the testdata directory can be passed to commonSetup and then + * run automated tests against it based on its manifest. + * + * Example: + * @code + * + * static uint8_t object_nameC_keyid3_protoinfo[] = { + * 0x00, 0x02, 0x00, 110, // ver = 0, type = object, length = 110 + * 0x00, 0x00, 0x00, 5, // reserved = 0, header length = 5 + * // --------------------------- + * // snip middle of packet + * // ------------------------ + * // byte offset 76 + * 0x00, 0x03, 0x00, 26, // Protocol Information, length = 26 + * 0x00, 0x0B, 0x00, 17, // Object Metadata, length = 17 + * 0x00, 0x0C, 0x00, 0x01, // Object Type, length = 1 + * 0x04, // LINK + * 0x00, 0x0D, 0x00, 8, // Creation Time + * 0x00, 0x00, 0x01, 0x43, // 1,388,534,400,000 msec + * 0x4B, 0x19, 0x84, 0x00, + * 0x00, 0x19, 0x00, 0x01, // EndSegment, length = 1 + * 42, + * // --------------------------- + * // snip to end of packet + * // --------------------------- + * }; + * + * static TruthTableEntry TRUTHTABLENAME(object_nameC_keyid3_protoinfo)[] = { + * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_METADATA, .bodyManifest=true, .extent = { 80, 17} }, + * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_OBJ_TYPE, .bodyManifest=true, .extent = { 84, 1} }, + * { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0} }, + * }; + * + * LONGBOW_TEST_FIXTURE_SETUP(Global) + * { + * commonSetup(testCase, object_nameC_keyid3_protoinfo, sizeof(object_nameC_keyid3_protoinfo), object_nameC_keyid3_protoinfo_truthTableEntries, MANIFEST_OBJ_METADATA); + * return LONGBOW_STATUS_SUCCEEDED; + * } + * + * LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV0ProtoInfo_GetEndSegmentNumber) + * { + * testInt32Getter(testCase, MANIFEST_OBJ_OBJ_TYPE, ccnxCodecSchemaV0Metadata_Decode, ccnxCodecSchemaV0Metadata_GetContentType); + * } + * + * @endcode + * + */ + +#include <inttypes.h> +#include <stdio.h> + +#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h> +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h> +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_testrig_truthTable.h> + +/** + * Finds a row in the truthtable where bodyManifest is TRUE and the + * indexOrKey equals 'key'. + */ +TlvExtent +getTruthTableExtent(TruthTableEntry *ttentry, int key) +{ + for (int i = 0; ttentry[i].indexOrKey != T_INVALID; i++) { + if (ttentry[i].bodyManifest && ttentry[i].indexOrKey == key) { + return ttentry[i].extent; + } + } + return (TlvExtent) { 0, 0 }; +} + +/** + * Finds a row in the truthtable where bodyManifest is FALSE and the + * indexOrKey equals 'key'. + */ +TlvExtent +getTruthTableHeaderExtent(TruthTableEntry *ttentry, int key) +{ + for (int i = 0; ttentry[i].indexOrKey != T_INVALID; i++) { + if (!ttentry[i].bodyManifest && ttentry[i].indexOrKey == key) { + return ttentry[i].extent; + } + } + return (TlvExtent) { 0, 0 }; +} + +typedef struct test_data { + PARCBuffer *interest; + CCNxCodecTlvDecoder *decoder; + CCNxTlvDictionary *dictionary; + + uint8_t *packet; + size_t packetLength; + TruthTableEntry *truthTable; +} TestData; + +/** + * Wraps the given (packet, length) in a PARCBuffer where the data->memoryRegion member will be set + * to a given extent within that PARCBuffer. The function will locate the truthTableKey in the truthTable and + * use it's extent as the bounds for the wrapped packet. + * + * For example, if the key V1_INT_NAME has the extent {32, 12}, then the PARCBuffer will wrap the packet + * memory and it will have and offset of 32, position 0, and a limit of 12. + */ +TestData * +commonSetup(uint8_t *packet, size_t length, TruthTableEntry *truthTable, int truthTableKey) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + TlvExtent extent = getTruthTableExtent(truthTable, truthTableKey); + + data->interest = parcBuffer_Wrap(packet, length, extent.offset, extent.offset + extent.length); + data->decoder = ccnxCodecTlvDecoder_Create(data->interest); + + // content objects have more fields than interests, so use that + data->dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END); + + data->packet = packet; + data->packetLength = length; + data->truthTable = truthTable; + return data; +} + +void +commonSetupWholePacket(LongBowTestCase *testCase, uint8_t *packet, size_t length, TruthTableEntry *truthTable) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + data->interest = parcBuffer_Wrap(packet, length, 0, length); + data->decoder = ccnxCodecTlvDecoder_Create(data->interest); + data->dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END); + + data->packet = packet; + data->packetLength = length; + data->truthTable = truthTable; + + longBowTestCase_SetClipBoardData(testCase, data); +} + +void +commonTeardown(TestData *data) +{ + ccnxTlvDictionary_Release(&data->dictionary); + ccnxCodecTlvDecoder_Destroy(&data->decoder); + parcBuffer_Release(&data->interest); + parcMemory_Deallocate((void **) &data); +} + +/** + * Tests that an int32_t getter returns the right value + * + * Given a packet byte array and a truth table (see transport/test_tools/testdata/testrig_truthTable.h), + * check that the buffer the decoder parsed is the right buffer. + * + * The function will run the specified decoder on the TestData's packet and put the results in the + * TestData's dictionary. It will then call the specified getter and make sure its value is equal + * to the truth table's value. + * + * The function will assert if the test fails. + * + * @param [in] testCase Used to get the clipboard data with the TestData member + * @param [in] truthTableKey Used to match the .indexOrKey truth table member + * @param [in] containerDecoder The decoder to use on the packet contained in TestData + * @param [in] getter The function to call to fetch a decoded value + * + * Example: + * @code + * + * static uint8_t object_nameC_keyid3_protoinfo[] = { + * 0x00, 0x02, 0x00, 110, // ver = 0, type = object, length = 110 + * 0x00, 0x00, 0x00, 5, // reserved = 0, header length = 5 + * // --------------------------- + * // snip middle of packet + * // ------------------------ + * // byte offset 76 + * 0x00, 0x03, 0x00, 26, // Protocol Information, length = 26 + * 0x00, 0x0B, 0x00, 17, // Object Metadata, length = 17 + * 0x00, 0x0C, 0x00, 0x01, // Object Type, length = 1 + * 0x04, // LINK + * 0x00, 0x0D, 0x00, 8, // Creation Time + * 0x00, 0x00, 0x01, 0x43, // 1,388,534,400,000 msec + * 0x4B, 0x19, 0x84, 0x00, + * 0x00, 0x19, 0x00, 0x01, // EndSegment, length = 1 + * 42, + * // --------------------------- + * // snip to end of packet + * // --------------------------- + * }; + * + * static TruthTableEntry TRUTHTABLENAME(object_nameC_keyid3_protoinfo)[] = { + * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_METADATA, .bodyManifest=true, .extent = { 80, 17} }, + * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_OBJ_TYPE, .bodyManifest=true, .extent = { 84, 1} }, + * { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0} }, + * }; + * + * LONGBOW_TEST_FIXTURE_SETUP(Global) + * { + * commonSetup(testCase, object_nameC_keyid3_protoinfo, sizeof(object_nameC_keyid3_protoinfo), object_nameC_keyid3_protoinfo_truthTableEntries, MANIFEST_OBJ_METADATA); + * return LONGBOW_STATUS_SUCCEEDED; + * } + * + * LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV0ProtoInfo_GetEndSegmentNumber) + * { + * testInt32Getter(testCase, MANIFEST_OBJ_OBJ_TYPE, ccnxCodecSchemaV0Metadata_Decode, ccnxCodecSchemaV0Metadata_GetContentType); + * } + * * @endcode + */ +void +testInt32Getter(LongBowTestCase *testCase, int truthTableKey, bool containerDecoder(CCNxCodecTlvDecoder *, CCNxTlvDictionary *), + int32_t (*getter)(CCNxTlvDictionary *)) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + containerDecoder(data->decoder, data->dictionary); + int32_t testvalue = getter(data->dictionary); + + // look up the true name buffer from the truth table + TlvExtent extent = getTruthTableExtent(data->truthTable, truthTableKey); + PARCBuffer *truthbuffer = parcBuffer_Wrap(data->packet, data->packetLength, extent.offset, extent.offset + extent.length); + uint64_t truthvalue = -2; + ccnxCodecTlvUtilities_GetVarInt(truthbuffer, parcBuffer_Remaining(truthbuffer), &truthvalue); + + parcBuffer_Release(&truthbuffer); + + assertTrue(testvalue == (int32_t) truthvalue, "Wrong value, got %d expected %d", testvalue, (int32_t) truthvalue); +} + +/** + * Tests that an int64_t getter returns the right value + * + * Given a packet byte array and a truth table (see transport/test_tools/testdata/testrig_truthTable.h), + * check that the buffer the decoder parsed is the right buffer. + * + * The function will run the specified decoder on the TestData's packet and put the results in the + * TestData's dictionary. It will then call the specified getter and make sure its value is equal + * to the truth table's value. + * + * The function will assert if the test fails. + * + * @param [in] testCase Used to get the clipboard data with the TestData member + * @param [in] truthTableKey Used to match the .indexOrKey truth table member + * @param [in] containerDecoder The decoder to use on the packet contained in TestData + * @param [in] getter The function to call to fetch a decoded value + * + * Example: + * @code + * + * static uint8_t object_nameC_keyid3_protoinfo[] = { + * 0x00, 0x02, 0x00, 110, // ver = 0, type = object, length = 110 + * 0x00, 0x00, 0x00, 5, // reserved = 0, header length = 5 + * // --------------------------- + * // snip middle of packet + * // ------------------------ + * // byte offset 76 + * 0x00, 0x03, 0x00, 26, // Protocol Information, length = 26 + * 0x00, 0x0B, 0x00, 17, // Object Metadata, length = 17 + * 0x00, 0x0C, 0x00, 0x01, // Object Type, length = 1 + * 0x04, // LINK + * 0x00, 0x0D, 0x00, 8, // Creation Time + * 0x00, 0x00, 0x01, 0x43, // 1,388,534,400,000 msec + * 0x4B, 0x19, 0x84, 0x00, + * 0x00, 0x19, 0x00, 0x01, // EndSegment, length = 1 + * 42, + * // --------------------------- + * // snip to end of packet + * // --------------------------- + * }; + * + * static TruthTableEntry TRUTHTABLENAME(object_nameC_keyid3_protoinfo)[] = { + * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_PROTOINFO, .bodyManifest=true, .extent = { 76, 26} }, + * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_ENDSEGMENT, .bodyManifest=true, .extent = {101, 1} }, + * { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0} }, + * }; + * + * LONGBOW_TEST_FIXTURE_SETUP(Global) + * { + * commonSetup(testCase, object_nameC_keyid3_protoinfo, sizeof(object_nameC_keyid3_protoinfo), object_nameC_keyid3_protoinfo_truthTableEntries, MANIFEST_OBJ_PROTOINFO); + * return LONGBOW_STATUS_SUCCEEDED; + * } + * + * LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV0ProtoInfo_GetEndSegmentNumber) + * { + * testInt64Getter(testCase, MANIFEST_OBJ_ENDSEGMENT, ccnxCodecSchemaV0ProtoInfo_Decode, ccnxCodecSchemaV0ProtoInfo_GetEndSegmentNumber); + * } + * + * @endcode + */ +void +testInt64Getter(TestData *data, int truthTableKey, bool containerDecoder(CCNxCodecTlvDecoder *, CCNxTlvDictionary *), + int64_t (*getter)(CCNxTlvDictionary *)) +{ + containerDecoder(data->decoder, data->dictionary); + int64_t testvalue = getter(data->dictionary); + + // look up the true name buffer from the truth table + TlvExtent extent = getTruthTableExtent(data->truthTable, truthTableKey); + PARCBuffer *truthbuffer = parcBuffer_Wrap(data->packet, data->packetLength, extent.offset, extent.offset + extent.length); + uint64_t truthvalue = -2; + ccnxCodecTlvUtilities_GetVarInt(truthbuffer, parcBuffer_Remaining(truthbuffer), &truthvalue); + + parcBuffer_Release(&truthbuffer); + + assertTrue(testvalue == (int64_t) truthvalue, "Wrong value, got %" PRId64 " expected %" PRId64, testvalue, (int64_t) truthvalue); +} + +/** + * Tests that a buffer getter returns the right buffer + * + * Given a packet byte array and a truth table (see transport/test_tools/testdata/testrig_truthTable.h), + * check that the buffer the decoder parsed is the right buffer. + * + * The function will run the specified decoder on the TestData's packet and put the results in the + * TestData's dictionary. It will then call the specified getter and make sure its value is equal + * to the truth table's value. + * + * The function will assert if the test fails. + * + * @param [in] testCase Used to get the clipboard data with the TestData member + * @param [in] truthTableKey Used to match the .indexOrKey truth table member + * @param [in] containerDecoder The decoder to use on the packet contained in TestData + * @param [in] getter The function to call to fetch a decoded value + * + * Example: + * @code + * + * static uint8_t object_nameC_keyid3_protoinfo[] = { + * 0x00, 0x02, 0x00, 110, // ver = 0, type = object, length = 110 + * 0x00, 0x00, 0x00, 5, // reserved = 0, header length = 5 + * // --------------------------- + * // snip middle of packet + * // ------------------------ + * // byte offset = 117 + * 0x00, 0x05, 0x00, 0x06, // signature block, length = 6 + * 0x00, 0x0E, 0x00, 0x02, // signature bits, length = 2 + * 0xBE, 0xEF // value = 0xBEEF + * }; + * + * static TruthTableEntry TRUTHTABLENAME(object_nameC_keyid3_protoinfo)[] = { + * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_SIGBLOCK, .bodyManifest=true, .extent = {117, 6} }, + * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_SIGBITS, .bodyManifest=true, .extent = {121, 2} }, + * { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0} }, + * }; + * + * LONGBOW_TEST_FIXTURE_SETUP(Global) + * { + * commonSetup(testCase, object_nameC_keyid3_protoinfo, sizeof(object_nameC_keyid3_protoinfo), object_nameC_keyid3_protoinfo_truthTableEntries, MANIFEST_OBJ_SIGBLOCK); + * return LONGBOW_STATUS_SUCCEEDED; + * } + * + * LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV0SigBlock_GetSignatureBits) + * { + * testBufferGetter(testCase, MANIFEST_OBJ_SIGBITS, ccnxCodecSchemaV0SigBlock_Decode, ccnxCodecSchemaV0SigBlock_GetSignatureBits); + * } + * + * @endcode + */ +void +testBufferGetter(TestData *data, int truthTableKey, bool containerDecoder(CCNxCodecTlvDecoder *, CCNxTlvDictionary *), + PARCBuffer *(*getter)(const CCNxTlvDictionary *)) +{ + containerDecoder(data->decoder, data->dictionary); + PARCBuffer *test = getter(data->dictionary); + + // look up the true name buffer from the truth table + TlvExtent extent = getTruthTableExtent(data->truthTable, truthTableKey); + PARCBuffer *truth = parcBuffer_Wrap(data->packet, data->packetLength, extent.offset, extent.offset + extent.length); + + assertTrue(parcBuffer_Equals(test, truth), "Buffers not equal") + { + printf("Expected:\n"); + parcBuffer_Display(truth, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); +} + +void +testHashGetter(TestData *data, int truthTableKey, bool containerDecoder(CCNxCodecTlvDecoder *, CCNxTlvDictionary *), + PARCCryptoHash *(*getter)(CCNxTlvDictionary *)) +{ + containerDecoder(data->decoder, data->dictionary); + PARCCryptoHash *testHash = getter(data->dictionary); + + // look up the true hash buffer from the truth table + TlvExtent extent = getTruthTableExtent(data->truthTable, truthTableKey); + PARCBuffer *truthBuffer = parcBuffer_Wrap(data->packet, data->packetLength, extent.offset, extent.offset + extent.length); + + // decode the hash value + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(truthBuffer); + PARCCryptoHash *truthHash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, extent.length); + ccnxCodecTlvDecoder_Destroy(&decoder); + + // compare the decoded value against the expected value + assertTrue(parcCryptoHash_Equals(testHash, truthHash), "Hashes not equal") + { + printf("Expected:\n"); + printf(" %s\n", parcBuffer_ToHexString(parcCryptoHash_GetDigest(truthHash))); + printf("Got:\n"); + printf(" %s\n", parcBuffer_ToHexString(parcCryptoHash_GetDigest(testHash))); + } + + parcCryptoHash_Release(&truthHash); + parcBuffer_Release(&truthBuffer); +} + +void +testNameGetter(TestData *data, int truthTableKey, bool containerDecoder(CCNxCodecTlvDecoder *, CCNxTlvDictionary *), + CCNxName *(*getter)(CCNxTlvDictionary *)) +{ + containerDecoder(data->decoder, data->dictionary); + CCNxName *test = getter(data->dictionary); + + // look up the true name buffer from the truth table + TlvExtent extent = getTruthTableExtent(data->truthTable, truthTableKey); + + // we need to backup 4 bytes to get the TLV container + PARCBuffer *truthBuffer = + parcBuffer_Wrap(data->packet, data->packetLength, extent.offset - 4, extent.offset + extent.length); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(truthBuffer); + CCNxName *truthName = ccnxCodecSchemaV1NameCodec_Decode(decoder, CCNxCodecSchemaV1Types_CCNxMessage_Name); + ccnxCodecTlvDecoder_Destroy(&decoder); + + assertTrue(ccnxName_Equals(test, truthName), "Names not equal") + { + printf("Expected:\n"); + ccnxName_Display(truthName, 3); + printf("Got:\n"); + ccnxName_Display(test, 3); + } + + ccnxName_Release(&truthName); + parcBuffer_Release(&truthBuffer); +} + +void +testMissingInt32Getter(LongBowTestCase *testCase, int32_t (*getter)(CCNxTlvDictionary *)) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + int32_t test = getter(data->dictionary); + + assertTrue(test == -1, "Wrong value, got %d expected %d", test, -1); +} + +/** + * Tried to retrieve execute the getter on the dictionary and ensures that + * the field is missing. + */ +void +testMissingInt64Getter(LongBowTestCase *testCase, int64_t (*getter)(CCNxTlvDictionary *)) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + int64_t test = getter(data->dictionary); + + assertTrue(test == -1, "Wrong value, got %" PRId64 " expected %d", test, -1); +} + +/** + * Tried to retrieve execute the getter on the dictionary and ensures that + * the field is missing. + */ +void +testMissingNameGetter(LongBowTestCase *testCase, CCNxName *(*getter)(CCNxTlvDictionary *)) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxName *test = getter(data->dictionary); + + assertNull(test, "Should have gotten null for missing field, got %p", (void *) test); +} + +/** + * Tried to retrieve execute the getter on the dictionary and ensures that + * the field is missing. + */ +void +testMissingBufferGetter(LongBowTestCase *testCase, PARCBuffer *(*getter)(CCNxTlvDictionary *)) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *test = getter(data->dictionary); + + assertNull(test, "Should have gotten null for missing field, got %p", (void *) test); +} + +/** + * Tried to retrieve execute the getter on the dictionary and ensures that + * the field is missing. + */ +void +testMissingDictionaryGetter(LongBowTestCase *testCase, CCNxTlvDictionary *(*getter)(CCNxTlvDictionary *)) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxTlvDictionary *test = getter(data->dictionary); + + assertNull(test, "Should have gotten null for missing field, got %p", (void *) test); +} |