diff options
author | Luca Muscariello <lumuscar+fdio@cisco.com> | 2017-02-23 20:44:26 +0100 |
---|---|---|
committer | Luca Muscariello <lumuscar+fdio@cisco.com> | 2017-02-23 19:51:14 +0000 |
commit | d18ae43123fcd7604d1c36a1ec8450dbe6071824 (patch) | |
tree | 2d49fc3aabd0f2607251c854565648d47b56b2e9 /libccnx-common/ccnx/common/codec/test | |
parent | 9b30fc10fb1cbebe651e5a107e8ca5b24de54675 (diff) |
Initial commit: ccnxlibs.
Change-Id: I1b376527a7dd01a6b9e083a6cb646955902f45c0
Signed-off-by: Luca Muscariello <lumuscar+fdio@cisco.com>
Diffstat (limited to 'libccnx-common/ccnx/common/codec/test')
14 files changed, 4195 insertions, 0 deletions
diff --git a/libccnx-common/ccnx/common/codec/test/.gitignore b/libccnx-common/ccnx/common/codec/test/.gitignore new file mode 100644 index 00000000..f0d97bc9 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/test/.gitignore @@ -0,0 +1,7 @@ +test_ccnxCodec_EncodingBuffer +test_ccnxCodec_Error +test_ccnxCodec_NetworkBuffer +test_ccnxCodec_TlvDecoder +test_ccnxCodec_TlvEncoder +test_ccnxCodec_TlvPacket +test_ccnxCodec_TlvUtilities diff --git a/libccnx-common/ccnx/common/codec/test/CMakeLists.txt b/libccnx-common/ccnx/common/codec/test/CMakeLists.txt new file mode 100644 index 00000000..73dd544e --- /dev/null +++ b/libccnx-common/ccnx/common/codec/test/CMakeLists.txt @@ -0,0 +1,24 @@ +# Enable gcov output for the tests +add_definitions(--coverage) +set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage") + +configure_file(test_rsa.p12 test_rsa.p12 COPYONLY) +configure_file(test_random_bytes test_random_bytes COPYONLY) +configure_file(test_random_bytes.sig test_random_bytes.sig COPYONLY) +configure_file(test_rsa_key.pem test_rsa_key.pem COPYONLY) + +set(TestsExpectedToPass + test_ccnxCodec_EncodingBuffer + test_ccnxCodec_Error + test_ccnxCodec_NetworkBuffer + test_ccnxCodec_TlvDecoder + test_ccnxCodec_TlvEncoder + test_ccnxCodec_TlvPacket + test_ccnxCodec_TlvUtilities +) + + +foreach(test ${TestsExpectedToPass}) + AddTest(${test}) +endforeach() + diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_EncodingBuffer.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_EncodingBuffer.c new file mode 100755 index 00000000..33bdbbc7 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_EncodingBuffer.c @@ -0,0 +1,343 @@ +/* + * 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 "../ccnxCodec_EncodingBuffer.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +typedef struct test_data { + CCNxCodecEncodingBuffer *encodingBuffer; +} TestData; + +static TestData * +_commonSetup(void) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + data->encodingBuffer = ccnxCodecEncodingBuffer_Create(); + return data; +} + +static void +_commonTeardown(TestData *data) +{ + ccnxCodecEncodingBuffer_Release(&data->encodingBuffer); + parcMemory_Deallocate((void **) &data); +} + +LONGBOW_TEST_RUNNER(ccnxCodec_EncodingBuffer) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodec_EncodingBuffer) +{ + 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(ccnxCodec_EncodingBuffer) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_AppendBuffer_FirstAppend); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_AppendBuffer_SameArray); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_AppendBuffer_SecondArray); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_Create); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_CreateIOVec); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_CreateIOVec_Empty); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_Display); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_Length); +} + +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; +} + +LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_AppendBuffer_FirstAppend) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *buffer = parcBuffer_Wrap("hello", 5, 0, 5); + size_t position = ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer); + assertTrue(position == 0, "Wrong position, got %zu expected %d", position, 0); + + _ccnxCodecEncodingBuffer_Validate(data->encodingBuffer); + assertTrue(data->encodingBuffer->totalCount == 1, "Wrong count, got %u expected %u", data->encodingBuffer->totalCount, 1); + assertTrue(data->encodingBuffer->totalBytes == 5, "Wrong bytes, got %zu expected %u", data->encodingBuffer->totalBytes, 5); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_AppendBuffer_SameArray) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *buffer = parcBuffer_Wrap("hello", 5, 0, 5); + + // do two appends + ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer); + size_t position = ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer); + assertTrue(position == 1, "Wrong position, got %zu expected %d", position, 1); + + _ccnxCodecEncodingBuffer_Validate(data->encodingBuffer); + assertTrue(data->encodingBuffer->totalCount == 2, "Wrong count, got %u expected %u", data->encodingBuffer->totalCount, 2); + assertTrue(data->encodingBuffer->totalBytes == 10, "Wrong bytes, got %zu expected %u", data->encodingBuffer->totalBytes, 10); + + // should still be in the first listarray + assertTrue(data->encodingBuffer->head == data->encodingBuffer->tail, "Head != tail") + { + ccnxCodecEncodingBuffer_Display(data->encodingBuffer, 0); + } + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_AppendBuffer_SecondArray) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *buffer = parcBuffer_Wrap("hello", 5, 0, 5); + + ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer); + + // now fake out the list array so it thinks its full. + // Do this by reducing the capacity so there are no undefined buffers on the list + data->encodingBuffer->head->capacity = data->encodingBuffer->head->count; + + size_t position = ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer); + assertTrue(position == 1, "Wrong position, got %zu expected %u", position, 1); + + _ccnxCodecEncodingBuffer_Validate(data->encodingBuffer); + assertTrue(data->encodingBuffer->totalCount == 2, "Wrong count, got %u expected %u", data->encodingBuffer->totalCount, 2); + assertTrue(data->encodingBuffer->totalBytes == 10, "Wrong bytes, got %zu expected %u", data->encodingBuffer->totalBytes, 10); + + // should now have different head and tail + assertTrue(data->encodingBuffer->head != data->encodingBuffer->tail, "Head == tail") + { + ccnxCodecEncodingBuffer_Display(data->encodingBuffer, 0); + } + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_Create) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + assertNotNull(data->encodingBuffer, "Got null buffer from create"); + assertNull(data->encodingBuffer->head, "buffer head is not null"); + assertNull(data->encodingBuffer->tail, "Buffer tail is not null"); + assertTrue(data->encodingBuffer->totalCount == 0, "Buffer itemCount is not 0"); + assertTrue(data->encodingBuffer->totalBytes == 0, "Buffer totalBytes is not 0"); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_CreateIOVec) +{ + char foo[] = "foo"; + char bar[] = "barbar"; + + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *buffer_1 = parcBuffer_Wrap(foo, sizeof(foo), 0, sizeof(foo)); + PARCBuffer *buffer_2 = parcBuffer_Wrap(bar, sizeof(bar), 0, sizeof(bar)); + ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer_2); + ccnxCodecEncodingBuffer_PrependBuffer(data->encodingBuffer, buffer_1); + + CCNxCodecEncodingBufferIOVec *iov = ccnxCodecEncodingBuffer_CreateIOVec(data->encodingBuffer); + assertNotNull(iov, "Got null iov from CreateIOVec"); + assertTrue(iov->iovcnt == 2, "Wrong iovec count, got %d expected %d", iov->iovcnt, 2); + assertTrue(iov->iov[0].iov_base == foo, "WRong iov[0].iov_base, got %p exected %p", iov->iov[0].iov_base, foo); + assertTrue(iov->iov[1].iov_base == bar, "WRong iov[1].iov_base, got %p exected %p", iov->iov[1].iov_base, bar); + assertTrue(iov->iov[0].iov_len == sizeof(foo), "WRong iov[1].iov_base, got %zu exected %zu", iov->iov[0].iov_len, sizeof(foo)); + assertTrue(iov->iov[1].iov_len == sizeof(bar), "WRong iov[1].iov_base, got %zu exected %zu", iov->iov[1].iov_len, sizeof(bar)); + + // Slice crossing two iovec arrays + CCNxCodecEncodingBuffer *bufferSlice = ccnxCodecEncodingBuffer_Slice(data->encodingBuffer, 1, 6); + CCNxCodecEncodingBufferIOVec *iovSlice = ccnxCodecEncodingBuffer_CreateIOVec(bufferSlice); + assertTrue(iovSlice->iovcnt == 2, "Wrong iovec count, got %d expected %d", iovSlice->iovcnt, 2); + assertTrue(iovSlice->iov[0].iov_base == foo + 1, "WRong iovSlice[0].iov_base, got %p exected %p", iovSlice->iov[0].iov_base, foo + 1); + assertTrue(iovSlice->iov[0].iov_len == sizeof(foo) - 1, "WRong iovSlice[1].iov_len, got %zu exected %zu", iovSlice->iov[0].iov_len, sizeof(foo) - 1); + assertTrue(iovSlice->iov[1].iov_len == 6 - (sizeof(foo) - 1), "WRong iovSlice[1].iov_base, got %zu exected %lu", iovSlice->iov[1].iov_len, 6 - (sizeof(foo) - 1)); + ccnxCodecEncodingBufferIOVec_Release(&iovSlice); + ccnxCodecEncodingBuffer_Release(&bufferSlice); + + // Slice within one iovec array + bufferSlice = ccnxCodecEncodingBuffer_Slice(data->encodingBuffer, 1, 1); + iovSlice = ccnxCodecEncodingBuffer_CreateIOVec(bufferSlice); + assertTrue(iovSlice->iovcnt == 1, "Wrong iovec count, got %d expected %d", iovSlice->iovcnt, 1); + assertTrue(iovSlice->iov[0].iov_base == foo + 1, "WRong iovSlice[0].iov_base, got %p exected %p", iovSlice->iov[0].iov_base, foo + 1); + assertTrue(iovSlice->iov[0].iov_len == 1, "WRong iovSlice[1].iov_len, got %zu exected %d", iovSlice->iov[0].iov_len, 1); + ccnxCodecEncodingBufferIOVec_Release(&iovSlice); + ccnxCodecEncodingBuffer_Release(&bufferSlice); + + // Slice beyond contents + bufferSlice = ccnxCodecEncodingBuffer_Slice(data->encodingBuffer, sizeof(foo) + sizeof(bar), 1); + assertNull(bufferSlice, "ccnxCodecEncodingBuffer_Slice returned allocation for slice outside of buffer"); + + // Slice including all and beyond + bufferSlice = ccnxCodecEncodingBuffer_Slice(data->encodingBuffer, 0, sizeof(foo) + sizeof(bar) + 10); + iovSlice = ccnxCodecEncodingBuffer_CreateIOVec(bufferSlice); + assertTrue(iovSlice->iovcnt == 2, "Wrong iovec count, got %d expected %d", iovSlice->iovcnt, 2); + assertTrue(iovSlice->iov[0].iov_base == foo, "WRong iovSlice[0].iov_base, got %p exected %p", iovSlice->iov[0].iov_base, foo); + assertTrue(iovSlice->iov[0].iov_len == sizeof(foo), "WRong iovSlice[1].iov_len, got %zu exected %zu", iovSlice->iov[0].iov_len, sizeof(foo)); + assertTrue(iovSlice->iov[1].iov_len == sizeof(bar), "WRong iovSlice[1].iov_base, got %zu exected %lu", iovSlice->iov[1].iov_len, sizeof(bar)); + ccnxCodecEncodingBufferIOVec_Release(&iovSlice); + ccnxCodecEncodingBuffer_Release(&bufferSlice); + + ccnxCodecEncodingBufferIOVec_Release(&iov); + + parcBuffer_Release(&buffer_1); + parcBuffer_Release(&buffer_2); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_CreateIOVec_Empty) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxCodecEncodingBufferIOVec *iov = ccnxCodecEncodingBuffer_CreateIOVec(data->encodingBuffer); + assertNotNull(iov, "Got null iov from CreateIOVec"); + assertTrue(iov->iovcnt == 0, "Wrong iovec count, got %d expected %d", iov->iovcnt, 0); + + // single allocation means that the iov will never be null + assertNotNull(iov->iov, "iov->iov should not be null"); + + ccnxCodecEncodingBufferIOVec_Release(&iov); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_Display) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *buffer = parcBuffer_Wrap("hello", 5, 0, 5); + ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer); + parcBuffer_Release(&buffer); + + ccnxCodecEncodingBuffer_Display(data->encodingBuffer, 0); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_Length) +{ + char foo[] = "foo"; + char bar[] = "barbar"; + + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *buffer_1 = parcBuffer_Wrap(foo, sizeof(foo), 0, sizeof(foo)); + PARCBuffer *buffer_2 = parcBuffer_Wrap(bar, sizeof(bar), 0, sizeof(bar)); + ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer_1); + ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer_2); + + size_t length = ccnxCodecEncodingBuffer_Length(data->encodingBuffer); + size_t truth = sizeof(foo) + sizeof(bar); + assertTrue(length == truth, "Wrong length, got %zu expected %zu", length, truth); + + parcBuffer_Release(&buffer_1); + parcBuffer_Release(&buffer_2); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_Size) +{ + char foo[] = "foo"; + char bar[] = "barbar"; + + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *buffer_1 = parcBuffer_Wrap(foo, sizeof(foo), 0, sizeof(foo)); + PARCBuffer *buffer_2 = parcBuffer_Wrap(bar, sizeof(bar), 0, sizeof(bar)); + ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer_1); + ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer_2); + + size_t size = ccnxCodecEncodingBuffer_Size(data->encodingBuffer); + assertTrue(size == 2, "Wrong size, got %zu expected %u", size, 2); + + parcBuffer_Release(&buffer_1); + parcBuffer_Release(&buffer_2); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_Example) +{ + PARCBuffer *name = parcBuffer_Wrap("marc", 4, 0, 4); + PARCBuffer *space = parcBuffer_Wrap(" ", 1, 0, 1); + PARCBuffer *email = parcBuffer_Wrap("<marc@example.com>", 18, 0, 18); + + CCNxCodecEncodingBuffer *encodingBuffer = ccnxCodecEncodingBuffer_Create(); + ccnxCodecEncodingBuffer_AppendBuffer(encodingBuffer, name); + ccnxCodecEncodingBuffer_AppendBuffer(encodingBuffer, space); + parcBuffer_Release(&space); + parcBuffer_Release(&name); + + CCNxCodecEncodingBuffer *emailBuffer = ccnxCodecEncodingBuffer_Create(); + ccnxCodecEncodingBuffer_AppendBuffer(emailBuffer, email); + parcBuffer_Release(&email); + + ccnxCodecEncodingBuffer_Release(&emailBuffer); + + CCNxCodecEncodingBufferIOVec *iov = ccnxCodecEncodingBuffer_CreateIOVec(encodingBuffer); + ssize_t nwritten = writev(STDOUT_FILENO, iov->iov, iov->iovcnt); + assertTrue(nwritten > -1, "Error writev"); + + ccnxCodecEncodingBufferIOVec_Release(&iov); + + ccnxCodecEncodingBuffer_Release(&encodingBuffer); +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +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; +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodec_EncodingBuffer); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_Error.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_Error.c new file mode 100755 index 00000000..1fee88c3 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_Error.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 "../ccnxCodec_Error.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(tlv_Errors) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(tlv_Errors) +{ + 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(tlv_Errors) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecError_Create_Destroy); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecError_GetByteOffset); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecError_GetErrorCode); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecError_GetLine); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecError_GetFunction); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecError_GetErrorMessage); +} + +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, ccnxCodecError_Create_Destroy) +{ + CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_NO_ERROR, "apple", 10, 100); + ccnxCodecError_Release(&error); + assertTrue(parcMemory_Outstanding() == 0, "memory imbalance after create/destroy"); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecError_GetByteOffset) +{ + CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_NO_ERROR, "apple", 10, 100); + assertTrue(ccnxCodecError_GetByteOffset(error) == 100, + "Wrong offset, expected %u got %zu", + 100, + ccnxCodecError_GetByteOffset(error)); + ccnxCodecError_Release(&error); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecError_GetErrorCode) +{ + CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_NO_ERROR, "apple", 10, 100); + assertTrue(ccnxCodecError_GetErrorCode(error) == TLV_ERR_NO_ERROR, + "Wrong error code, expected %d got %d", + TLV_ERR_NO_ERROR, + ccnxCodecError_GetErrorCode(error)); + ccnxCodecError_Release(&error); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecError_GetLine) +{ + CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_NO_ERROR, "apple", 10, 100); + assertTrue(ccnxCodecError_GetLine(error) == 10, + "Wrong line number, expected %d got %d", + 10, + ccnxCodecError_GetLine(error)); + ccnxCodecError_Release(&error); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecError_GetFunction) +{ + char *apple = "apple"; + + CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_NO_ERROR, apple, 10, 100); + assertTrue(ccnxCodecError_GetFunction(error) == apple, + "Wrong function string, expected %p got %p", + apple, + ccnxCodecError_GetFunction(error)); + ccnxCodecError_Release(&error); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecError_GetErrorMessage) +{ + char *apple = "apple"; + const char *truth = ccnxCodecErrors_ErrorMessage(TLV_ERR_NO_ERROR); + + CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_NO_ERROR, apple, 10, 100); + assertTrue(ccnxCodecError_GetErrorMessage(error) == truth, + "Wrong function string, expected %p got %p", + truth, + ccnxCodecError_GetErrorMessage(error)); + ccnxCodecError_Release(&error); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(tlv_Errors); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_NetworkBuffer.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_NetworkBuffer.c new file mode 100755 index 00000000..aec3018e --- /dev/null +++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_NetworkBuffer.c @@ -0,0 +1,952 @@ +/* + * 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 "../ccnxCodec_NetworkBuffer.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <arpa/inet.h> + +#include <parc/security/parc_Security.h> +#include <parc/security/parc_Pkcs12KeyStore.h> +#include <parc/security/parc_PublicKeySigner.h> + +typedef struct test_data { + CCNxCodecNetworkBuffer *buffer; +} TestData; + +static TestData * +_commonSetup(void) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + data->buffer = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL); + return data; +} + +static void +_commonTeardown(TestData *data) +{ + ccnxCodecNetworkBuffer_Release(&data->buffer); + parcMemory_Deallocate((void **) &data); +} + +LONGBOW_TEST_RUNNER(ccnx_NetworkBuffer) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); + LONGBOW_RUN_TEST_FIXTURE(SetLimit); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnx_NetworkBuffer) +{ + 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(ccnx_NetworkBuffer) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBufferIoVec_Acquire); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_Acquire); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_ComputeSignature); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_Create); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_CreateFromArray); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_CreateIoVec); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_Display); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_GetUint8); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_GetUint8_NotCurrentBlock); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_Position); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_SpaceOk); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_SpaceToZero); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_NoSpace); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_SpanThree); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutBuffer); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint16); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint64); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint8_SpaceOk); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint8_SpaceToZero); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint8_NoSpace); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint32_OK); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint32_2bytes); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint32_2bytes_withnext); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_SetPosition_BeyondLimit); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_SetPosition_InCurrent); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_SetPosition_InDifferent); + + LONGBOW_RUN_TEST_CASE(Global, ccnxNetworkbufferIoVec_GetArray); + LONGBOW_RUN_TEST_CASE(Global, ccnxNetworkbufferIoVec_GetCount); + LONGBOW_RUN_TEST_CASE(Global, ccnxNetworkbufferIoVec_Length); + LONGBOW_RUN_TEST_CASE(Global, ccnxNetworkbufferIoVec_Display); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + longBowTestCase_SetClipBoardData(testCase, _commonSetup()); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + _commonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + 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, ccnxCodecNetworkBufferIoVec_Acquire) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxCodecNetworkBufferIoVec *first = ccnxCodecNetworkBuffer_CreateIoVec(data->buffer); + assertTrue(first->refcount == 1, "Wrong refcount, got %u expected %u", first->refcount, 1); + + CCNxCodecNetworkBufferIoVec *second = ccnxCodecNetworkBufferIoVec_Acquire(first); + assertTrue(first->refcount == 2, "Wrong refcount, got %u expected %u", first->refcount, 2); + + ccnxCodecNetworkBufferIoVec_Release(&second); + ccnxCodecNetworkBufferIoVec_Release(&first); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_Acquire) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxCodecNetworkBuffer *second = ccnxCodecNetworkBuffer_Acquire(data->buffer); + assertTrue(data->buffer->refcount == 2, "wrong refcount, got %u expected %u", data->buffer->refcount, 2); + ccnxCodecNetworkBuffer_Release(&second); + assertTrue(data->buffer->refcount == 1, "wrong refcount, got %u expected %u", data->buffer->refcount, 1); +} + +/* + * Uses a test set generated by openssl: + * openssl genrsa -out test_rsa_key.pem + * openssl rsa -pubout -in test_rsa_key.pem -out test_rsa_pub.pem + * openssl req -new -key test_rsa_key.pem -out test_rsa.csr + * openssl x509 -req -days 365 -in test_rsa.csr -signkey test_rsa_key.pem -out test_rsa.crt + * openssl pkcs12 -export -in test_rsa.crt -inkey test_rsa_key.pem -out test_rsa.p12 -name ccnxuser -CAfile test_rsa.crt -caname root -chain -passout pass:blueberry + * openssl sha -sha256 -sign test_rsa_key.pem -out test_random_bytes.sig < test_random_bytes + * + * In English: generate a public private key, put it in a PKCS12 file (test_rsa.p12), then use that to sign + * a buffer (test_random_bytes) and put the signature in a file (test_random_bytes.sig). + */ +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_ComputeSignature) +{ + parcSecurity_Init(); + + PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_rsa.p12", "blueberry", PARCCryptoHashType_SHA256); + PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); + parcPkcs12KeyStore_Release(&publicKeyStore); + PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256); + PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); + parcPublicKeySigner_Release(&publicKeySigner); + + parcKeyStore_Release(&keyStore); + assertNotNull(signer, "Got null result from opening openssl pkcs12 file"); + + // read the buffer to sign + int fd = open("test_random_bytes", O_RDONLY); + assertTrue(fd != -1, "Cannot open test_random_bytes file."); + uint8_t buffer_to_sign[2048]; + ssize_t read_bytes = read(fd, buffer_to_sign, 2048); + close(fd); + + // Put it in a NetworkBuffer + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecNetworkBuffer_PutArray(data->buffer, read_bytes, buffer_to_sign); + + // Sign it + PARCSignature *testSignature = ccnxCodecNetworkBuffer_ComputeSignature(data->buffer, 0, ccnxCodecNetworkBuffer_Limit(data->buffer), signer); + PARCBuffer *testBytes = parcSignature_GetSignature(testSignature); + + // now read the "true" signature + uint8_t scratch_buffer[1024]; + fd = open("test_random_bytes.sig", O_RDONLY); + assertTrue(fd != -1, "Cannot open test_random_bytes.sig file."); + read_bytes = read(fd, scratch_buffer, 1024); + assertTrue(read_bytes == 128, "read incorrect size signature from disk: %zu", read_bytes); + close(fd); + + PARCBuffer *truth = parcBuffer_Wrap(scratch_buffer, read_bytes, 0, read_bytes); + + assertTrue(parcBuffer_Equals(testBytes, truth), "Signatures do not match") + { + parcBuffer_Display(testBytes, 0); + parcBuffer_Display(truth, 0); + } + + parcBuffer_Release(&truth); + parcSignature_Release(&testSignature); + parcSigner_Release(&signer); + + parcSecurity_Fini(); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_Create) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + assertNotNull(data->buffer, "null buffer"); + assertTrue(data->buffer->head == data->buffer->current && data->buffer->current == data->buffer->tail, + "wrong pointers, head should equal current should equal tail"); + assertTrue(data->buffer->refcount == 1, "wrong refcount, got %u expected %u", data->buffer->refcount, 1); + assertTrue(data->buffer->position == 0, "wrong position, got %zu expected %u", data->buffer->position, 1); +} + + +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_CreateFromArray) +{ + size_t length = 64; + uint8_t *memory = parcMemory_Allocate(length); + assertNotNull(memory, "parcMemory_Allocate(%zu) returned NULL", length); + for (int i = 0; i < length; i++) { + memory[i] = i * 3; + } + + CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, length, memory); + + assertNotNull(netbuff, "Got null from createFromArray"); + + PARCBuffer *test = ccnxCodecNetworkBuffer_CreateParcBuffer(netbuff); + PARCBuffer *truth = parcBuffer_Wrap(memory, length, 0, length); + + assertTrue(parcBuffer_Equals(test, truth), "Buffers do not match") + { + ccnxCodecNetworkBuffer_Display(netbuff, 3); + parcBuffer_Display(test, 3); + parcBuffer_Display(truth, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxCodecNetworkBuffer_Release(&netbuff); +} + + +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_CreateIoVec) +{ + // Write an array that will span 3 blocks + TestData *data = longBowTestCase_GetClipBoardData(testCase); + size_t arrayLength = 8192; + uint8_t array[arrayLength]; + + // fill the array with stuff so we have a pattern that must match + for (size_t i = 0; i < arrayLength; i++) { + array[i] = i; + } + + ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array); + CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(data->buffer); + + assertTrue(vec->iovcnt == 5, "iovcnt wrong got %d expected %d", vec->iovcnt, 5); + assertTrue(vec->totalBytes == 8192, "Wrong total bytes, got %zu expected %u", vec->totalBytes, 8192) + { + ccnxCodecNetworkBufferIoVec_Display(vec, 3); + } + + ccnxCodecNetworkBufferIoVec_Release(&vec); +} + +/* + * not much to do excpet make sure there's no leaks or assertions + */ +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_Display) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecNetworkBuffer_Display(data->buffer, 0); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_Position) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->buffer->position = 22; + + size_t test = ccnxCodecNetworkBuffer_Position(data->buffer); + assertTrue(test == 22, "wrong position, got %zu expected %u", test, 22); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_SpaceOk) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint8_t array[] = { 1, 2, 3, 4, 5, 6 }; + size_t nextPosition = data->buffer->position + sizeof(array); + + ccnxCodecNetworkBuffer_PutArray(data->buffer, sizeof(array), array); + assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition); + assertTrue(memcmp(&data->buffer->current->memory[0], array, sizeof(array)) == 0, "wrong memory"); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_SpaceToZero) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint8_t array[] = { 1, 2, 3, 4, 5, 6 }; + + size_t startPosition = data->buffer->capacity - sizeof(array); + size_t nextPosition = startPosition + sizeof(array); + + data->buffer->position = startPosition; + + ccnxCodecNetworkBuffer_PutArray(data->buffer, sizeof(array), array); + assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition); + assertTrue(memcmp(&data->buffer->current->memory[startPosition], array, sizeof(array)) == 0, "wrong memory"); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_NoSpace) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint8_t array[] = { 1, 2, 3, 4, 5, 6 }; + + // 3 elements in the current block, 3 in the next block + size_t startPosition = data->buffer->capacity - 3; + size_t nextPosition = startPosition + sizeof(array); + + data->buffer->position = startPosition; + + ccnxCodecNetworkBuffer_PutArray(data->buffer, sizeof(array), array); + assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition); + assertTrue(memcmp(&data->buffer->head->memory[startPosition], array, 3) == 0, "wrong memory"); + assertTrue(memcmp(&data->buffer->tail->memory[0], array + 3, 3) == 0, "wrong memory"); + // and we should have a new buffer + assertTrue(data->buffer->head != data->buffer->tail, "head should not be equal to tail"); +} + + +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_SpanThree) +{ + // Write an array that will span 3 blocks + TestData *data = longBowTestCase_GetClipBoardData(testCase); + size_t arrayLength = 8192; + uint8_t array[arrayLength]; + + // fill the array with stuff so we have a pattern that must match + for (size_t i = 0; i < arrayLength; i++) { + array[i] = i; + } + + ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array); + + CCNxCodecNetworkBufferMemory *block = data->buffer->head; + size_t offset = 0; + while (offset < arrayLength) { + size_t remaining = (arrayLength - offset > block->capacity) ? block->capacity : arrayLength - offset; + assertTrue(memcmp(&block->memory[0], array + offset, remaining) == 0, "wrong memory"); + offset += remaining; + block = block->next; + } +} + +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutBuffer) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint8_t array[] = { 1, 2, 3, 4, 5, 6 }; + PARCBuffer *buffer = parcBuffer_Wrap(array, sizeof(array), 0, sizeof(array)); + + size_t nextPosition = data->buffer->position + sizeof(array); + + ccnxCodecNetworkBuffer_PutBuffer(data->buffer, buffer); + assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition); + assertTrue(memcmp(&data->buffer->current->memory[0], array, sizeof(array)) == 0, "wrong memory"); + + parcBuffer_Release(&buffer); +} + + +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint16) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + uint16_t value = 0x2587; + size_t nextPosition = data->buffer->position + sizeof(value); + + ccnxCodecNetworkBuffer_PutUint16(data->buffer, value); + assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition); + + uint16_t testValue = htons(value); + assertTrue(memcmp(&data->buffer->current->memory[0], &testValue, sizeof(testValue)) == 0, "wrong memory") + { + ccnxCodecNetworkBuffer_Display(data->buffer, 0); + } +} + +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint64) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + uint64_t value = 0xABCDEF0122334455; + size_t nextPosition = data->buffer->position + sizeof(value); + + ccnxCodecNetworkBuffer_PutUint64(data->buffer, value); + assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition); + + uint8_t truthValue[] = { 0xAB, 0xCD, 0xEF, 0x01, 0x22, 0x33, 0x44, 0x55 }; + assertTrue(memcmp(&data->buffer->current->memory[0], truthValue, sizeof(truthValue)) == 0, "wrong memory") + { + ccnxCodecNetworkBuffer_Display(data->buffer, 0); + } +} + +/* + * Put a uint32 in to a block with plenty of space + */ +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint32_OK) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + uint32_t value = 0xABCDEF01; + size_t nextPosition = data->buffer->position + 4; + + ccnxCodecNetworkBuffer_PutUint32(data->buffer, value); + assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition); + + uint32_t testValue = htonl(value); + assertTrue(memcmp(&data->buffer->current->memory[0], &testValue, sizeof(testValue)) == 0, "wrong memory") + { + ccnxCodecNetworkBuffer_Display(data->buffer, 0); + } +} + +/* + * The current block only has 2 bytes left and there is no next pointer. Should throw away + * those 2 bytes, allocate a new block, then write the whole thing there. + */ +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint32_2bytes) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + // set limit and position out to capacity -2 + data->buffer->current->limit = data->buffer->current->capacity - 2; + data->buffer->position = data->buffer->current->limit; + + uint32_t value = 0xABCDEF01; + size_t nextPosition = data->buffer->position + 4; + + ccnxCodecNetworkBuffer_PutUint32(data->buffer, value); + assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition); + + uint32_t testValue = htonl(value); + assertTrue(memcmp(&data->buffer->current->memory[0], &testValue, sizeof(testValue)) == 0, "wrong memory") + { + ccnxCodecNetworkBuffer_Display(data->buffer, 0); + } +} + +/* + * The current block only has 2 bytes left and there is a next block. Because the current + * block is frozen, it will need to split the write over the two blocks. + */ +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint32_2bytes_withnext) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + // this is where we'll want to start our write + size_t start = data->buffer->current->capacity - 2; + size_t nextPosition = start + 4; + + // set limit and position out to capacity then allocate another block + data->buffer->current->limit = data->buffer->current->capacity; + data->buffer->position = data->buffer->current->limit; + _ccnxCodecNetworkBuffer_AllocateIfNeeded(data->buffer); + + ccnxCodecNetworkBuffer_SetPosition(data->buffer, start); + uint32_t value = 0x33445566; + ccnxCodecNetworkBuffer_PutUint32(data->buffer, value); + assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition); + + uint32_t testValue = htonl(value); + // check the value is split between the two buffers + assertTrue(memcmp(&data->buffer->head->memory[start], &testValue, 2) == 0, "wrong memory in first buffer") + { + ccnxCodecNetworkBuffer_Display(data->buffer, 0); + } + + assertTrue(memcmp(&data->buffer->tail->memory[0], (uint8_t *) &testValue + 2, 2) == 0, "wrong memory in second buffer") + { + ccnxCodecNetworkBuffer_Display(data->buffer, 0); + } +} + +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_GetUint8) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + uint8_t value = 1; + + ccnxCodecNetworkBuffer_PutUint8(data->buffer, value); + + uint8_t test = ccnxCodecNetworkBuffer_GetUint8(data->buffer, 0); + assertTrue(data->buffer->current->memory[0] == test, "wrong memory, got %u expected %u", test, data->buffer->current->memory[0]); +} + +/* + * Write stuff that spans two blocks, then get the uint8 from the second block + */ +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_GetUint8_NotCurrentBlock) +{ + // Write an array that will span 5 blocks + TestData *data = longBowTestCase_GetClipBoardData(testCase); + size_t arrayLength = 8192; + uint8_t array[arrayLength]; + + // fill the array with stuff so we have a pattern that must match + for (size_t i = 0; i < arrayLength; i++) { + array[i] = i; + } + + ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array); + + uint8_t test = ccnxCodecNetworkBuffer_GetUint8(data->buffer, 4777); + assertTrue(test == array[4777], "Data at index 4777 wrong, got %02X expected %02X", + test, array[4777]); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint8_SpaceOk) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + uint8_t value = 1; + size_t relativePosition = data->buffer->position - data->buffer->current->begin; + size_t nextPosition = data->buffer->position + 1; + + ccnxCodecNetworkBuffer_PutUint8(data->buffer, value); + assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition); + assertTrue(data->buffer->current->memory[relativePosition] == value, "wrong memory"); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint8_SpaceToZero) +{ + // put the position to just before the end of the buffer + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + uint8_t value = 1; + + data->buffer->position = data->buffer->current->capacity - 1; + size_t relativePosition = data->buffer->position - data->buffer->current->begin; + size_t nextPosition = data->buffer->position + 1; + + ccnxCodecNetworkBuffer_PutUint8(data->buffer, value); + assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition); + assertTrue(data->buffer->current->memory[relativePosition] == value, "wrong memory"); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint8_NoSpace) +{ + // put the position at the end of the current buffer, force an allocation + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + uint8_t value = 1; + + // pretend we've written all the way out to the capacity + data->buffer->position = data->buffer->current->capacity; + data->buffer->current->limit = data->buffer->current->capacity; + + size_t nextPosition = data->buffer->position + 1; + + ccnxCodecNetworkBuffer_PutUint8(data->buffer, value); + + size_t relativePosition = 0; + + assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition); + assertTrue(data->buffer->current->memory[relativePosition] == value, "wrong memory"); + // and we should have a new buffer + assertTrue(data->buffer->head != data->buffer->tail, "head should not be equal to tail"); +} + +/* + * Set position beyond the limit of what's been written + */ +LONGBOW_TEST_CASE_EXPECTS(Global, ccnxCodecNetworkBuffer_SetPosition_BeyondLimit, .event = &LongBowAssertEvent) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + size_t limit = ccnxCodecNetworkBuffer_Limit(data->buffer); + ccnxCodecNetworkBuffer_SetPosition(data->buffer, limit + 1); +} + +/* + * Set position to good location that is in the current block + */ +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_SetPosition_InCurrent) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecNetworkBuffer_PutUint32(data->buffer, 0x12345678); + + size_t limit = ccnxCodecNetworkBuffer_Limit(data->buffer); + ccnxCodecNetworkBuffer_SetPosition(data->buffer, limit - 1); + + assertTrue(data->buffer->current->memory[data->buffer->position] == 0x78, + "Wrong memory got %02X expected %02X", + data->buffer->current->memory[data->buffer->position], 0x78) + { + ccnxCodecNetworkBuffer_Display(data->buffer, 0); + } +} + +/* + * Set position to a good location that is not in the current block + */ +LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_SetPosition_InDifferent) +{ + // Write an array that will span 5 blocks + TestData *data = longBowTestCase_GetClipBoardData(testCase); + size_t arrayLength = 8192; + uint8_t array[arrayLength]; + + // fill the array with stuff so we have a pattern that must match + for (size_t i = 0; i < arrayLength; i++) { + array[i] = i; + } + + ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array); + + ccnxCodecNetworkBuffer_SetPosition(data->buffer, 4777); + + assertTrue(data->buffer->position == 4777, "Wrong position set, got %zu expected %u", data->buffer->position, 4777); + assertTrue(_ccnxCodecNetworkBufferMemory_ContainsPosition(data->buffer->current, 4777), "Did not seek to right position"); +} + +LONGBOW_TEST_CASE(Global, ccnxNetworkbufferIoVec_GetArray) +{ + // Write an array that will span 3 blocks + TestData *data = longBowTestCase_GetClipBoardData(testCase); + size_t arrayLength = 8192; + uint8_t array[arrayLength]; + + // fill the array with stuff so we have a pattern that must match + for (size_t i = 0; i < arrayLength; i++) { + array[i] = i; + } + + ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array); + CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(data->buffer); + + const struct iovec *iov = ccnxCodecNetworkBufferIoVec_GetArray(vec); + assertTrue(iov == vec->array, "Got wrong iovec array, got %p expected %p", (void *) iov, (void *) vec->array); + + ccnxCodecNetworkBufferIoVec_Release(&vec); +} + +LONGBOW_TEST_CASE(Global, ccnxNetworkbufferIoVec_GetCount) +{ + // Write an array that will span 3 blocks + TestData *data = longBowTestCase_GetClipBoardData(testCase); + size_t arrayLength = 8192; + uint8_t array[arrayLength]; + + // fill the array with stuff so we have a pattern that must match + for (size_t i = 0; i < arrayLength; i++) { + array[i] = i; + } + + ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array); + CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(data->buffer); + + assertTrue(ccnxCodecNetworkBufferIoVec_GetCount(vec) == 5, "iovcnt wrong got %d expected %d", ccnxCodecNetworkBufferIoVec_GetCount(vec), 5); + + ccnxCodecNetworkBufferIoVec_Release(&vec); +} + +LONGBOW_TEST_CASE(Global, ccnxNetworkbufferIoVec_Length) +{ + // Write an array that will span 3 blocks + TestData *data = longBowTestCase_GetClipBoardData(testCase); + size_t arrayLength = 8192; + uint8_t array[arrayLength]; + + // fill the array with stuff so we have a pattern that must match + for (size_t i = 0; i < arrayLength; i++) { + array[i] = i; + } + + ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array); + CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(data->buffer); + + assertTrue(ccnxCodecNetworkBufferIoVec_Length(vec) == arrayLength, "Wrong length got %zu expected %zu", ccnxCodecNetworkBufferIoVec_Length(vec), arrayLength); + + ccnxCodecNetworkBufferIoVec_Release(&vec); +} + +LONGBOW_TEST_CASE(Global, ccnxNetworkbufferIoVec_Display) +{ + // Write an array that will span 3 blocks + TestData *data = longBowTestCase_GetClipBoardData(testCase); + size_t arrayLength = 8192; + uint8_t array[arrayLength]; + + // fill the array with stuff so we have a pattern that must match + for (size_t i = 0; i < arrayLength; i++) { + array[i] = i; + } + + ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array); + CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(data->buffer); + + ccnxCodecNetworkBufferIoVec_Display(vec, 0); + + ccnxCodecNetworkBufferIoVec_Release(&vec); +} + +// ===================================================================== + +LONGBOW_TEST_FIXTURE(SetLimit) +{ + LONGBOW_RUN_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_EndOfTail); + LONGBOW_RUN_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_MidOfTail); + LONGBOW_RUN_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_StartOfTail); + LONGBOW_RUN_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_EndOfMid); + LONGBOW_RUN_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_MidOfMid); + LONGBOW_RUN_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_StartOfMid); + LONGBOW_RUN_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_Zero); +} + +LONGBOW_TEST_FIXTURE_SETUP(SetLimit) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(SetLimit) +{ + 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; +} + +typedef struct setlimit_s { + CCNxCodecNetworkBuffer *netbuff; + PARCBuffer *truth; +} SetLimitData; + +/* + * In this test, SetLimit is called when we are at position 4036 + * + * (always in ABSOLUTE bytes) + * position = 4077 + * begin = 0 begin = 1536 begin = 3577 | + * | | | | + * +--------------------------+--------------------------+--------------------------+ + * | block 0 | block 1 | block 2 | + * +--------------------------+--------------------------+--------------------------+ + * | | | | + * capacity = 1536 capacity = 2048 | capacity = 2048 + * limit = 1536 limit = 2041 limit = 500 + * (always in RELATIVE bytes) + */ +static SetLimitData +_allocateData(void) +{ + SetLimitData data; + + data.netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL); + + size_t buffer1_length = 3577; + uint8_t buffer1[buffer1_length]; + memset(buffer1, 0x11, buffer1_length); + + ccnxCodecNetworkBuffer_PutArray(data.netbuff, buffer1_length, buffer1); + assertTrue(data.netbuff->position == buffer1_length, "Wrong position, expected %zu got %zu", buffer1_length, data.netbuff->position); + + // we should be in 'block1' in the diagram + assertTrue(data.netbuff->current->limit == 2041, "wrong limit, expected %u got %zu", 2041, data.netbuff->current->limit); + + // now allocate the second buffer to move to 'block 2'. this should freeze 'block 1' at 2000 bytes. + + // now we need to write it at 8 bytes to get block 1 to freeze + uint64_t x = 0x1234567812345678ULL; + + ccnxCodecNetworkBuffer_PutUint64(data.netbuff, x); + assertTrue(data.netbuff->position == 3585, "Wrong position, expected %u got %zu", 3585, data.netbuff->position); + assertTrue(data.netbuff->current->limit == 8, "wrong limit, expected %u got %zu", 8, data.netbuff->current->limit); + + size_t buffer2_length = 492; + uint8_t buffer2[buffer2_length]; + memset(buffer2, 0xaa, buffer2_length); + + ccnxCodecNetworkBuffer_PutArray(data.netbuff, buffer2_length, buffer2); + + assertTrue(data.netbuff->position == 4077, "Wrong position, expected %u got %zu", 4077, data.netbuff->current->limit); + assertTrue(data.netbuff->current->limit == 500, "wrong limit, expected %u got %zu", 500, data.netbuff->current->limit); + + data.truth = parcBuffer_Allocate(buffer1_length + buffer2_length + 8); + parcBuffer_PutArray(data.truth, buffer1_length, buffer1); + parcBuffer_PutUint64(data.truth, x); + parcBuffer_PutArray(data.truth, buffer2_length, buffer2); + parcBuffer_Flip(data.truth); + + return data; +} + +static void +_destroyData(SetLimitData data) +{ + ccnxCodecNetworkBuffer_Release(&data.netbuff); + parcBuffer_Release(&data.truth); +} + +static void +_runDataTest(size_t position) +{ + SetLimitData data = _allocateData(); + ccnxCodecNetworkBuffer_SetPosition(data.netbuff, position); + parcBuffer_SetLimit(data.truth, position); + + ccnxCodecNetworkBuffer_Finalize(data.netbuff); + PARCBuffer *test = ccnxCodecNetworkBuffer_CreateParcBuffer(data.netbuff); + assertTrue(parcBuffer_Equals(data.truth, test), "wrong value") + { + printf("Expected\n"); + parcBuffer_Display(data.truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + _destroyData(data); +} + +/* + * In this test, SetLimit is called when we are at position 4077 + */ +LONGBOW_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_EndOfTail) +{ + _runDataTest(4077); +} + +/* + * In this test, SetLimit is called when we are at position 4000, which + * is in the middle of 'block 2' + */ +LONGBOW_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_MidOfTail) +{ + _runDataTest(4000); +} + +/* + * In this test, SetLimit is called when we are at position 3577, which + * is in the start of 'block 2' + */ +LONGBOW_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_StartOfTail) +{ + _runDataTest(3577); +} + +/* + * In this test, SetLimit is called when we are at position 3576, which + * is the last byte of 'block 1' + */ +LONGBOW_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_EndOfMid) +{ + _runDataTest(3576); +} + +/* + * In this test, SetLimit is called when we are at position 2000, which + * is the middle of 'block 1' + */ +LONGBOW_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_MidOfMid) +{ + _runDataTest(2000); +} + +/* + * 1536 is 1st byte of 'block 1' + */ +LONGBOW_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_StartOfMid) +{ + _runDataTest(1536); +} + +/* + * Wipe it all out + */ +LONGBOW_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_Zero) +{ + _runDataTest(0); +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, _ccnxCodecNetworkBufferMemory_Allocate); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + longBowTestCase_SetClipBoardData(testCase, _commonSetup()); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + _commonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + 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(Local, _ccnxCodecNetworkBufferMemory_Allocate) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + size_t desired = 2048; + CCNxCodecNetworkBufferMemory *memory = _ccnxCodecNetworkBufferMemory_Allocate(data->buffer, desired); + assertNotNull(memory, "Got null memory"); + assertNull(memory->next, "memory->next is not null"); + assertTrue(memory->begin == 0, "memory has wrong offset, got %zu expecting %u", memory->begin, 0); + assertTrue(memory->capacity == desired, "Wrong capacity, got %zu expecting %zu", memory->capacity, desired); + + _ccnxCodecNetworkBufferMemory_Release(data->buffer, &memory); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_NetworkBuffer); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvDecoder.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvDecoder.c new file mode 100755 index 00000000..db835bb5 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvDecoder.c @@ -0,0 +1,808 @@ +/* + * 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 "../ccnxCodec_TlvDecoder.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include <inttypes.h> + +LONGBOW_TEST_RUNNER(parc_Tlv) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Decoder); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_Tlv) +{ + 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(parc_Tlv) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ============================================ + +LONGBOW_TEST_FIXTURE(Decoder) +{ + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Create); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetLength); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetType); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_PeekType); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetValue); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetValue_TooLong); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetContainer); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetContainer_TooLong); + + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_IsEmpty_True); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_IsEmpty_False); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Position); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_EnsureRemaining_True); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_EnsureRemaining_False); + + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_Good); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_Short); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_WrongType); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_WrongLength); + + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_Good); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_Short); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_WrongType); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_WrongLength); + + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_Good); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_Short); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_WrongType); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_WrongLength); + + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_Good); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_Short); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_WrongType); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_WrongLength); + + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_Good); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_WrongType); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_TooShort); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_TooLong); + + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Advance_Good); + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Advance_TooLong); + + LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetVarInt); +} + +LONGBOW_TEST_FIXTURE_SETUP(Decoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Decoder) +{ + 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; +} + +/** + * check for memory leaks on create/destroy + */ +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Create) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1); + size_t before = parcMemory_Outstanding(); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + ccnxCodecTlvDecoder_Destroy(&decoder); + size_t after = parcMemory_Outstanding(); + parcBuffer_Release(&buffer); + assertTrue(before == after, "Memory leak, expected %zu got %zu bytes\n", before, after); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetLength) +{ + /** + * We will create a TLV structure that looks like this: + * { T = 1, L = 19 }, + * { T = 2, L = 5, V = "hello" } + * { T = 3, L = 6, V = "mr tlv" } + */ + uint8_t truthBytes[] = { + 0x00, 0x01, 0x00, 0x13, + 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o', + 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v' + }; + + PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes)); + + CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer); + parcBuffer_Release(&buffer); + + // we're calling this on byte 0, so the "length" will be 0x0001 + uint16_t length = ccnxCodecTlvDecoder_GetLength(outerDecoder); + + assertTrue(parcBuffer_Position(outerDecoder->buffer) == 2, + "Did not advance buffer to right spot, expected %u got %zu", + 2, parcBuffer_Position(outerDecoder->buffer)); + + assertTrue(length == 1, "Wrong length expected %u got %u", 1, length); + + ccnxCodecTlvDecoder_Destroy(&outerDecoder); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetType) +{ + /** + * We will create a TLV structure that looks like this: + * { T = 1, L = 19 }, + * { T = 2, L = 5, V = "hello" } + * { T = 3, L = 6, V = "mr tlv" } + */ + uint8_t truthBytes[] = { + 0x00, 0x01, 0x00, 0x13, + 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o', + 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v' + }; + + PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes)); + + CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer); + parcBuffer_Release(&buffer); + + uint16_t type = ccnxCodecTlvDecoder_GetType(outerDecoder); + + assertTrue(parcBuffer_Position(outerDecoder->buffer) == 2, + "Did not advance buffer to right spot, expected %u got %zu", + 2, parcBuffer_Position(outerDecoder->buffer)); + + assertTrue(type == 1, "Wrong type expected %u got %u", 1, type); + + ccnxCodecTlvDecoder_Destroy(&outerDecoder); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_PeekType) +{ + /** + * We will create a TLV structure that looks like this: + * { T = 1, L = 19 }, + * { T = 2, L = 5, V = "hello" } + * { T = 3, L = 6, V = "mr tlv" } + */ + uint8_t truthBytes[] = { + 0x00, 0x01, 0x00, 0x13, + 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o', + 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v' + }; + + PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes)); + + CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer); + parcBuffer_Release(&buffer); + + uint16_t type = ccnxCodecTlvDecoder_PeekType(outerDecoder); + + assertTrue(parcBuffer_Position(outerDecoder->buffer) == 0, + "Did not advance buffer to right spot, expected %u got %zu", + 0, parcBuffer_Position(outerDecoder->buffer)); + + assertTrue(type == 1, "Wrong type expected %u got %u", 1, type); + + ccnxCodecTlvDecoder_Destroy(&outerDecoder); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetValue) +{ + /** + * We will create a TLV structure that looks like this: + * { T = 1, L = 19 }, + * { T = 2, L = 5, V = "hello" } + * { T = 3, L = 6, V = "mr tlv" } + */ + uint8_t truthBytes[] = { + 0x00, 0x01, 0x00, 0x13, + 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o', + 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v' + }; + + PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes)); + + CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer); + parcBuffer_Release(&buffer); + + uint16_t type = ccnxCodecTlvDecoder_GetType(outerDecoder); + uint16_t length = ccnxCodecTlvDecoder_GetLength(outerDecoder); + + assertTrue(type == 1, "Wrong type expected %u got %u", 1, type); + assertTrue(length == 19, "Wrong length expected %u got %u", 19, length); + + PARCBuffer *inner = ccnxCodecTlvDecoder_GetValue(outerDecoder, length); + + // inner should now be empty + assertTrue(ccnxCodecTlvDecoder_IsEmpty(outerDecoder), "outer decoder should be emtpy"); + + CCNxCodecTlvDecoder *innerDecoder = ccnxCodecTlvDecoder_Create(inner); + parcBuffer_Release(&inner); + + type = ccnxCodecTlvDecoder_GetType(innerDecoder); + length = ccnxCodecTlvDecoder_GetLength(innerDecoder); + + assertTrue(type == 2, "Wrong type expected %u got %u", 2, type); + assertTrue(length == 5, "Wrong length expected %u got %u", 5, length); + + PARCBuffer *hello = ccnxCodecTlvDecoder_GetValue(innerDecoder, length); + + parcBuffer_Release(&hello); + ccnxCodecTlvDecoder_Destroy(&innerDecoder); + ccnxCodecTlvDecoder_Destroy(&outerDecoder); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetValue_TooLong) +{ + // Length is beyond end of buffer + uint8_t truthBytes[] = { 0x00, 0x02, 0x00, 0x99, 'h', 'e', 'l', 'l', 'o' }; + + PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes)); + + CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer); + parcBuffer_Release(&buffer); + + (void) ccnxCodecTlvDecoder_GetType(outerDecoder); + uint16_t length = ccnxCodecTlvDecoder_GetLength(outerDecoder); + PARCBuffer *value = ccnxCodecTlvDecoder_GetValue(outerDecoder, length); + + assertNull(value, "Value should be null because of buffer underrun"); + + ccnxCodecTlvDecoder_Destroy(&outerDecoder); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_IsEmpty_True) +{ + /** + * We will create a TLV structure that looks like this: + * { T = 1, L = 19 }, + * { T = 2, L = 5, V = "hello" } + * { T = 3, L = 6, V = "mr tlv" } + */ + uint8_t truthBytes[] = { + 0x00, 0x01, 0x00, 0x13, + 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o', + 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v' + }; + + PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes)); + + CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer); + parcBuffer_Release(&buffer); + + PARCBuffer *value = ccnxCodecTlvDecoder_GetValue(outerDecoder, sizeof(truthBytes)); + parcBuffer_Release(&value); + + assertTrue(ccnxCodecTlvDecoder_IsEmpty(outerDecoder), "Decoder said it was not empty when its should be empty"); + ccnxCodecTlvDecoder_Destroy(&outerDecoder); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_IsEmpty_False) +{ + /** + * We will create a TLV structure that looks like this: + * { T = 1, L = 19 }, + * { T = 2, L = 5, V = "hello" } + * { T = 3, L = 6, V = "mr tlv" } + */ + uint8_t truthBytes[] = { + 0x00, 0x01, 0x00, 0x13, + 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o', + 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v' + }; + + PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes)); + + CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer); + parcBuffer_Release(&buffer); + + assertFalse(ccnxCodecTlvDecoder_IsEmpty(outerDecoder), "Decoder said it was empty when its full"); + ccnxCodecTlvDecoder_Destroy(&outerDecoder); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Position) +{ + /** + * We will create a TLV structure that looks like this: + * { T = 1, L = 19 }, + * { T = 2, L = 5, V = "hello" } + * { T = 3, L = 6, V = "mr tlv" } + */ + uint8_t truthBytes[] = { + 0x00, 0x01, 0x00, 0x13, + 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o', + 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v' + }; + + PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes)); + + CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer); + parcBuffer_Release(&buffer); + + PARCBuffer *value = ccnxCodecTlvDecoder_GetValue(outerDecoder, 8); + parcBuffer_Release(&value); + + assertTrue(ccnxCodecTlvDecoder_Position(outerDecoder) == 8, + "Decoder reports wrong position, expected %u got %zu", + 8, + ccnxCodecTlvDecoder_Position(outerDecoder)); + + ccnxCodecTlvDecoder_Destroy(&outerDecoder); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_EnsureRemaining_True) +{ + uint8_t truthBytes[] = { + 0x00, 0x01, 0x00, 0x13, + 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o', + 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v' + }; + + PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes)); + + CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer); + parcBuffer_Release(&buffer); + + bool success = ccnxCodecTlvDecoder_EnsureRemaining(outerDecoder, 5); + + ccnxCodecTlvDecoder_Destroy(&outerDecoder); + + assertTrue(success, + "Decoder failed ensureRemaining check for 5 bytes when its a 19 byte buffer"); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_EnsureRemaining_False) +{ + uint8_t truthBytes[] = { + 0x00, 0x01, 0x00, 0x13, + 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o', + 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v' + }; + + PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes)); + + CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer); + parcBuffer_Release(&buffer); + + bool success = ccnxCodecTlvDecoder_EnsureRemaining(outerDecoder, 24); + + ccnxCodecTlvDecoder_Destroy(&outerDecoder); + + assertFalse(success, + "Decoder passed ensureRemaining check for 24 bytes when its a 19 byte buffer"); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_Good) +{ + PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x20, 0x00, 0x01, 0xFF }, 5, 0, 5); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + uint8_t value; + bool success = ccnxCodecTlvDecoder_GetUint8(decoder, 0x1020, &value); + assertTrue(success, "Did not decode a correct buffer"); + assertTrue(value == 0xFF, "Incorrect value, expected 0x%X got 0x%X", 0xFF, value); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_Short) +{ + // LIMIT IS SHORT + PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x20, 0x00, 0x01, 0xFF }, 5, 0, 4); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + uint8_t value; + bool success = ccnxCodecTlvDecoder_GetUint8(decoder, 0x1020, &value); + assertFalse(success, "Should have failed a short buffer"); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_WrongType) +{ + // TYPE IS WRONG + PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0xFF, 0xFF, 0x00, 0x01, 0xFF }, 5, 0, 5); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + uint8_t value; + bool success = ccnxCodecTlvDecoder_GetUint8(decoder, 0x1020, &value); + assertFalse(success, "Should have failed because of wrong type"); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_WrongLength) +{ + // LENGTH TOO BIG + PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x20, 0x00, 0x99, 0xFF }, 5, 0, 5); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + uint8_t value; + bool success = ccnxCodecTlvDecoder_GetUint8(decoder, 0x1020, &value); + assertFalse(success, "Should have failed because of incorrect length"); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_Good) +{ + PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x21, 0x00, 0x02, 0xFF, 0x01 }, 6, 0, 6); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + uint16_t value; + bool success = ccnxCodecTlvDecoder_GetUint16(decoder, 0x1021, &value); + assertTrue(success, "Did not decode a correct buffer"); + assertTrue(value == 0xFF01, "Incorrect value, expected 0x%X got 0x%X", 0xFF01, value); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_Short) +{ + // LIMIT IS SHORT + PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x21, 0x00, 0x02, 0xFF, 0x01 }, 6, 0, 5); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + uint16_t value; + bool success = ccnxCodecTlvDecoder_GetUint16(decoder, 0x1021, &value); + assertFalse(success, "Should have failed because of wrong type"); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_WrongType) +{ + // TYPE IS WRONG + PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0xFF, 0xFF, 0x00, 0x02, 0xFF, 0x01 }, 6, 0, 6); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + uint16_t value; + bool success = ccnxCodecTlvDecoder_GetUint16(decoder, 0x1021, &value); + assertFalse(success, "Should have failed because of wrong type"); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_WrongLength) +{ + // LENGTH TOO BIG + PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x21, 0x00, 0x99, 0xFF }, 5, 0, 5); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + uint16_t value; + bool success = ccnxCodecTlvDecoder_GetUint16(decoder, 0x1021, &value); + assertFalse(success, "Should have failed because of incorrect length"); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_Good) +{ + PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x22, 0x00, 0x04, 0xFF, 0x01, 0x02, 0x03 }, 8, 0, 8); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + uint32_t value; + bool success = ccnxCodecTlvDecoder_GetUint32(decoder, 0x1022, &value); + assertTrue(success, "Did not decode a correct buffer"); + assertTrue(value == 0xFF010203, "Incorrect value, expected 0x%X got 0x%X", 0xFF010203, value); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_Short) +{ + // LIMIT IS SHORT + PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x22, 0x00, 0x04, 0xFF, 0x01, 0x02, 0x03 }, 8, 0, 7); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + uint32_t value; + bool success = ccnxCodecTlvDecoder_GetUint32(decoder, 0x1022, &value); + assertFalse(success, "Should have failed because of wrong type"); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_WrongType) +{ + // TYPE IS WRONG + PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0xFF, 0xFF, 0x00, 0x04, 0xFF, 0x01, 0x02, 0x03 }, 8, 0, 8); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + uint32_t value; + bool success = ccnxCodecTlvDecoder_GetUint32(decoder, 0x1022, &value); + assertFalse(success, "Should have failed because of wrong type"); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_WrongLength) +{ + // LENGTH TOO BIG + PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x22, 0x00, 0x99, 0xFF, 0x01, 0x02, 0x03 }, 8, 0, 8); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + uint32_t value; + bool success = ccnxCodecTlvDecoder_GetUint32(decoder, 0x1022, &value); + assertFalse(success, "Should have failed because of incorrect length"); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_Good) +{ + PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x23, 0x00, 0x08, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, 12, 0, 12); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + uint64_t value; + uint64_t truth = 0xFF01020304050607ULL; + bool success = ccnxCodecTlvDecoder_GetUint64(decoder, 0x1023, &value); + assertTrue(success, "Did not decode a correct buffer"); + assertTrue(value == truth, "Incorrect value, expected %#" PRIx64 " got %#" PRIx64, truth, value); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_Short) +{ + // LIMIT IS SHORT + PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x23, 0x00, 0x08, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, 12, 0, 11); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + uint64_t value; + bool success = ccnxCodecTlvDecoder_GetUint64(decoder, 0x1023, &value); + assertFalse(success, "Should have failed because of wrong type"); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_WrongType) +{ + // TYPE IS WRONG + PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0xFF, 0xFF, 0x00, 0x08, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, 12, 0, 11); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + uint64_t value; + bool success = ccnxCodecTlvDecoder_GetUint64(decoder, 0x1023, &value); + assertFalse(success, "Should have failed because of wrong type"); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_WrongLength) +{ + // LENGTH TOO BIG + PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x23, 0x00, 0x99, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, 12, 0, 12); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + uint64_t value; + bool success = ccnxCodecTlvDecoder_GetUint64(decoder, 0x1023, &value); + assertFalse(success, "Should have failed because of incorrect length"); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_Good) +{ + PARCBuffer *truth = parcBuffer_Wrap((uint8_t[]) { 0x01, 0x02, 0x03, 0x04 }, 4, 0, 4); + PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) { 0x00, 0x01, 0x00, 0x08, 0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04 }, 12, 0, 12); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input); + + (void) ccnxCodecTlvDecoder_GetType(decoder); + (void) ccnxCodecTlvDecoder_GetLength(decoder); + + PARCBuffer *test = ccnxCodecTlvDecoder_GetBuffer(decoder, 0xAABB); + if (!parcBuffer_Equals(truth, test)) { + printf("Buffers not equal\n"); + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal"); + } + + parcBuffer_Release(&test); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&truth); + parcBuffer_Release(&input); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_WrongType) +{ + // INNER TYPE IS WRONG + PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) { 0x00, 0x01, 0x00, 0x08, 0xFF, 0xFF, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04 }, 12, 0, 12); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input); + + (void) ccnxCodecTlvDecoder_GetType(decoder); + (void) ccnxCodecTlvDecoder_GetLength(decoder); + + PARCBuffer *test = ccnxCodecTlvDecoder_GetBuffer(decoder, 0xAABB); + assertNull(test, "Should have returned NULL because of incorrect TLV type"); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&input); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_TooShort) +{ + // OVERALL LENGTH TOO SHORT TO PARSE + // buffer only goes to here ---------------------------------! + PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) { 0x00, 0x01, 0x00, 0x08, 0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04 }, 12, 0, 6); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input); + + (void) ccnxCodecTlvDecoder_GetType(decoder); + (void) ccnxCodecTlvDecoder_GetLength(decoder); + + PARCBuffer *test = ccnxCodecTlvDecoder_GetBuffer(decoder, 0xAABB); + assertNull(test, "Should have returned NULL because of input underrun"); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&input); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_TooLong) +{ + // VALUE (4 bytes) SHORTER THAN LENGTH (0x99) + PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) { 0x00, 0x01, 0x00, 0x08, 0xAA, 0xBB, 0x00, 0x99, 0x01, 0x02, 0x03, 0x04 }, 12, 0, 12); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input); + + (void) ccnxCodecTlvDecoder_GetType(decoder); + (void) ccnxCodecTlvDecoder_GetLength(decoder); + + PARCBuffer *test = ccnxCodecTlvDecoder_GetBuffer(decoder, 0xAABB); + assertNull(test, "Should have returned NULL because of value underrun"); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&input); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetContainer) +{ + /** + * We will create a TLV structure that looks like this: + * { T = 1, L = 19 }, + * { T = 2, L = 5, V = "hello" } + * { T = 3, L = 6, V = "mr tlv" } + */ + uint8_t truthBytes[] = { + 0x00, 0x01, 0x00, 0x13, + 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o', + 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v' + }; + + PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes)); + + CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer); + parcBuffer_Release(&buffer); + + (void) ccnxCodecTlvDecoder_GetType(outerDecoder); + uint16_t length = ccnxCodecTlvDecoder_GetLength(outerDecoder); + CCNxCodecTlvDecoder *innerDecoder = ccnxCodecTlvDecoder_GetContainer(outerDecoder, length); + assertNotNull(innerDecoder, "Got a null decoder for a valid slice"); + assertTrue(ccnxCodecTlvDecoder_Position(innerDecoder) == 0, "Wrong position, expected 0 got %zu", ccnxCodecTlvDecoder_Position(innerDecoder)); + assertTrue(ccnxCodecTlvDecoder_EnsureRemaining(innerDecoder, 19), "Inner decoder does not have enough bytes in it"); + + ccnxCodecTlvDecoder_Destroy(&innerDecoder); + ccnxCodecTlvDecoder_Destroy(&outerDecoder); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetContainer_TooLong) +{ + /** + * We will create a TLV structure that looks like this: + * { T = 1, L = 19 }, + * { T = 2, L = 5, V = "hello" } + * { T = 3, L = 6, V = "mr tlv" } + */ + uint8_t truthBytes[] = { + 0x00, 0x01, 0x00, 0x13, + 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o', + 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v' + }; + + PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes)); + + CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer); + parcBuffer_Release(&buffer); + + (void) ccnxCodecTlvDecoder_GetType(outerDecoder); + (void) ccnxCodecTlvDecoder_GetLength(outerDecoder); + // ask for too many bytes + CCNxCodecTlvDecoder *innerDecoder = ccnxCodecTlvDecoder_GetContainer(outerDecoder, 100); + assertNull(innerDecoder, "Got a decoder for an invalid slice"); + ccnxCodecTlvDecoder_Destroy(&outerDecoder); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Advance_Good) +{ + PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0xFF, 0xFF, 0x00, 0x04, 0xFF, 0x01, 0x02, 0x03 }, 8, 0, 8); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + + size_t advance = 3; + size_t beforePosition = ccnxCodecTlvDecoder_Position(decoder); + bool success = ccnxCodecTlvDecoder_Advance(decoder, advance); + size_t afterPosition = ccnxCodecTlvDecoder_Position(decoder); + + assertTrue(success, "Failed to advance decoder"); + assertTrue(beforePosition + advance == afterPosition, "Wrong position, got %zu expected %zu", afterPosition, beforePosition + advance); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Advance_TooLong) +{ + PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0xFF, 0xFF, 0x00, 0x04, 0xFF, 0x01, 0x02, 0x03 }, 8, 0, 8); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + + size_t advance = 9; + size_t beforePosition = ccnxCodecTlvDecoder_Position(decoder); + bool success = ccnxCodecTlvDecoder_Advance(decoder, advance); + size_t afterPosition = ccnxCodecTlvDecoder_Position(decoder); + + assertFalse(success, "Should have returned false advancing beyond end of decoder"); + assertTrue(beforePosition == afterPosition, "Wrong position, got %zu expected %zu", afterPosition, beforePosition); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetVarInt) +{ + struct test_vector { + uint64_t value; + bool valid; + int length; + uint8_t *array; + } vectors[] = { + // length 0 invalid + { .value = 0, .valid = false, .length = 0, .array = (uint8_t[]) { 0x00 } }, + { .value = 0, .valid = true, .length = 1, .array = (uint8_t[]) { 0x00 } }, + { .value = 0xFF, .valid = true, .length = 1, .array = (uint8_t[]) { 0xFF } }, + { .value = 0x0001, .valid = true, .length = 2, .array = (uint8_t[]) { 0x00, 0x01} }, + { .value = 0xFF01, .valid = true, .length = 2, .array = (uint8_t[]) { 0xFF, 0x01} }, + { .value = 0x000001, .valid = true, .length = 3, .array = (uint8_t[]) { 0x00, 0x00, 0x01} }, + { .value = 0xFF0001, .valid = true, .length = 3, .array = (uint8_t[]) { 0xFF, 0x00, 0x01} }, + { .value = 0x00000001, .valid = true, .length = 4, .array = (uint8_t[]) { 0x00, 0x00, 0x00, 0x01} }, + { .value = 0xFF002001, .valid = true, .length = 4, .array = (uint8_t[]) { 0xFF, 0x00, 0x20, 0x01} }, + { .value = 0xFF00200103040506ULL, .valid = true, .length = 8, .array = (uint8_t[]) { 0xFF, 0x00, 0x20, 0x01, 0x03, 0x04, 0x05, 0x06} }, + // length 9 invalid + { .value = 0, .valid = false, .length = 9, .array = (uint8_t[]) { 0xFF, 0x00, 0x20, 0x01, 0x03, 0x04, 0x05, 0x06, 0x07} }, + // sentinal is NULL array + { .value = 0, .valid = false, .length = 0, .array = NULL }, + }; + + for (int i = 0; vectors[i].array != NULL; i++) { + PARCBuffer *buffer = parcBuffer_Wrap(vectors[i].array, vectors[i].length, 0, vectors[i].length); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + + uint64_t value; + bool success = ccnxCodecTlvDecoder_GetVarInt(decoder, vectors[i].length, &value); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); + + assertTrue(success == vectors[i].valid, "index %d: Wrong return, got %d expected %d", i, success, vectors[i].valid); + if (vectors[i].valid) { + assertTrue(value == vectors[i].value, "index %d: wrong value: got %" PRIu64 " expected %" PRIu64, i, value, vectors[i].value); + } + } +} + +// ============================================ + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Tlv); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvEncoder.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvEncoder.c new file mode 100755 index 00000000..0898077d --- /dev/null +++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvEncoder.c @@ -0,0 +1,874 @@ +/* + * 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 "../ccnxCodec_TlvEncoder.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include <ccnx/common/validation/ccnxValidation_CRC32C.h> + +LONGBOW_TEST_RUNNER(parc_Tlv) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Encoder); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_Tlv) +{ + 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(parc_Tlv) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ========================================== + +LONGBOW_TEST_FIXTURE(Encoder) +{ + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendArray); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendRawArray); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendBuffer); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendBuffer_TestReturn); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendContainer); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint8); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint16); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint32); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint64); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendVarInt); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_PutUint8); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_PutUint16); + + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Create); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Finalize); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Finalize_TrimLimit_Buffer); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Finalize_TrimLimit_IoVec); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Initialize); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Initialize_Twice); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Position); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetContainerLength); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetPosition); + + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetError_Present); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetError_Missing); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_GetError); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_ClearError_Present); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_ClearError_Missing); + + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_MarkSignatureEnd); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_MarkSignatureStart); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_ComputeSignature); + LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_GetSigner); +} + +LONGBOW_TEST_FIXTURE_SETUP(Encoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Encoder) +{ + 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; +} + +/** + * We will create a TLV structure that looks like this: + * { T = 1, L = 19 }, + * { T = 2, L = 5, V = "hello" } + * { T = 3, L = 6, V = "mr tlv" } + */ +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendArray) +{ + uint8_t truthBytes[] = { 0x00, 0x01, 0x00, 0x13, + 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o', + 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v' }; + + PARCBuffer *truth = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes)); + + uint8_t helloString[] = "hello"; + uint8_t mrTlvString[] = "mr tlv"; + + CCNxCodecTlvEncoder *innerEncoder = ccnxCodecTlvEncoder_Create(); + + // sizeof -1 to account for null byte at end of string + ccnxCodecTlvEncoder_AppendArray(innerEncoder, 2, sizeof(helloString) - 1, helloString); + ccnxCodecTlvEncoder_AppendArray(innerEncoder, 3, sizeof(mrTlvString) - 1, mrTlvString); + + ccnxCodecTlvEncoder_Finalize(innerEncoder); + PARCBuffer *inner = ccnxCodecTlvEncoder_CreateBuffer(innerEncoder); + + CCNxCodecTlvEncoder *outerEncoder = ccnxCodecTlvEncoder_Create(); + + ccnxCodecTlvEncoder_AppendBuffer(outerEncoder, 1, inner); + ccnxCodecTlvEncoder_Finalize(outerEncoder); + PARCBuffer *container = ccnxCodecTlvEncoder_CreateBuffer(outerEncoder); + + parcBuffer_Release(&inner); + + ccnxCodecTlvEncoder_Destroy(&innerEncoder); + ccnxCodecTlvEncoder_Destroy(&outerEncoder); + + // parcBuffer_ToString() will not work well as we have 0 bytes, use parcBuffer_ToHexString() case 1017 + assertTrue(parcBuffer_Equals(truth, container), "Buffer mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(container, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&container); +} + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendRawArray) +{ + uint8_t truthBytes[] = { 0x00, 0x01, 0x00, 0x13, + 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o', + 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v' }; + + PARCBuffer *truth = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes)); + + uint8_t helloString[] = "hello"; + uint8_t mrTlvString[] = "mr tlv"; + + CCNxCodecTlvEncoder *innerEncoder = ccnxCodecTlvEncoder_Create(); + + // sizeof -1 to account for null byte at end of string + ccnxCodecTlvEncoder_AppendContainer(innerEncoder, 2, sizeof(helloString) - 1); + ccnxCodecTlvEncoder_AppendRawArray(innerEncoder, sizeof(helloString) - 1, helloString); + ccnxCodecTlvEncoder_AppendContainer(innerEncoder, 3, sizeof(mrTlvString) - 1); + ccnxCodecTlvEncoder_AppendRawArray(innerEncoder, sizeof(mrTlvString) - 1, mrTlvString); + + ccnxCodecTlvEncoder_Finalize(innerEncoder); + PARCBuffer *inner = ccnxCodecTlvEncoder_CreateBuffer(innerEncoder); + + CCNxCodecTlvEncoder *outerEncoder = ccnxCodecTlvEncoder_Create(); + + ccnxCodecTlvEncoder_AppendBuffer(outerEncoder, 1, inner); + ccnxCodecTlvEncoder_Finalize(outerEncoder); + PARCBuffer *container = ccnxCodecTlvEncoder_CreateBuffer(outerEncoder); + + parcBuffer_Release(&inner); + + ccnxCodecTlvEncoder_Destroy(&innerEncoder); + ccnxCodecTlvEncoder_Destroy(&outerEncoder); + + // parcBuffer_ToString() will not work well as we have 0 bytes, use parcBuffer_ToHexString() case 1017 + assertTrue(parcBuffer_Equals(truth, container), "Buffer mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(container, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&container); +} + + +/** + * We will create a TLV structure that looks like this: + * { T = 1, L = 19 }, + * { T = 2, L = 5, V = "hello" } + * { T = 3, L = 6, V = "mr tlv" } + */ +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendBuffer) +{ + uint8_t truthBytes[] = { 0x00, 0x01, 0x00, 0x13, + 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o', + 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v' }; + + PARCBuffer *truth = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes)); + + uint8_t helloString[] = "hello"; + PARCBuffer *hello = parcBuffer_Wrap(helloString, 5, 0, 5); + + uint8_t mrTlvString[] = "mr tlv"; + PARCBuffer *mrTlv = parcBuffer_Wrap(mrTlvString, 6, 0, 6); + + CCNxCodecTlvEncoder *innerEncoder = ccnxCodecTlvEncoder_Create(); + + ccnxCodecTlvEncoder_AppendBuffer(innerEncoder, 2, hello); + ccnxCodecTlvEncoder_AppendBuffer(innerEncoder, 3, mrTlv); + + ccnxCodecTlvEncoder_Finalize(innerEncoder); + PARCBuffer *inner = ccnxCodecTlvEncoder_CreateBuffer(innerEncoder); + + CCNxCodecTlvEncoder *outerEncoder = ccnxCodecTlvEncoder_Create(); + + ccnxCodecTlvEncoder_AppendBuffer(outerEncoder, 1, inner); + ccnxCodecTlvEncoder_Finalize(outerEncoder); + PARCBuffer *container = ccnxCodecTlvEncoder_CreateBuffer(outerEncoder); + + parcBuffer_Release(&inner); + parcBuffer_Release(&hello); + parcBuffer_Release(&mrTlv); + + ccnxCodecTlvEncoder_Destroy(&innerEncoder); + ccnxCodecTlvEncoder_Destroy(&outerEncoder); + + // parcBuffer_ToString() will not work well as we have 0 bytes, use parcBuffer_ToHexString() case 1017 + assertTrue(parcBuffer_Equals(truth, container), + "buffers not equal\nexpected '%s'\ngot '%s'\n", + parcBuffer_ToString(truth), + parcBuffer_ToString(container) + ); + + parcBuffer_Release(&truth); + parcBuffer_Release(&container); +} + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendBuffer_TestReturn) +{ + uint8_t helloString[] = "hello"; + PARCBuffer *hello = parcBuffer_Wrap(helloString, 5, 0, 5); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(encoder); + + size_t trueLength = 2 + 2 + 5; + size_t length = ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, hello); + assertTrue(length == trueLength, "AppendBuffer returned wrong length, expected %zu got %zu", trueLength, length); + + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&hello); +} + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendContainer) +{ + uint8_t truthString[] = { 0x00, 0x02, 0xF1, 0x07 }; + PARCBuffer *truth = parcBuffer_Wrap(truthString, 4, 0, 4); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(encoder); + + size_t trueLength = 2 + 2; + size_t length = ccnxCodecTlvEncoder_AppendContainer(encoder, 2, 0xF107); + assertTrue(length == trueLength, "AppendBuffer returned wrong length, expected %zu got %zu", trueLength, length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + + assertTrue(parcBuffer_Equals(test, truth), "Buffer is incorrect."); + + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); + parcBuffer_Release(&test); +} + +/** + * Check for memory leaks and correct isInitialized state + */ +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Create) +{ + size_t before = parcMemory_Outstanding(); + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + // add a signer to make sure it is destroyed + PARCSigner *signer = ccnxValidationCRC32C_CreateSigner(); + ccnxCodecTlvEncoder_SetSigner(encoder, signer); + parcSigner_Release(&signer); + + // add an error to make sure its destroyed too + CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, "foo", 1, 1); + ccnxCodecTlvEncoder_SetError(encoder, error); + ccnxCodecError_Release(&error); + + ccnxCodecTlvEncoder_Destroy(&encoder); + size_t after = parcMemory_Outstanding(); + assertTrue(before == after, "Memory leak, expected %zu got %zu bytes\n", before, after); +} + +/** + * Check for memory leaks + */ +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Finalize) +{ + size_t before = parcMemory_Outstanding(); + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + ccnxCodecTlvEncoder_Initialize(encoder); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + parcBuffer_Release(&test); + + ccnxCodecTlvEncoder_Destroy(&encoder); + size_t after = parcMemory_Outstanding(); + assertTrue(before == after, "Memory leak, expected %zu got %zu bytes\n", before, after); +} + +/* + * Do a long write, then backup the position. + * After Finalize, the Limit should have trimmed off the erased part. + */ +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Finalize_TrimLimit_Buffer) +{ + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + uint8_t array[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + ccnxCodecTlvEncoder_AppendRawArray(encoder, sizeof(array), array); + ccnxCodecTlvEncoder_SetPosition(encoder, 3); + ccnxCodecTlvEncoder_Finalize(encoder); + + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Remaining(test) == 3, "Wrong length, expected 3 got %zu", parcBuffer_Remaining(test)); + + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +/* + * Do a long write, then backup the position. + * After Finalize, the Limit should have trimmed off the erased part. + */ +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Finalize_TrimLimit_IoVec) +{ + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + uint8_t array[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + ccnxCodecTlvEncoder_AppendRawArray(encoder, sizeof(array), array); + ccnxCodecTlvEncoder_SetPosition(encoder, 3); + ccnxCodecTlvEncoder_Finalize(encoder); + + CCNxCodecNetworkBufferIoVec *iov = ccnxCodecTlvEncoder_CreateIoVec(encoder); + assertTrue(ccnxCodecNetworkBufferIoVec_Length(iov) == 3, "Wrong length, expected 3 got %zu", ccnxCodecNetworkBufferIoVec_Length(iov)); + + ccnxCodecNetworkBufferIoVec_Release(&iov); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +/** + * Check for memory leaks and correct isInitialized state + */ +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Initialize) +{ + size_t before = parcMemory_Outstanding(); + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + ccnxCodecTlvEncoder_Initialize(encoder); + + ccnxCodecTlvEncoder_Destroy(&encoder); + + size_t after = parcMemory_Outstanding(); + assertTrue(before == after, "Memory leak, expected %zu got %zu bytes\n", before, after); +} + +/** + * Make sure calling Initialized on an Initialized buffer does not leak + */ +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Initialize_Twice) +{ + size_t before = parcMemory_Outstanding(); + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(encoder); + ccnxCodecTlvEncoder_Initialize(encoder); + ccnxCodecTlvEncoder_Destroy(&encoder); + + size_t after = parcMemory_Outstanding(); + assertTrue(before == after, "Memory leak, expected %zu got %zu bytes\n", before, after); +} + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Position) +{ + uint8_t helloString[] = "hello"; + PARCBuffer *hello = parcBuffer_Wrap(helloString, 5, 0, 5); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(encoder); + + size_t length = ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, hello); + size_t position = ccnxCodecTlvEncoder_Position(encoder); + + assertTrue(length == position, "Position not right expected %zu got %zu", length, position); + + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&hello); +} + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetContainerLength) +{ + uint8_t helloString[] = "hello"; + PARCBuffer *hello = parcBuffer_Wrap(helloString, 5, 0, 5); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(encoder); + + size_t containerPosition = ccnxCodecTlvEncoder_Position(encoder); + ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, hello); + ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, hello); + + size_t currentPosition = ccnxCodecTlvEncoder_Position(encoder); + + // when I set the length of the first container, we should be positioned back to + // the current location. + + ccnxCodecTlvEncoder_SetContainerLength(encoder, containerPosition, 99); + size_t testPosition = ccnxCodecTlvEncoder_Position(encoder); + + assertTrue(testPosition == currentPosition, "Position not right expected %zu got %zu", currentPosition, testPosition); + + // and make sure the length was updated + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *output = ccnxCodecTlvEncoder_CreateBuffer(encoder); + parcBuffer_SetPosition(output, 2); + uint16_t testlength = parcBuffer_GetUint16(output); + + assertTrue(testlength == 99, "Updated length wrong, expected %u got %u", 99, testlength); + + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&hello); + parcBuffer_Release(&output); +} + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint8) +{ + PARCBuffer *truth = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x20, 0x00, 0x01, 0xFF }, 5, 0, 5); + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(encoder); + ccnxCodecTlvEncoder_AppendUint8(encoder, 0x1020, 0xFF); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + + if (!parcBuffer_Equals(truth, test)) { + printf("Buffers not equal\n"); + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal"); + } + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); +} + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint16) +{ + PARCBuffer *truth = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x21, 0x00, 0x02, 0xFF, 0x01 }, 6, 0, 6); + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(encoder); + ccnxCodecTlvEncoder_AppendUint16(encoder, 0x1021, 0xFF01); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + + if (!parcBuffer_Equals(truth, test)) { + printf("Buffers not equal\n"); + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal"); + } + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); +} + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint32) +{ + PARCBuffer *truth = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x22, 0x00, 0x04, 0xFF, 0x01, 0x02, 0x03 }, 8, 0, 8); + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(encoder); + ccnxCodecTlvEncoder_AppendUint32(encoder, 0x1022, 0xFF010203); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + + if (!parcBuffer_Equals(truth, test)) { + printf("Buffers not equal\n"); + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal"); + } + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); +} + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint64) +{ + PARCBuffer *truth = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x23, 0x00, 0x08, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, 12, 0, 12); + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(encoder); + ccnxCodecTlvEncoder_AppendUint64(encoder, 0x1023, 0xFF01020304050607ULL); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + + if (!parcBuffer_Equals(truth, test)) { + printf("Buffers not equal\n"); + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal"); + } + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); +} + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendVarInt) +{ + struct test_vector { + uint64_t value; + bool valid; + int length; + uint8_t *array; + } vectors[] = { + { .value = 0, .valid = true, .length = 5, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x01, 0x00 } }, + { .value = 0xFF, .valid = true, .length = 5, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x01, 0xFF } }, + { .value = 0x0101, .valid = true, .length = 6, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x02, 0x01, 0x01} }, + { .value = 0xFF01, .valid = true, .length = 6, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x02, 0xFF, 0x01} }, + { .value = 0x010001, .valid = true, .length = 7, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x03, 0x01, 0x00, 0x01} }, + { .value = 0xFF0001, .valid = true, .length = 7, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x03, 0xFF, 0x00, 0x01} }, + { .value = 0x01000000, .valid = true, .length = 8, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00} }, + { .value = 0xFF002001, .valid = true, .length = 8, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x04, 0xFF, 0x00, 0x20, 0x01} }, + { .value = 0xFF00200103040506ULL, .valid = true, .length = 12, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x08, 0xFF, 0x00, 0x20, 0x01, 0x03, 0x04, 0x05, 0x06} }, + // sentinal is NULL array + { .value = 0, .valid = false, .length = 0, .array = NULL }, + }; + + for (int i = 0; vectors[i].array != NULL; i++) { + // only do the valid ones for the encode test + if (vectors[i].valid) { + PARCBuffer *truth = parcBuffer_Wrap(vectors[i].array, vectors[i].length, 0, vectors[i].length); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(encoder); + size_t length = ccnxCodecTlvEncoder_AppendVarInt(encoder, 0x1023, vectors[i].value); + + assertTrue(length == vectors[i].length, "Wrong length index %d, got %zu expected %d", i, length, vectors[i].length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + + assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal index %d", i) + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); + } + } +} + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_MarkSignatureEnd) +{ + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(encoder); + ccnxCodecTlvEncoder_AppendUint8(encoder, 0x1020, 0xFF); + + ccnxCodecTlvEncoder_MarkSignatureEnd(encoder); + assertTrue(encoder->signatureEnd == 5, "Wrong end position, expected %u got %zu", 5, encoder->signatureEnd) + { + ccnxCodecNetworkBuffer_Display(encoder->buffer, 3); + } + + assertTrue(encoder->signatureStartEndSet == END_SET, "Wrong flag, expected %d got %d", END_SET, encoder->signatureStartEndSet); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_MarkSignatureStart) +{ + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(encoder); + ccnxCodecTlvEncoder_AppendUint8(encoder, 0x1020, 0xFF); + + ccnxCodecTlvEncoder_MarkSignatureStart(encoder); + assertTrue(encoder->signatureStart == 5, "Wrong start position, expected %u got %zu", 5, encoder->signatureStart) + { + ccnxCodecNetworkBuffer_Display(encoder->buffer, 3); + } + + assertTrue(encoder->signatureStartEndSet == START_SET, "Wrong flag, expected %d got %d", START_SET, encoder->signatureStartEndSet); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_ComputeSignature) +{ + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(encoder); + ccnxCodecTlvEncoder_MarkSignatureStart(encoder); + ccnxCodecTlvEncoder_AppendUint8(encoder, 0x1020, 0xFF); + ccnxCodecTlvEncoder_MarkSignatureEnd(encoder); + + PARCSigner *signer = ccnxValidationCRC32C_CreateSigner(); + ccnxCodecTlvEncoder_SetSigner(encoder, signer); + parcSigner_Release(&signer); + + assertTrue(encoder->signatureStartEndSet == BOTH_SET, "Wrong flag, expected %d got %d", BOTH_SET, encoder->signatureStartEndSet); + + PARCSignature *sig = ccnxCodecTlvEncoder_ComputeSignature(encoder); + assertNotNull(sig, "Got null signature"); + + uint8_t truesig[] = { 0xA3, 0xAA, 0xC8, 0x4B }; + PARCBuffer *truesigBuffer = parcBuffer_Rewind(parcBuffer_CreateFromArray(truesig, sizeof(truesig))); + PARCBuffer *test = parcSignature_GetSignature(sig); + assertTrue(parcBuffer_Equals(truesigBuffer, test), "wrong crc value") + { + printf("Expected\n"); + parcBuffer_Display(truesigBuffer, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truesigBuffer); + parcSignature_Release(&sig); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_GetSigner) +{ + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + PARCSigner *signer = ccnxValidationCRC32C_CreateSigner(); + ccnxCodecTlvEncoder_SetSigner(encoder, signer); + + PARCSigner *test = ccnxCodecTlvEncoder_GetSigner(encoder); + assertTrue(test == signer, "Did not return the right signer, expected %p got %p", (void *) signer, (void *) test); + parcSigner_Release(&signer); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_PutUint8) +{ + PARCBuffer *truth = parcBuffer_Wrap((uint8_t[]) { 0x10, 0xEE, 0x00, 0x01, 0xFF }, 5, 0, 5); + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(encoder); + ccnxCodecTlvEncoder_AppendUint8(encoder, 0x1020, 0xFF); + + ccnxCodecTlvEncoder_PutUint8(encoder, 1, 0xEE); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + + if (!parcBuffer_Equals(truth, test)) { + printf("Buffers not equal\n"); + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal"); + } + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); +} + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_PutUint16) +{ + PARCBuffer *truth = parcBuffer_Wrap((uint8_t[]) { 0x10, 0xEE, 0xDD, 0x01, 0xFF }, 5, 0, 5); + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(encoder); + ccnxCodecTlvEncoder_AppendUint8(encoder, 0x1020, 0xFF); + + ccnxCodecTlvEncoder_PutUint16(encoder, 1, 0xEEDD); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + + if (!parcBuffer_Equals(truth, test)) { + printf("Buffers not equal\n"); + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal"); + } + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); +} + + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetPosition) +{ + uint8_t helloString[] = "hello"; + PARCBuffer *hello = parcBuffer_Wrap(helloString, 5, 0, 5); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(encoder); + + ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, hello); + // position is now at 9 (2+2+5) + + ccnxCodecTlvEncoder_SetPosition(encoder, 2); + + size_t position = ccnxCodecTlvEncoder_Position(encoder); + + assertTrue(2 == position, "Position not right expected %u got %zu", 2, position); + + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&hello); +} + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetError_Present) +{ + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, "foo", 1, 1); + ccnxCodecTlvEncoder_SetError(encoder, error); + + // now try to set a second time + bool success = ccnxCodecTlvEncoder_SetError(encoder, error); + ccnxCodecError_Release(&error); + + + assertFalse(success, "Returned success when should have failed"); + assertNotNull(encoder->error, "Encoder has null error member"); + + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetError_Missing) +{ + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, "foo", 1, 1); + bool success = ccnxCodecTlvEncoder_SetError(encoder, error); + ccnxCodecError_Release(&error); + + assertTrue(success, "Returned failure when should have succeeded"); + assertNotNull(encoder->error, "Encoder has null error member"); + + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_GetError) +{ + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, "foo", 1, 1); + ccnxCodecTlvEncoder_SetError(encoder, error); + ccnxCodecError_Release(&error); + + CCNxCodecError *test = ccnxCodecTlvEncoder_GetError(encoder); + assertNotNull(test, "Encoder has null error member"); + + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_ClearError_Present) +{ + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, "foo", 1, 1); + ccnxCodecTlvEncoder_SetError(encoder, error); + ccnxCodecError_Release(&error); + + ccnxCodecTlvEncoder_ClearError(encoder); + assertNull(encoder->error, "Encoder does not have a null error"); + + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_ClearError_Missing) +{ + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + ccnxCodecTlvEncoder_ClearError(encoder); + assertNull(encoder->error, "Encoder does not have a null error"); + + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +// ============================================ + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, _ccnxCodecTlvEncoder_ComputeVarIntLength); +} + +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, _ccnxCodecTlvEncoder_ComputeVarIntLength) +{ + struct test_vector { + uint64_t value; + int length; + } vectors[] = { + { .value = 0, .length = 1 }, + { .value = 0xFF, .length = 1 }, + { .value = 0x0101, .length = 2 }, + { .value = 0xFF01, .length = 2 }, + { .value = 0x010001, .length = 3 }, + { .value = 0xFF0001, .length = 3 }, + { .value = 0x01000000, .length = 4 }, + { .value = 0xFF002001, .length = 4 }, + { .value = 0x0100000000, .length = 5 }, + { .value = 0xFF00002001, .length = 5 }, + { .value = 0x010000000000, .length = 6 }, + { .value = 0xFF0000002001, .length = 6 }, + { .value = 0x01000000000000, .length = 7 }, + { .value = 0xFF000000002001, .length = 7 }, + { .value = 0xFF00200103040506ULL, .length = 8 }, + // sentinal is length 0 + { .value = 0, .length = 0 }, + }; + + for (int i = 0; vectors[i].length != 0; i++) { + unsigned test = _ccnxCodecTlvEncoder_ComputeVarIntLength(vectors[i].value); + assertTrue(test == vectors[i].length, "Incorrect length index %d, expected %u got %u", i, vectors[i].length, test); + } +} + + +// =================================================== + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Tlv); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvPacket.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvPacket.c new file mode 100644 index 00000000..2dfdfcb3 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvPacket.c @@ -0,0 +1,447 @@ +/* + * 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. + */ + +/** + * Does not do detailed tests of the decode -- those are tested in the individual schema_vX unit tests. + * These tests make sure that we (a) get a result when we expect to get a results, and (b) will spot-check + * the result, such as looking at the Name. + * + */ + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. + +#include <config.h> +#include <stdio.h> +#include <fcntl.h> + +#include "../ccnxCodec_TlvPacket.c" +#include <parc/algol/parc_SafeMemory.h> + +#include <LongBow/unit-test.h> + +#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h> +#include <ccnx/common/validation/ccnxValidation_HmacSha256.h> + +#include <ccnx/common/ccnx_Interest.h> +#include <ccnx/common/ccnx_ContentObject.h> + +#include <ccnx/common/internal/ccnx_InterestDefault.h> + +#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_interest_bad_message_length.h> + +LONGBOW_TEST_RUNNER(rta_TlvPacket) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(rta_TlvPacket) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(rta_TlvPacket) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, rtaTlvPacket_BufferDecode_V1); + LONGBOW_RUN_TEST_CASE(Global, rtaTlvPacket_BufferDecode_VFF); + + LONGBOW_RUN_TEST_CASE(Global, rtaTlvPacket_IoVecDecode_OneBuffer); + LONGBOW_RUN_TEST_CASE(Global, rtaTlvPacket_IoVecDecode_SeveralBuffer); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_DictionaryEncode_V1); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_DictionaryEncode_VFF); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_Decode_V1); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_Decode_VFF); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_EncodeWithSignature); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_GetPacketLength); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_MinimalHeaderLength); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + 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, rtaTlvPacket_BufferDecode_V1) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + PARCBuffer *interestMessage = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields)); + parcBufferComposer_PutBuffer(composer, interestMessage); + parcBuffer_Release(&interestMessage); + + // Append extraneous data to the end of the buffer to make sure the decoder terminates at the end of the CCNx message. + PARCBuffer *padding = parcBuffer_AllocateCString("ThisShouldNeverBeParsed"); + parcBufferComposer_PutBuffer(composer, padding); + parcBuffer_Release(&padding); + PARCBuffer *packetBuffer = parcBufferComposer_CreateBuffer(composer); + parcBufferComposer_Release(&composer); + parcBuffer_Rewind(packetBuffer); + + //PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields)); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecTlvPacket_BufferDecode(packetBuffer, dict); + assertTrue(success, "Failed to decode good v1 interest"); + + CCNxName *name = ccnxInterest_GetName(dict); + assertNotNull(name, "Did not find a name in the decoded interest"); + + ccnxTlvDictionary_Release(&dict); + parcBuffer_Release(&packetBuffer); +} + +LONGBOW_TEST_CASE(Global, rtaTlvPacket_BufferDecode_VFF) +{ + uint8_t encoded[] = { + 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + + PARCBuffer *packetBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecTlvPacket_BufferDecode(packetBuffer, dict); + assertFalse(success, "Did not fail on decode of version 255 packet"); + + ccnxTlvDictionary_Release(&dict); + parcBuffer_Release(&packetBuffer); +} + +typedef struct allocator_arg { + size_t maxallocation; +} AllocatorArg; + +static size_t +testAllocator(void *userarg, size_t bytes, void **output) +{ + AllocatorArg *arg = userarg; + if (bytes > arg->maxallocation) { + bytes = arg->maxallocation; + } + + *output = parcMemory_Allocate(bytes); + assertNotNull(*output, "parcMemory_Allocate(%zu) returned NULL", bytes); + if (*output) { + return bytes; + } + return 0; +} + +static void +testDeallocator(void *userarg, void **memory) +{ + parcMemory_Deallocate((void **) memory); +} + +const CCNxCodecNetworkBufferMemoryBlockFunctions TestMemoryBlock = { + .allocator = &testAllocator, + .deallocator = &testDeallocator +}; + + +static void +runIoVecTest(AllocatorArg maxalloc) +{ + CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&TestMemoryBlock, &maxalloc); + + ccnxCodecNetworkBuffer_PutArray(netbuff, + sizeof(v1_interest_all_fields), + v1_interest_all_fields); + + CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff); + + CCNxTlvDictionary *output = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END); + + ccnxTlvDictionary_SetMessageType_Interest(output, CCNxTlvDictionary_SchemaVersion_V1); + + bool success = ccnxCodecTlvPacket_IoVecDecode(vec, output); + assertTrue(success, "Failed to decode buffer in iovec format"); + + ccnxTlvDictionary_Release(&output); + ccnxCodecNetworkBufferIoVec_Release(&vec); + ccnxCodecNetworkBuffer_Release(&netbuff); +} + +LONGBOW_TEST_CASE(Global, rtaTlvPacket_IoVecDecode_OneBuffer) +{ + AllocatorArg maxalloc = { .maxallocation = 2048 }; + runIoVecTest(maxalloc); +} + +LONGBOW_TEST_CASE(Global, rtaTlvPacket_IoVecDecode_SeveralBuffer) +{ + // 32 bytes is needed for bookkeeping, so this means we'll have a 32-byte memory block + AllocatorArg maxalloc = { .maxallocation = 64 }; + runIoVecTest(maxalloc); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_DictionaryEncode_V1) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/Antidisestablishmentarianism"); + CCNxTlvDictionary *message = + ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation, + name, CCNxInterestDefault_LifetimeMilliseconds, NULL, NULL, CCNxInterestDefault_HopLimit); + + CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvPacket_DictionaryEncode(message, NULL); + assertNotNull(iovec, "Got null iovec on a good dictionary"); + + ccnxCodecNetworkBufferIoVec_Release(&iovec); + ccnxTlvDictionary_Release(&message); + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_DictionaryEncode_VFF) +{ + CCNxTlvDictionary *message = ccnxTlvDictionary_Create(20, 20); + ccnxTlvDictionary_SetMessageType_Interest(message, 0xFF); + CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvPacket_DictionaryEncode(message, NULL); + assertNull(iovec, "Should have gotten null result for schema version 255"); + ccnxTlvDictionary_Release(&message); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_Decode_V1) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + PARCBuffer *interestMessage = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields)); + parcBufferComposer_PutBuffer(composer, interestMessage); + parcBuffer_Release(&interestMessage); + + // Append extraneous data to the end of the buffer to make sure the decoder terminates at the end of the CCNx message. + PARCBuffer *padding = parcBuffer_AllocateCString("ThisShouldNeverBeParsed"); + parcBufferComposer_PutBuffer(composer, padding); + parcBuffer_Release(&padding); + PARCBuffer *packetBuffer = parcBufferComposer_CreateBuffer(composer); + parcBufferComposer_Release(&composer); + parcBuffer_Rewind(packetBuffer); + + CCNxTlvDictionary *dict = ccnxCodecTlvPacket_Decode(packetBuffer); + assertNotNull(dict, "Got null dictionary decoding good packet"); + + ccnxTlvDictionary_Release(&dict); + parcBuffer_Release(&packetBuffer); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_Decode_VFF) +{ + uint8_t encoded[] = { + 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + + PARCBuffer *packetBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxTlvDictionary *dict = ccnxCodecTlvPacket_Decode(packetBuffer); + assertNull(dict, "Got non-null dictionary decoding version 255 packet"); + parcBuffer_Release(&packetBuffer); +} + + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_EncodeWithSignature) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/foo/bar"); + PARCBuffer *payload = parcBuffer_WrapCString("payload"); + CCNxContentObject *obj = ccnxContentObject_CreateWithNameAndPayload(name, payload); + ccnxName_Release(&name); + parcBuffer_Release(&payload); + + PARCBuffer *secretKey = parcBuffer_WrapCString("abcdefghijklmnopqrstuvwxyx"); + PARCSigner *signer = ccnxValidationHmacSha256_CreateSigner(secretKey); + + // should really scrub the memory + parcBuffer_Release(&secretKey); + + // this was breaking the signature + PARCKeyStore *keyStore = parcSigner_GetKeyStore(signer); + const PARCCryptoHash *secretHash = parcKeyStore_GetVerifierKeyDigest(keyStore); + const PARCBuffer *keyid = parcCryptoHash_GetDigest(secretHash); + ccnxValidationHmacSha256_Set(obj, keyid); + parcCryptoHash_Release((PARCCryptoHash **) &secretHash); + + CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvPacket_DictionaryEncode(obj, signer); + + ccnxCodecNetworkBufferIoVec_Display(iovec, 0); + + int fd = open("/dev/null", O_WRONLY); + assertTrue(fd != -1, "Error opening /dev/null"); + + ssize_t written = writev(fd, ccnxCodecNetworkBufferIoVec_GetArray(iovec), ccnxCodecNetworkBufferIoVec_GetCount(iovec)); + assertTrue(written != -1, "Error writting to /dev/null"); + close(fd); + + ccnxCodecNetworkBufferIoVec_Release(&iovec); + parcSigner_Release(&signer); + ccnxContentObject_Release(&obj); +} + +static uint8_t testDataV1_Interest_AllFields[] = { + 0x01, 0x00, 0x00, 100, // ver = 1, type = interest, length = 100 + 0x20, 0x00, 0x11, 14, // HopLimit = 32, reserved = 0, flags = 0x11, header length = 14 + // ------------------------ + 0x00, 0x01, 0x00, 2, // Interest Lifetime (2 bytes) + 0xEA, 0xEB, + // ------------------------ + 0x00, 0x01, 0x00, 82, // type = interest, length = 82 + // ------------------------ + 0x00, 0x00, 0x00, 8, // type = name, length = 8 + 0x00, 0x02, 0x00, 4, // type = binary, length = 4 + 'c', 'o', 'o', 'l', // "cool" + // ------------------------ + 0x00, 0x02, 0x00, 16, // type = keyid restriction, length = 16 + 0xa0, 0xa1, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, + 0xac, 0xad, 0xae, 0xaf, + // ------------------------ + 0x00, 0x03, 0x00, 32, // type = hash restriction, length = 32 + 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, + 0xcc, 0xcd, 0xce, 0xcf, + // ------------------------ + 0x00, 0x04, 0x00, 1, // Internest payload method (1 byte) + 0x00, + // ------------------------ + 0x00, 0x01, 0x00, 5, // type = payload, length = 5 + 0xD0, 0xD1, 0xD2, 0xD3, + 0xD4, +}; + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_GetPacketLength) +{ + PARCBuffer *packet = parcBuffer_Wrap(testDataV1_Interest_AllFields, sizeof(testDataV1_Interest_AllFields), 0, sizeof(testDataV1_Interest_AllFields)); + size_t packetLength = ccnxCodecTlvPacket_GetPacketLength(packet); + assertTrue(packetLength == sizeof(testDataV1_Interest_AllFields), "Wrong total message length, expected %zu got %zu", sizeof(testDataV1_Interest_AllFields), packetLength); + parcBuffer_Release(&packet); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_MinimalHeaderLength) +{ + assertTrue(ccnxCodecTlvPacket_MinimalHeaderLength() > 0, "ccnxCodecTlvPacket_MinimalHeaderLength failed"); +} + +// ================================================================= + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Global, _decodeV1_Interest); + LONGBOW_RUN_TEST_CASE(Global, _decodeV1_ContentObject); + LONGBOW_RUN_TEST_CASE(Global, _decodeV1_Control); + LONGBOW_RUN_TEST_CASE(Global, _decodeV1_Unknown); + LONGBOW_RUN_TEST_CASE(Global, _decodeV1_Error); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, _decodeV1_Interest) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields)); + CCNxTlvDictionary *dict = _decodeV1(packetBuffer); + assertNotNull(dict, "Error decoding good packet"); + + CCNxName *name = ccnxInterest_GetName(dict); + assertNotNull(name, "Null name in decoded Interest"); + + ccnxTlvDictionary_Release(&dict); + parcBuffer_Release(&packetBuffer); +} + +LONGBOW_TEST_CASE(Global, _decodeV1_ContentObject) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), 0, sizeof(v1_content_nameA_keyid1_rsasha256)); + CCNxTlvDictionary *dict = _decodeV1(packetBuffer); + assertNotNull(dict, "Error decoding good packet"); + + CCNxName *name = ccnxContentObject_GetName(dict); + assertNotNull(name, "Null name in decoded Interest"); + + ccnxTlvDictionary_Release(&dict); + parcBuffer_Release(&packetBuffer); +} + +LONGBOW_TEST_CASE(Global, _decodeV1_Control) +{ + testUnimplemented("V1 control not implemented yet"); +} + +LONGBOW_TEST_CASE(Global, _decodeV1_Unknown) +{ + uint8_t encoded[] = { + 0x01, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + + PARCBuffer *packetBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxTlvDictionary *dict = _decodeV1(packetBuffer); + assertNull(dict, "Should have gotten NULL dictionary from unknown packet type"); + + parcBuffer_Release(&packetBuffer); +} + +LONGBOW_TEST_CASE(Global, _decodeV1_Error) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_bad_message_length, sizeof(v1_interest_bad_message_length), 0, sizeof(v1_interest_bad_message_length)); + CCNxTlvDictionary *dict = _decodeV1(packetBuffer); + assertNull(dict, "Should have gotten NULL dictionary from unknown packet type"); + + parcBuffer_Release(&packetBuffer); +} + +// ================================================================= + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_TlvPacket); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvUtilities.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvUtilities.c new file mode 100644 index 00000000..b8215822 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvUtilities.c @@ -0,0 +1,496 @@ +/* + * 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 "../ccnxCodec_TlvUtilities.c" +#include <parc/algol/parc_SafeMemory.h> + +#include <LongBow/unit-test.h> + +#include <inttypes.h> + +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h> +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.h> +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.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 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(%u) returned NULL", 8); + + // Make a V1 fixed header + memcpy(data->packet, &((uint8_t[]) { + 0x01, // version + 0x01, // packetType + 0x01, 0x02, // packetLength + 0x00, // hopLimit/hopCount + 0x00, // returnCode + 0x03, // flags + 0x04 // headerLength + }), 8); + + + data->fixedHeader = parcBuffer_Wrap(data->packet, 8, 0, 8); + data->version = 1; + data->packetType = 1; + data->packetLength = 0x0102; + data->headerLength = 0x04; + data->decoder = ccnxCodecTlvDecoder_Create(data->fixedHeader); + data->dictionary = ccnxTlvDictionary_Create(10, 10); + return data; +} + +static void +_commonTeardown(TestData *data) +{ + ccnxTlvDictionary_Release(&data->dictionary); + ccnxCodecTlvDecoder_Destroy(&data->decoder); + parcBuffer_Release(&data->fixedHeader); + parcMemory_Deallocate((void **) &(data->packet)); + parcMemory_Deallocate((void **) &data); +} + +LONGBOW_TEST_RUNNER(rta_TlvUtilities) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(rta_TlvUtilities) +{ + 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(rta_TlvUtilities) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_GetVarInt); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_DecodeContainer); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_DecodeSubcontainer); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsName); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsBuffer); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsHash); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsListBuffer); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_NestedEncode); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_EncodeCustomList); +} + +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; +} + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsBuffer) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + uint32_t type = 1; + uint32_t length = 8; + + bool success = ccnxCodecTlvUtilities_PutAsBuffer(data->decoder, data->dictionary, type, length, + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader); + + assertTrue(success, "Failed to save buffer slice"); + + int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion(data->dictionary); + assertTrue(version == data->version, "Wrong version, got %d expected %d", version, data->version); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsHash) +{ + uint8_t encoded[] = { + 0x00, 0x01, 0x00, 0x20, // 0x01 = CCNxCodecSchemaV1Types_HashType_SHA256 + 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); + + uint16_t type = 0x01; + CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, 10); + bool success = ccnxCodecTlvUtilities_PutAsHash(decoder, dictionary, type, sizeof(encoded), + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION); + assertTrue(success, "Failed to save hash"); + + parcBuffer_Release(&tlvBuffer); + ccnxCodecTlvDecoder_Destroy(&decoder); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_GetVarInt) +{ + struct test_vector { + uint64_t value; + bool valid; + int length; + uint8_t *array; + } vectors[] = { + // length 0 invalid + { .value = 0, .valid = false, .length = 0, .array = (uint8_t[]) { 0x00 } }, + { .value = 0, .valid = true, .length = 1, .array = (uint8_t[]) { 0x00 } }, + { .value = 0xFF, .valid = true, .length = 1, .array = (uint8_t[]) { 0xFF } }, + { .value = 0x0001, .valid = true, .length = 2, .array = (uint8_t[]) { 0x00, 0x01} }, + { .value = 0xFF01, .valid = true, .length = 2, .array = (uint8_t[]) { 0xFF, 0x01} }, + { .value = 0x000001, .valid = true, .length = 3, .array = (uint8_t[]) { 0x00, 0x00, 0x01} }, + { .value = 0xFF0001, .valid = true, .length = 3, .array = (uint8_t[]) { 0xFF, 0x00, 0x01} }, + { .value = 0x00000001, .valid = true, .length = 4, .array = (uint8_t[]) { 0x00, 0x00, 0x00, 0x01} }, + { .value = 0xFF002001, .valid = true, .length = 4, .array = (uint8_t[]) { 0xFF, 0x00, 0x20, 0x01} }, + { .value = 0xFF00200103040506ULL, .valid = true, .length = 8, .array = (uint8_t[]) { 0xFF, 0x00, 0x20, 0x01, 0x03, 0x04, 0x05, 0x06} }, + // length 9 invalid + { .value = 0, .valid = false, .length = 9, .array = (uint8_t[]) { 0xFF, 0x00, 0x20, 0x01, 0x03, 0x04, 0x05, 0x06, 0x07} }, + // sentinal is NULL array + { .value = 0, .valid = false, .length = 0, .array = NULL }, + }; + + for (int i = 0; vectors[i].array != NULL; i++) { + PARCBuffer *buffer = parcBuffer_Wrap(vectors[i].array, vectors[i].length, 0, vectors[i].length); + + uint64_t value; + bool success = ccnxCodecTlvUtilities_GetVarInt(buffer, vectors[i].length, &value); + parcBuffer_Release(&buffer); + + assertTrue(success == vectors[i].valid, "index %d: Wrong return, got %d expected %d", i, success, vectors[i].valid); + if (vectors[i].valid) { + assertTrue(value == vectors[i].value, "index %d: wrong value: got %" PRIu64 " expected %" PRIu64, i, value, vectors[i].value); + } + } +} + + +static bool +_decodeSubContainer(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary) +{ + return true; +} + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_DecodeSubcontainer) +{ + uint8_t metadata[] = { + 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, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(metadata, sizeof(metadata), 0, sizeof(metadata)); + + // now decode that snippit + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(20, 20); + + uint16_t key = ccnxCodecTlvDecoder_GetType(decoder); + uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder); + + bool success = ccnxCodecTlvUtilities_DecodeSubcontainer(decoder, dictionary, key, length, _decodeSubContainer); + + assertTrue(success, "Failed to decode metadata container"); + + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + + +static bool +testTypeDecoder(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length) +{ + switch (type) { + case 0x000C: // fallthrough + case 0x000D: + ccnxCodecTlvDecoder_Advance(decoder, length); + return true; + default: + return false; + } +} + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_DecodeContainer) +{ + uint8_t metadataContainer[] = { + 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, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(metadataContainer, sizeof(metadataContainer), 0, sizeof(metadataContainer)); + + // now decode that snippit + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(10, 10); + + bool success = ccnxCodecTlvUtilities_DecodeContainer(decoder, dictionary, testTypeDecoder); + + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); + + assertTrue(success, "The TLV types were known to us"); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsName) +{ + // A list of 2 TLV containers (types 0x000C and 0x000D) + uint8_t nameContainer[] = { + 0x00, 0x00, 0x00, 9, // type = name, length = 9 + 0x00, 0x03, 0x00, 5, // type = binary, length = 5 + 'h', 'e', 'l', 'l', // "hello" + 'o', + }; + + PARCBuffer *buffer = parcBuffer_Wrap(nameContainer, sizeof(nameContainer), 0, sizeof(nameContainer)); + + // now decode that snippit + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(10, 10); + + uint16_t tlvtype = ccnxCodecTlvDecoder_GetType(decoder); + uint16_t tlvlength = ccnxCodecTlvDecoder_GetLength(decoder); + + // Saves "lci:/3=hello" + bool success = ccnxCodecTlvUtilities_PutAsName(decoder, dictionary, tlvtype, tlvlength, 1); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); + + assertTrue(success, "The Name failed to decode or some other error"); + + CCNxName *truth = ccnxName_CreateFromCString("lci:/3=hello"); + CCNxName *test = ccnxTlvDictionary_GetName(dictionary, 1); + assertTrue(ccnxName_Equals(truth, test), "Names not equal") + { + ccnxName_Display(test, 3); + ccnxName_Display(truth, 3); + ccnxName_Release(&truth); + ccnxTlvDictionary_Release(&dictionary); + } + + ccnxName_Release(&truth); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsListBuffer) +{ + uint8_t array[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + PARCBuffer *buffer = parcBuffer_Wrap(array, sizeof(array), 0, sizeof(array)); + + PARCBuffer *truth[3]; + truth[0] = parcBuffer_Wrap(array, sizeof(array), 0, 2); + truth[1] = parcBuffer_Wrap(array, sizeof(array), 2, 3); + truth[2] = parcBuffer_Wrap(array, sizeof(array), 3, 6); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(10, 10); + + // put 3 buffers of {0x01, 0x02} and {0x03} and {0x04, 0x05, x06} on the list + int listkey = 1; + ccnxCodecTlvUtilities_PutAsListBuffer(decoder, dictionary, 0, 2, listkey); + ccnxCodecTlvUtilities_PutAsListBuffer(decoder, dictionary, 1, 1, listkey); + ccnxCodecTlvUtilities_PutAsListBuffer(decoder, dictionary, 2, 3, listkey); + + assertTrue(ccnxTlvDictionary_ListSize(dictionary, listkey) == 3, + "Wrong list size, got %zu expected %u", + ccnxTlvDictionary_ListSize(dictionary, listkey), 3); + + // now make sure they are right + for (int i = 0; i < ccnxTlvDictionary_ListSize(dictionary, listkey); i++) { + PARCBuffer *test = ccnxTlvDictionary_ListGetByType(dictionary, listkey, i); + assertNotNull(test, "Failed to get index %d", i); + + assertTrue(parcBuffer_Equals(truth[i], test), "Buffers not equal for index %d", i) + { + parcBuffer_Display(test, 3); + parcBuffer_Display(truth[i], 3); + } + } + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&truth[0]); + parcBuffer_Release(&truth[1]); + parcBuffer_Release(&truth[2]); + parcBuffer_Release(&buffer); + ccnxTlvDictionary_Release(&dictionary); +} + + + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_NestedEncode) +{ +// TODO: This test needs to be updated with V1 data. +// See BugzID: 3919 + + +// uint8_t metadata[] = { +// 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, +// }; +// +// +// PARCBuffer *truth = parcBuffer_Wrap(metadata, sizeof(metadata), 0, sizeof(metadata)); +// +// // now decode that snippit +// CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(truth); +// CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(20, 20); +// ccnxCodecTlvDecoder_Advance(decoder, 4); +// ccnxCodecTlvUtilities_DecodeContainer(decoder, dictionary, _ccnxCodecSchemaV0MetadataDecoder_DecodeType); +// +// // the dictionary should now be ready for encoding +// ccnxCodecTlvDecoder_Destroy(&decoder); +// +// CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); +// ssize_t length = ccnxCodecTlvUtilities_NestedEncode(encoder, dictionary, 0x000B, ccnxCodecSchemaV0MetadataEncoder_Encode); +// +// assertTrue(length == sizeof(metadata), "Wrong size, got %zu expected %zu", length, sizeof(metadata)); +// +// ccnxCodecTlvEncoder_Finalize(encoder); +// PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); +// assertTrue(parcBuffer_Equals(test, truth), "Buffers do not match") +// { +// parcBuffer_Display(test, 3); +// parcBuffer_Display(truth, 3); +// } +// +// ccnxCodecTlvEncoder_Destroy(&encoder); +// ccnxTlvDictionary_Release(&dictionary); +// parcBuffer_Release(&truth); +// parcBuffer_Release(&test); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_EncodeCustomList) +{ + uint8_t truthArray[] = { 0x00, 0x00, 0x00, 0x02, 0x01, 0x02, + 0x00, 0x01, 0x00, 0x01, 0x03, + 0x00, 0x02, 0x00, 0x03, 0x04, 0x05, 0x06 }; + + PARCBuffer *truth = parcBuffer_Wrap(truthArray, sizeof(truthArray), 0, sizeof(truthArray)); + + PARCBuffer *buffers[3]; + buffers[0] = parcBuffer_Wrap(truthArray, sizeof(truthArray), 4, 6); + buffers[1] = parcBuffer_Wrap(truthArray, sizeof(truthArray), 10, 11); + buffers[2] = parcBuffer_Wrap(truthArray, sizeof(truthArray), 15, 18); + + CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(10, 10); + + // put 3 buffers of {0x01, 0x02} and {0x03} and {0x04, 0x05, x06} on the list + int listkey = 1; + ccnxTlvDictionary_PutListBuffer(dictionary, listkey, 2, buffers[2]); + ccnxTlvDictionary_PutListBuffer(dictionary, listkey, 1, buffers[1]); + ccnxTlvDictionary_PutListBuffer(dictionary, listkey, 0, buffers[0]); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvUtilities_EncodeCustomList(encoder, dictionary, listkey); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + + assertTrue(parcBuffer_Equals(test, truth), "Buffers not equal") + { + parcBuffer_Display(test, 3); + parcBuffer_Display(truth, 3); + } + + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&buffers[0]); + parcBuffer_Release(&buffers[1]); + parcBuffer_Release(&buffers[2]); + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxTlvDictionary_Release(&dictionary); +} + +// ==================================================================================== + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +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; +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_TlvUtilities); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/test/test_random_bytes b/libccnx-common/ccnx/common/codec/test/test_random_bytes Binary files differnew file mode 100644 index 00000000..33a80af5 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/test/test_random_bytes diff --git a/libccnx-common/ccnx/common/codec/test/test_random_bytes.sig b/libccnx-common/ccnx/common/codec/test/test_random_bytes.sig Binary files differnew file mode 100644 index 00000000..9c395ce0 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/test/test_random_bytes.sig diff --git a/libccnx-common/ccnx/common/codec/test/test_rsa.p12 b/libccnx-common/ccnx/common/codec/test/test_rsa.p12 Binary files differnew file mode 100644 index 00000000..471c4006 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/test/test_rsa.p12 diff --git a/libccnx-common/ccnx/common/codec/test/test_rsa_key.pem b/libccnx-common/ccnx/common/codec/test/test_rsa_key.pem new file mode 100644 index 00000000..6c502b15 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/test/test_rsa_key.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQCn1pPF8XPGErX6ecXvGIvvqs0EAY+Ddz+xZqFauTkqsj4w+xH8 +V/yd0S938Kt3rWYsJsibUW9pvyYQBinuy7AsXpEOJEKN5nWgTgRDDD5MBnRnrYTD +6PTFlHPEnyWoQga/RRnimBw2oUNNm3EI4YLf4k8qPD0PNZKucCf70uQeJwIDAQAB +AoGAVOYPA/7aIGSQlu4IOKTDDG3qnM8pSEgG+PbAQgMVrspQ+TfXZj0ftLj++P3N +zpDw8P6BVUfBQs2FNG/ZwEhaiZVgJAl7cIAxJ9Ac+1oZYSgGyJfb3u9iWvkbMOoj +83Inx5yyN+Qmk5zceH4pOC5D5cDAuGGZ740Euv4o2/2O3qECQQDTmWZw021PvEbA +r18O1YfZGxO3zFCwFXCpnHvtSMbP+MXAG5Gt47wZt4Vx1rX9k78beeCUitwqp3d3 +ZI+YlUu3AkEAyw5wssQsJty/n2FL8DbJN3UzUhkcaCFYrKz3RtFye9wu+Bw0TxPC +3jhFVcynm3nH3ZJN0JsnsPnHXuoQToShEQJATXC51hb6zZC5UDGel348fo9zUvP6 +n8bo+ZoknL3izSBdtyYf1cUgBUVuGDCdYFWfPn4HXDXJx+6MQWzTRON21wJBAMZL +U8M/z94jtP3wBjiPR/Dggz2pSBRofDAkuVZvM13BqByjbnHK2oIocY1YTlWGl6fJ +ODR/UEODqS8HZOVIoAECQANcuvVnqDixSIl2ySZvydQytv4DKTbvE0nYSRroYIlJ +PTOBPy8ynIUkJwc2E1BsLl7V8gO62a5O0ntTwBMnPSQ= +-----END RSA PRIVATE KEY----- diff --git a/libccnx-common/ccnx/common/codec/test/testrig_Compare.c b/libccnx-common/ccnx/common/codec/test/testrig_Compare.c new file mode 100755 index 00000000..3dc73a1c --- /dev/null +++ b/libccnx-common/ccnx/common/codec/test/testrig_Compare.c @@ -0,0 +1,90 @@ +/* + * 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. + */ + +/** + * Utilities used by the Schema unit tests to compare buffers + * + */ + +/** + * Compares an encoding buffer to linear memory + * + * Will assert if the memory does not compare. The encoding buffer will be finalized. + * Will assert if the encoder has an error. + * + * @param [in] encoder The encoding buffer to compare + * @param [in] length The length of linear memory + * @param [in] memory The "truth" memory to compare against + * + * Example: + * @code + * <#example#> + * @endcode + */ +void +testCompareEncoderToLinearMemory(CCNxCodecTlvEncoder *encoder, size_t length, uint8_t memory[length]) +{ + assertFalse(ccnxCodecTlvEncoder_HasError(encoder), "Encoder has error") + { + printf("ERROR: %s\n", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + } + + PARCBuffer *truth = parcBuffer_Wrap(memory, length, 0, length); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *buffer = ccnxCodecTlvEncoder_CreateBuffer(encoder); + + assertTrue(parcBuffer_Equals(buffer, truth), "buffers not equal") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + + printf("Got this\n"); + parcBuffer_Display(buffer, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&buffer); +} + +/** + * Compares an encoding buffer to a PARCBuffer + * + * Will assert if the memory does not compare. The encoding buffer will be finalized. + * Will assert if the encoder has an error. + * + * @param [in] encoder The encoding buffer to compare + * @param [in] buffer The buffer to compare to, must be setup to be read (i.e. flipped) + * + * Example: + * @code + * <#example#> + * @endcode + */ +void +testCompareEncoderToBuffer(CCNxCodecTlvEncoder *encoder, PARCBuffer *buffer) +{ + assertFalse(ccnxCodecTlvEncoder_HasError(encoder), "Encoder has error") + { + printf("ERROR: %s\n", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + } + + + uint8_t *linearMemory = parcByteArray_Array(parcBuffer_Array(buffer)); + size_t offset = parcBuffer_ArrayOffset(buffer) + parcBuffer_Position(buffer); + size_t length = parcBuffer_Remaining(buffer); + + testCompareEncoderToLinearMemory(encoder, length, linearMemory + offset); +} + |