// Try for multiple URI path components that still total less than 128
TEST(CAProtocolMessage, CAParseURIManyPath)
{
    char sampleURI[] = "coap://[::]"
        "/medium/a/b/c/d/e/f/g/h/i/j/"
        "?rt=core.sensor;if=core.mi.ll";

    CoAPOptionCase cases[] = {
        {COAP_OPTION_URI_PATH, 6, "medium"},
        {COAP_OPTION_URI_PATH, 1, "a"},
        {COAP_OPTION_URI_PATH, 1, "b"},
        {COAP_OPTION_URI_PATH, 1, "c"},
        {COAP_OPTION_URI_PATH, 1, "d"},
        {COAP_OPTION_URI_PATH, 1, "e"},
        {COAP_OPTION_URI_PATH, 1, "f"},
        {COAP_OPTION_URI_PATH, 1, "g"},
        {COAP_OPTION_URI_PATH, 1, "h"},
        {COAP_OPTION_URI_PATH, 1, "i"},
        {COAP_OPTION_URI_PATH, 1, "j"},
        {COAP_OPTION_URI_QUERY, 14, "rt=core.sensor"},
        {COAP_OPTION_URI_QUERY, 13, "if=core.mi.ll"},
    };
    size_t numCases = sizeof(cases) / sizeof(cases[0]);


    coap_list_t *optlist = NULL;
    CAParseURI(sampleURI, &optlist);


    verifyParsedOptions(cases, numCases, optlist);
    coap_delete_list(optlist);
}
// Test that an initial long path component won't hide latter ones.
TEST(CAProtocolMessage, CAParseURILongPath)
{
    char sampleURI[] = "coap://[::]/oic"
        "123456789012345678901234567890123456789012345678901234567890"
        "12345678901234567890123456789012345678901234567890"
        "/res?rt=core.sensor;if=core.mi.ll";

    CoAPOptionCase cases[] = {
        {COAP_OPTION_URI_PATH, 113, "oic"
	 "123456789012345678901234567890123456789012345678901234567890"
	 "12345678901234567890123456789012345678901234567890"},
        {COAP_OPTION_URI_PATH, 3, "res"},
        {COAP_OPTION_URI_QUERY, 14, "rt=core.sensor"},
        {COAP_OPTION_URI_QUERY, 13, "if=core.mi.ll"},
    };
    size_t numCases = sizeof(cases) / sizeof(cases[0]);


    coap_list_t *optlist = NULL;
    CAParseURI(sampleURI, &optlist);


    verifyParsedOptions(cases, numCases, optlist);
    coap_delete_list(optlist);
}
// Try for multiple URI parameters that still total less than 128
TEST(CAProtocolMessage, CAParseURIManyParams)
{
    char sampleURI[] = "coap://[::]/oic/res/"
        "?rt=core.sensor;a=0;b=1;c=2;d=3;e=4;f=5;g=6;h=7;i=8;j=9";

    CoAPOptionCase cases[] = {
        {COAP_OPTION_URI_PATH, 3, "oic"},
        {COAP_OPTION_URI_PATH, 3, "res"},
        {COAP_OPTION_URI_QUERY, 14, "rt=core.sensor"},
        {COAP_OPTION_URI_QUERY, 3, "a=0"},
        {COAP_OPTION_URI_QUERY, 3, "b=1"},
        {COAP_OPTION_URI_QUERY, 3, "c=2"},
        {COAP_OPTION_URI_QUERY, 3, "d=3"},
        {COAP_OPTION_URI_QUERY, 3, "e=4"},
        {COAP_OPTION_URI_QUERY, 3, "f=5"},
        {COAP_OPTION_URI_QUERY, 3, "g=6"},
        {COAP_OPTION_URI_QUERY, 3, "h=7"},
        {COAP_OPTION_URI_QUERY, 3, "i=8"},
        {COAP_OPTION_URI_QUERY, 3, "j=9"},
    };
    size_t numCases = sizeof(cases) / sizeof(cases[0]);


    coap_list_t *optlist = NULL;
    CAParseURI(sampleURI, &optlist);


    verifyParsedOptions(cases, numCases, optlist);
    coap_delete_list(optlist);
}
coap_pdu_t* CAGeneratePdu(const char* uri, const uint32_t code, const CAInfo_t info)
{
    OIC_LOG(DEBUG, TAG, "generate PDU");

    coap_pdu_t *pdu;
    char* coapUri = NULL;
    uint32_t coapHeaderLength = 12;
    uint32_t length;
    coap_list_t *optlist = NULL;

    if (NULL == uri)
        return NULL;

    length = strlen(uri);
    coapUri = (char*) OICMalloc(length + coapHeaderLength + 1);
    memset(coapUri, 0, length + coapHeaderLength + 1);

    if (NULL != coapUri)
    {

        memcpy(coapUri, "coap://[::]/", coapHeaderLength);
        memcpy(coapUri + coapHeaderLength, uri, length);

        // parsing options in URI
        CAParseURI(coapUri, &optlist);

        // parsing options in HeadOption
        if (NULL != &info)
        {
            CAParseHeadOption(code, info, &optlist);
        }

        OICFree(coapUri);
    }

    if (NULL != info.payload)
    {
        if (!(pdu = CACreatePDUforRequestWithPayload((code_t) code, optlist, info.payload)))
            return NULL;
    }
    else
    {
        if (!(pdu = CACreatePDUforRequest((code_t) code, optlist)))
            return NULL;
    }

    // pdu print method : coap_show_pdu(pdu);

    return pdu;
}
coap_pdu_t *CAGeneratePDU(uint32_t code, const CAInfo_t *info, const CAEndpoint_t *endpoint)
{
    OIC_LOG(DEBUG, TAG, "IN");

    VERIFY_NON_NULL_RET(info, TAG, "info", NULL);
    VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", NULL);

    coap_pdu_t *pdu = NULL;

    // RESET have to use only 4byte (empty message)
    // and ACKNOWLEDGE can use empty message when code is empty.
    if (CA_MSG_RESET == info->type || (CA_EMPTY == code && CA_MSG_ACKNOWLEDGE == info->type))
    {
        OIC_LOG(DEBUG, TAG, "code is empty");
        if (!(pdu = CAGeneratePDUImpl((code_t) code, NULL, info, endpoint)))
        {
            OIC_LOG(ERROR, TAG, "pdu NULL");
            return NULL;
        }
    }
    else
    {
        coap_list_t *optlist = NULL;

        if (CA_MSG_ACKNOWLEDGE != info->type)
        {
            const char *uri = info->resourceUri;
            if (NULL == uri)
            {
                OIC_LOG(ERROR, TAG, "uri NULL");
                return NULL;
            }

            uint32_t length = strlen(uri);
            if (CA_MAX_URI_LENGTH < length)
            {
                OIC_LOG(ERROR, TAG, "URI len err");
                return NULL;
            }

            uint32_t uriLength = length + sizeof(COAP_URI_HEADER);
            char *coapUri = (char *) OICCalloc(1, uriLength);
            if (NULL == coapUri)
            {
                OIC_LOG(ERROR, TAG, "out of memory");
                return NULL;
            }
            OICStrcat(coapUri, uriLength, COAP_URI_HEADER);
            OICStrcat(coapUri, uriLength, uri);

            // parsing options in URI
            CAResult_t res = CAParseURI(coapUri, &optlist);
            if (CA_STATUS_OK != res)
            {
                if (optlist)
                {
                    coap_delete_list(optlist);
                }
                OICFree(coapUri);
                return NULL;
            }

            OICFree(coapUri);
        }
        // parsing options in HeadOption
        CAResult_t ret = CAParseHeadOption(code, info, &optlist);
        if (CA_STATUS_OK != ret)
        {
            coap_delete_list(optlist);
            return NULL;
        }

        pdu = CAGeneratePDUImpl((code_t) code, optlist, info, endpoint);
        if (NULL == pdu)
        {
            OIC_LOG(ERROR, TAG, "pdu NULL");
            coap_delete_list(optlist);
            return NULL;
        }

        // free option list
        coap_delete_list(optlist);
    }

    // pdu print method : coap_show_pdu(pdu);
    OIC_LOG(DEBUG, TAG, "OUT");
    return pdu;
}
coap_pdu_t *CAGeneratePDU(uint32_t code, const CAInfo_t *info, const CAEndpoint_t *endpoint,
                          coap_list_t **optlist, coap_transport_t *transport)
{
    VERIFY_NON_NULL_RET(info, TAG, "info", NULL);
    VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", NULL);
    VERIFY_NON_NULL_RET(optlist, TAG, "optlist", NULL);

    OIC_LOG_V(DEBUG, TAG, "generate pdu for [%d]adapter, [%d]flags",
              endpoint->adapter, endpoint->flags);

    coap_pdu_t *pdu = NULL;

    // RESET have to use only 4byte (empty message)
    // and ACKNOWLEDGE can use empty message when code is empty.
    if (CA_MSG_RESET == info->type || (CA_EMPTY == code && CA_MSG_ACKNOWLEDGE == info->type))
    {
        if (CA_EMPTY != code)
        {
            OIC_LOG(ERROR, TAG, "reset is not empty message");
            return NULL;
        }

        if (info->payloadSize > 0 || info->payload || info->token || info->tokenLength > 0)
        {
            OIC_LOG(ERROR, TAG, "Empty message has unnecessary data after messageID");
            return NULL;
        }

        OIC_LOG(DEBUG, TAG, "code is empty");
        if (!(pdu = CAGeneratePDUImpl((code_t) code, info, endpoint, NULL, transport)))
        {
            OIC_LOG(ERROR, TAG, "pdu NULL");
            return NULL;
        }
    }
    else
    {
        if (info->resourceUri)
        {
            OIC_LOG_V(DEBUG, TAG, "uri : %s", info->resourceUri);

            uint32_t length = strlen(info->resourceUri);
            if (CA_MAX_URI_LENGTH < length)
            {
                OIC_LOG(ERROR, TAG, "URI len err");
                return NULL;
            }

            uint32_t uriLength = length + sizeof(COAP_URI_HEADER);
            char *coapUri = (char *) OICCalloc(1, uriLength);
            if (NULL == coapUri)
            {
                OIC_LOG(ERROR, TAG, "out of memory");
                return NULL;
            }
            OICStrcat(coapUri, uriLength, COAP_URI_HEADER);
            OICStrcat(coapUri, uriLength, info->resourceUri);

            // parsing options in URI
            CAResult_t res = CAParseURI(coapUri, optlist);
            if (CA_STATUS_OK != res)
            {
                OICFree(coapUri);
                return NULL;
            }

            OICFree(coapUri);
        }
        // parsing options in HeadOption
        CAResult_t ret = CAParseHeadOption(code, info, optlist);
        if (CA_STATUS_OK != ret)
        {
            return NULL;
        }

        pdu = CAGeneratePDUImpl((code_t) code, info, endpoint, *optlist, transport);
        if (NULL == pdu)
        {
            OIC_LOG(ERROR, TAG, "pdu NULL");
            return NULL;
        }
    }

    // pdu print method : coap_show_pdu(pdu);
    return pdu;
}