LONGBOW_TEST_CASE(Global, cpiAddressList_Equals_same_lists)
{
    CPIAddressList *a = cpiAddressList_Create();
    CPIAddressList *b = cpiAddressList_Create();
    cpiAddressList_Append(a, cpiAddress_CreateFromInterface(1));
    cpiAddressList_Append(a, cpiAddress_CreateFromInterface(2));
    cpiAddressList_Append(b, cpiAddress_CreateFromInterface(1));
    cpiAddressList_Append(b, cpiAddress_CreateFromInterface(2));
    assertTrue(cpiAddressList_Equals(a, b), "same lists not equal, that's wrong");
    cpiAddressList_Destroy(&a);
    cpiAddressList_Destroy(&b);
}
LONGBOW_TEST_CASE(Global, cpiAddressList_Equals_wrong_order)
{
    CPIAddressList *a = cpiAddressList_Create();
    CPIAddressList *b = cpiAddressList_Create();
    cpiAddressList_Append(a, cpiAddress_CreateFromInterface(1));
    cpiAddressList_Append(a, cpiAddress_CreateFromInterface(2));
    cpiAddressList_Append(b, cpiAddress_CreateFromInterface(2));
    cpiAddressList_Append(b, cpiAddress_CreateFromInterface(1));
    assertFalse(cpiAddressList_Equals(a, b), "out of order lists equal, that's wrong");
    cpiAddressList_Destroy(&a);
    cpiAddressList_Destroy(&b);
}
LONGBOW_TEST_CASE(Global, cpiAddress_CreateFromInterface)
{
    uint32_t ifidx = 0x01020304;
    uint32_t test;

    CPIAddress *address = cpiAddress_CreateFromInterface(ifidx);

    bool success = cpiAddress_GetInterfaceIndex(address, &test);
    assertTrue(success, "Got false converting back address");

    assertTrue(ifidx == test, "Got mismatch addressed");

    assertTrue(cpiAddress_GetType(address) == cpiAddressType_IFACE,
               "Got wrong address type, expected %d, got %d", cpiAddressType_IFACE, cpiAddress_GetType(address));

    PARCJSON *json = cpiAddress_ToJson(address);
    CPIAddress *fromjson = cpiAddress_CreateFromJson(json);

    assertTrue(parcBuffer_Equals(address->blob, fromjson->blob), "fromjson blob does not equal known address");
    assertTrue(cpiAddress_Equals(address, fromjson), "cpiAddress_Equals broken for IFACE type");

    CPIAddress *copy = cpiAddress_Copy(address);
    assertTrue(cpiAddress_Equals(copy, address), "Copy and address not equal for IFACE");

    parcJSON_Release(&json);
    cpiAddress_Destroy(&address);
    cpiAddress_Destroy(&copy);
    cpiAddress_Destroy(&fromjson);
}
LONGBOW_TEST_CASE(Local, _cpiAddressList_FreeAddress)
{
    CPIAddress *address = cpiAddress_CreateFromInterface(1);
    _cpiAddressList_FreeAddress((void **) &address);

    assertTrue(parcMemory_Outstanding() == 0, "Got memory imbalance: %u", parcMemory_Outstanding());
}
LONGBOW_TEST_CASE(Global, cpiAddressList_Equals_unequal_sizes)
{
    CPIAddressList *a = cpiAddressList_Create();
    CPIAddressList *b = cpiAddressList_Create();
    cpiAddressList_Append(a, cpiAddress_CreateFromInterface(1));
    assertFalse(cpiAddressList_Equals(a, b), "length 0 == length 1, that's wrong");
    cpiAddressList_Destroy(&a);
    cpiAddressList_Destroy(&b);
}
LONGBOW_TEST_CASE(Global, cpiAddress_Copy)
{
    CPIAddress *a = cpiAddress_CreateFromInterface(1);
    CPIAddress *b = cpiAddress_Copy(a);

    assertTrue(cpiAddress_Equals(a, b), "Copy did not compare as equal: %s and %s", cpiAddress_ToString(a), cpiAddress_ToString(b));

    cpiAddress_Destroy(&a);
    cpiAddress_Destroy(&b);
}
LONGBOW_TEST_CASE(Global, cpiAddress_BuildString)
{
    CPIAddress *address = cpiAddress_CreateFromInterface(1);
    uint32_t beforeBalance = parcMemory_Outstanding();
    PARCBufferComposer *composer = cpiAddress_BuildString(address, parcBufferComposer_Create());
    parcBufferComposer_Release(&composer);
    uint32_t afterBalance = parcMemory_Outstanding();

    cpiAddress_Destroy(&address);
    assertTrue(beforeBalance == afterBalance, "Memory leak off by %d allocations", (int) (afterBalance - beforeBalance));
}
static CCNxControl *
customWriteReadResponse(void *userdata, CCNxMetaMessage *messageToWrite)
{
    CPIRouteEntryList *routeEntryList = cpiRouteEntryList_Create();
    CPIAddress *nexthop = cpiAddress_CreateFromInterface(10);
    CPIRouteEntry *route = cpiRouteEntry_Create(ccnxName_CreateFromURI("lci:/foo"),
                                                1,
                                                nexthop,
                                                cpiNameRouteProtocolType_STATIC,
                                                cpiNameRouteType_LONGEST_MATCH,
                                                &((struct timeval) { 100, 0 }), // lifetime
                                                1);   // cost
LONGBOW_TEST_CASE(Global, cpiAddress_ToString_IFACE)
{
    char truth_str[] = "{ .type=IFACE, .data={ .ifidx=55 } }";

    CPIAddress *cpiaddr = cpiAddress_CreateFromInterface(55);
    char *output = cpiAddress_ToString(cpiaddr);

    assertTrue(strcmp(output, truth_str) == 0, "Bad string, expected %s got %s", truth_str, output);

    parcMemory_Deallocate((void **) &output);
    cpiAddress_Destroy(&cpiaddr);
}
LONGBOW_TEST_CASE(Global, cpiAddressList_GetItem)
{
    CPIAddressList *list = cpiAddressList_Create();
    unsigned loops = 10;

    for (unsigned i = 0; i < loops; i++) {
        cpiAddressList_Append(list, cpiAddress_CreateFromInterface(i));
    }

    assertTrue(cpiAddressList_Length(list) == loops,
               "Got wrong length, expected %u got %zu",
               loops,
               cpiAddressList_Length(list));

    CPIAddress *truth = cpiAddress_CreateFromInterface(5);
    const CPIAddress *test = cpiAddressList_GetItem(list, 5);
    assertTrue(cpiAddress_Equals(truth, test), "Item 5 did not match!");

    cpiAddressList_Destroy(&list);
    cpiAddress_Destroy(&truth);
}
static CCNxControl *
customWriteReadResponse(void *userdata, CCNxMetaMessage *messageToWrite)
{
    CPIConnectionList *connlist = cpiConnectionList_Create();
    CPIConnection *conn = cpiConnection_Create(1, cpiAddress_CreateFromInterface(1), cpiAddress_CreateFromInterface(2), cpiConnection_L2);
    cpiConnectionList_Append(connlist, conn);

    PARCJSON *connectionListAsJson = cpiConnectionList_ToJson(connlist);

    CCNxControl *inboundControlMessage = ccnxMetaMessage_GetControl(messageToWrite);

    // Create a response to the inbound Control message.
    CCNxControl *outboundControlMessage = cpi_CreateResponse(inboundControlMessage, connectionListAsJson);
    parcJSON_Release(&connectionListAsJson);

    ccnxControl_Release(&inboundControlMessage);

    cpiConnectionList_Destroy(&connlist);

    return outboundControlMessage;
}
LONGBOW_TEST_CASE(Local, _IfaceToString)
{
    char truth_str[] = "{ .ifidx=55 }";

    CPIAddress *cpiaddr = cpiAddress_CreateFromInterface(55);

    char output[1024];
    ssize_t output_length = _IfaceToString(output, 1024, cpiaddr->blob);
    assertTrue(strcmp(output, truth_str) == 0, "Bad string, expected %s got %s", truth_str, output);
    assertTrue(strlen(truth_str) == output_length, "Got wrong output size, expected %zd got %zd", strlen(truth_str), output_length);

    cpiAddress_Destroy(&cpiaddr);
}
LONGBOW_TEST_CASE(Global, cpiAddressList_Append)
{
    CPIAddressList *list = cpiAddressList_Create();
    unsigned loops = 10;

    for (unsigned i = 0; i < loops; i++) {
        cpiAddressList_Append(list, cpiAddress_CreateFromInterface(i));
    }

    assertTrue(cpiAddressList_Length(list) == loops,
               "Got wrong length, expected %u got %zu",
               loops,
               cpiAddressList_Length(list));

    cpiAddressList_Destroy(&list);
}
LONGBOW_TEST_CASE(Global, cpiAddress_Equals_NotEqual)
{
    struct sockaddr_in addr_in;
    memset(&addr_in, 0, sizeof(struct sockaddr_in));

    addr_in.sin_addr.s_addr = 0x01020304;
    addr_in.sin_family = AF_INET;
    addr_in.sin_port = 0x0A0B;

    CPIAddress *a = cpiAddress_CreateFromInet(&addr_in);
    CPIAddress *b = cpiAddress_CreateFromInterface(1);

    assertFalse(cpiAddress_Equals(a, b), "Equals failed on different addresses: %s and %s", cpiAddress_ToString(a), cpiAddress_ToString(b));

    cpiAddress_Destroy(&a);
    cpiAddress_Destroy(&b);
}
LONGBOW_TEST_CASE(Global, cpiAddressList_ToFromJSON)
{
    CPIAddressList *truth_list = cpiAddressList_Create();
    int loops = 2;
    for (int i = 0; i < loops; i++) {
        cpiAddressList_Append(truth_list, cpiAddress_CreateFromInterface(i));
    }

    PARCJSONArray *json = cpiAddressList_ToJson(truth_list);

    CPIAddressList *test_list = cpiAddressList_CreateFromJson(json);

    assertTrue(cpiAddressList_Equals(truth_list, test_list), "Lists did not match!");

    cpiAddressList_Destroy(&truth_list);
    cpiAddressList_Destroy(&test_list);
    parcJSONArray_Release(&json);
}
LONGBOW_TEST_CASE(Global, cpiAddressList_ToString)
{
    CPIAddressList *truth_list = cpiAddressList_Create();
    int loops = 2;
    for (int i = 0; i < loops; i++) {
        cpiAddressList_Append(truth_list, cpiAddress_CreateFromInterface(i));
    }

    uint32_t beforeMemory = parcMemory_Outstanding();
    char *string = cpiAddressList_ToString(truth_list);
    assertNotNull(string, "Got null string from ToString");
    parcMemory_Deallocate((void **) &string);
    uint32_t afterMemory = parcMemory_Outstanding();

    cpiAddressList_Destroy(&truth_list);

    assertTrue(beforeMemory == afterMemory, "Memory leak from ToString by %d allocations", (int) (afterMemory - beforeMemory));
}
LONGBOW_TEST_CASE(Global, cpiAddressList_ToJSON)
{
    char truth[] = "[{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAAAA==\"},{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAAAQ==\"}]";

    CPIAddressList *a = cpiAddressList_Create();
    int loops = 2;
    for (int i = 0; i < loops; i++) {
        cpiAddressList_Append(a, cpiAddress_CreateFromInterface(i));
    }

    PARCJSONArray *jsonArray = cpiAddressList_ToJson(a);
    char *test = parcJSONArray_ToCompactString(jsonArray);

    assertTrue(strcmp(truth, test) == 0, "JSON strings did not match, got '%s' expected '%s'", test, truth);

    cpiAddressList_Destroy(&a);
    parcMemory_Deallocate((void **) &test);
    parcJSONArray_Release(&jsonArray);
}
LONGBOW_TEST_CASE(Global, cpiAddressList_FromJSON)
{
    char json_str[] = "{\"ARRAY\":[{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAAAA==\"},{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAAAQ==\"}]}";
    PARCJSON *json = parcJSON_ParseString(json_str);

    PARCJSONArray *jsonArray = parcJSONValue_GetArray(parcJSON_GetValueByIndex(json, 0));

    CPIAddressList *test_list = cpiAddressList_CreateFromJson(jsonArray);

    CPIAddressList *truth_list = cpiAddressList_Create();
    int loops = 2;
    for (int i = 0; i < loops; i++) {
        cpiAddressList_Append(truth_list, cpiAddress_CreateFromInterface(i));
    }

    assertTrue(cpiAddressList_Equals(truth_list, test_list), "Lists did not match!");

    cpiAddressList_Destroy(&truth_list);
    cpiAddressList_Destroy(&test_list);
    parcJSON_Release(&json);
}
LONGBOW_TEST_CASE(Global, cpiAddressList_Copy)
{
    CPIAddressList *list = cpiAddressList_Create();
    unsigned loops = 10;

    for (unsigned i = 0; i < loops; i++) {
        cpiAddressList_Append(list, cpiAddress_CreateFromInterface(i));
    }

    CPIAddressList *copy = cpiAddressList_Copy(list);
    assertTrue(cpiAddressList_Length(copy) == cpiAddressList_Length(list),
               "Copy wrong size, got %zu expected %zu",
               cpiAddressList_Length(copy),
               cpiAddressList_Length(list));

    for (unsigned i = 0; i < cpiAddressList_Length(copy); i++) {
        const CPIAddress *truth = cpiAddressList_GetItem(list, i);
        const CPIAddress *test = cpiAddressList_GetItem(copy, i);
        assertTrue(cpiAddress_Equals(truth, test), "Lists do not match at element %u", i);
    }

    cpiAddressList_Destroy(&list);
    cpiAddressList_Destroy(&copy);
}