/*
**  Licensed to the Apache Software Foundation (ASF) under one or more
** contributor license agreements.  See the NOTICE file distributed with
** this work for additional information regarding copyright ownership.
** The ASF licenses this file to You 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 "apreq_param.h"
#include "apreq_util.h"
#include "apreq_error.h"
#include "apr_strings.h"
#include "at.h"


static const char query_string[] = "a=1;quux=foo+bar&a=2&plus=%2B;"
                                   "uplus=%U002b;okie=dokie;foo=a%E1;"
                                   "novalue1;novalue2=";
static apr_table_t *args;
static apr_pool_t *p;


static void request_make(dAT)
{
    apr_status_t s;
    args = apr_table_make(p, APREQ_DEFAULT_NELTS);
    AT_not_null(args);
    s = apreq_parse_query_string(p, args, query_string);
    AT_int_eq(s, APR_SUCCESS);
    AT_int_eq(apr_table_elts(args)->nelts, 9);
}


static void request_args_get(dAT)
{
    const char *val;
    const apreq_param_t *param;

    AT_str_eq(apr_table_get(args,"a"), "1");

    val = apr_table_get(args,"quux");
    AT_str_eq(val, "foo bar");
    param = apreq_value_to_param(val);
    AT_int_eq(param->v.dlen, 7);

    AT_str_eq(apr_table_get(args,"plus"), "+");
    AT_str_eq(apr_table_get(args,"uplus"), "+");
    AT_str_eq(apr_table_get(args,"okie"), "dokie");
    AT_str_eq(apr_table_get(args,"novalue1"), "");
    AT_str_eq(apr_table_get(args,"novalue2"),"");
}

static void params_as(dAT)
{
    const char *val;
    apr_array_header_t *arr;
    arr = apreq_params_as_array(p,args,"a");
    AT_int_eq(arr->nelts, 2);
    val = apreq_params_as_string(p,args,"a",APREQ_JOIN_AS_IS);
    AT_str_eq(val, "1, 2");
    val = apreq_params_as_string(p,args,"does_not_exist",APREQ_JOIN_AS_IS);
    AT_str_eq(val, "");
}

static void string_decoding_in_place(dAT)
{
    char *s1 = apr_palloc(p,4096);
    char *s2 = apr_palloc(p,4096);
    char *s3;

    strcpy(s1, "bend it like beckham");
    strcpy(s2, "dandy %3Edons");

    AT_str_eq(s1,"bend it like beckham");
    apreq_unescape(s1);
    AT_str_eq(s1, "bend it like beckham");
    s3 = apreq_escape(p, s1, 20);
    AT_str_eq(s3, "bend+it+like+beckham");
    apreq_unescape(s3);
    AT_str_eq(s3,"bend it like beckham");

    AT_str_eq(s2,"dandy %3Edons");
    apreq_unescape(s2);
    AT_str_eq(s2,"dandy >dons");
    s3 = apreq_escape(p, s2, 11);
    AT_str_eq(s3,"dandy+%3Edons");
    apreq_unescape(s3);
    AT_str_eq(s3,"dandy >dons");
}

static void header_attributes(dAT)
{
    const char *hdr = "text/plain; boundary=\"-foo-\", charset=ISO-8859-1";
    const char *val;
    apr_size_t vlen;
    apr_status_t s;

    s = apreq_header_attribute(hdr, "none", 4, &val, &vlen);
    AT_int_eq(s, APREQ_ERROR_NOATTR);

    s = apreq_header_attribute(hdr, "set", 3, &val, &vlen);
    AT_int_eq(s, APREQ_ERROR_NOATTR);

    s = apreq_header_attribute(hdr, "boundary", 8, &val, &vlen);
    AT_int_eq(s, APR_SUCCESS);
    AT_int_eq(vlen, 5);
    AT_mem_eq(val, "-foo-", 5);

    s = apreq_header_attribute(hdr, "charset", 7, &val, &vlen);
    AT_int_eq(s, APR_SUCCESS);
    AT_int_eq(vlen, 10);
    AT_mem_eq(val, "ISO-8859-1", 10);

    hdr = "max-age=20; no-quote=\"...";

    s = apreq_header_attribute(hdr, "max-age", 7, &val, &vlen);
    AT_int_eq(s, APR_SUCCESS);
    AT_int_eq(vlen, 2);
    AT_mem_eq(val, "20", 2);

    s = apreq_header_attribute(hdr, "age", 3, &val, &vlen);
    AT_int_eq(s, APREQ_ERROR_BADSEQ);

    s = apreq_header_attribute(hdr, "no-quote", 8, &val, &vlen);
    AT_int_eq(s, APREQ_ERROR_BADSEQ);

}


static void make_param(dAT)
{
    apreq_param_t *param, *decode;
    apr_status_t s;
    apr_size_t nlen = 3, vlen = 11;
    char *name = apr_palloc(p,nlen+1);
    char *val = apr_palloc(p,vlen+1);
    char *encode;
    strcpy(name, "foo");
    strcpy(val, "bar > alpha");

    param = apreq_param_make(p, name, nlen, val, vlen);
    AT_str_eq(param->v.name, name);
    AT_int_eq(param->v.dlen, vlen);
    AT_str_eq(param->v.data, val);

    encode = apreq_param_encode(p, param);
    AT_str_eq(encode, "foo=bar+%3E+alpha");

    s = apreq_param_decode(&decode, p, encode, nlen, vlen+2);
    AT_int_eq(s, APR_SUCCESS);
    AT_str_eq(decode->v.name, name);
    AT_int_eq(decode->v.dlen, vlen);
    AT_str_eq(decode->v.data, val);
}

static void quote_strings(dAT)
{
    apr_size_t exp_len, res_len, res_quote_len;
    char *res = apr_palloc(p,24);
    char *res_quote = apr_palloc(p,24);
    const char *expr;
    int i;
    const char * arr[] = {"cest", "\"cest", "ce\"st", "\"cest\""};
    const char * arr_quote[] =
        {"\"cest\"", "\"\\\"cest\"", "\"ce\\\"st\"", "\"\\\"cest\\\"\""};
    apr_size_t arr_len[] = {4, 5, 5, 6};
    apr_size_t arr_quote_len[] = {6, 8, 8, 10};

    for (i=0; i<4; i++) {
        res_len = apreq_quote(res, arr[i], arr_len[i]);
        AT_int_eq(res_len, arr_quote_len[i]);
        AT_mem_eq(res, arr_quote[i], res_len);
        res_quote_len = apreq_quote_once(res_quote, res, res_len);
        AT_int_eq(res_quote_len, res_len);
        AT_mem_eq(res_quote, res, res_len);
        res_len = apreq_quote_once(res, arr[i], arr_len[i]);
        exp_len = (i == 3) ? arr_len[i] : arr_quote_len[i];
        expr = (i == 3) ? arr[i] : arr_quote[i];
        AT_int_eq(res_len, exp_len);
        AT_mem_eq(res, expr, exp_len);
    }
}

#define dT(func, plan) {#func, func, plan}

int main(int argc, char *argv[])
{
    unsigned i, plan = 0;
    dAT;
    at_test_t test_list [] = {
        dT(request_make, 3),
        dT(request_args_get, 8),
        dT(params_as, 3),
        dT(string_decoding_in_place, 8),
        dT(header_attributes, 13),
        dT(make_param, 8),
        dT(quote_strings, 24),
    };

    apr_initialize();
    atexit(apr_terminate);
    apr_pool_create(&p, NULL);

    apreq_initialize(p);

    AT = at_create(p, 0, at_report_stdout_make(p));
    AT_trace_on();
    for (i = 0; i < sizeof(test_list) / sizeof(at_test_t);  ++i)
        plan += test_list[i].plan;

    AT_begin(plan);

    for (i = 0; i < sizeof(test_list) / sizeof(at_test_t);  ++i)
        AT_run(&test_list[i]);

    AT_end();

    return 0;
}

