/* unit-inifile.c
 *
 * vim:smartindent ts=8:sts=2:sta:et:ai:shiftwidth=2
 ****************************************************************
 * Copyright (C) 2005, Canonical Limited
 *               Author: Robert Collins
 *
 * See the file "COPYING" for further information about
 * the copyright and warranty status of this work.
 */


#include "hackerlab/vu/safe-printfmt.h"
#include "hackerlab/bugs/panic.h"
#include "hackerlab/char/str.h"
#include "libfsutils/file-contents.h"
#include "libfsutils/rmrf.h"
#include "libinifile/inifile.h"



/* typedefs */



/* local methods */

static void
check_line_types (void)
{
    static t_uchar const * lines[]={
    "[sec",
    " []",
    " [section]",
    "[section]  ",
    " #",
    "#",
    " ;",
    "",
    " comment",
    "key",
    "key=",
    " key=foo",
    "key=foo; "
    };
    static inifile_line_type_t types[]={
    INIFILE_COMMENT,
    INIFILE_SECTION,
    INIFILE_SECTION,
    INIFILE_SECTION,
    INIFILE_COMMENT,
    INIFILE_COMMENT,
    INIFILE_COMMENT,
    INIFILE_COMMENT,
    INIFILE_COMMENT,
    INIFILE_COMMENT,
    INIFILE_KEY,
    INIFILE_KEY,
    INIFILE_KEY,
    };
    int entry;
    for (entry = 0; entry < 11; ++entry)
      {
        // safe_printfmt (2, "%s\n", lines[entry]);
        invariant_int_cmp (inifile_line_type (lines[entry]), types[entry]);
      }
}

static void
check_parse_call (t_uchar * (*fn)(t_uchar const *), t_uchar const *input, t_uchar const *output)
{
    t_uchar *temp;
    temp = fn (input);
    invariant_str_cmp (temp, output);
    lim_free (0, temp);
}

static void
check_section_parsing (void)
{
    check_parse_call (inifile_section_name, "[section1]", "section1");
    check_parse_call (inifile_section_name, " [section2]", "section2");
    check_parse_call (inifile_section_name, " [section3] ", "section3");
    check_parse_call (inifile_section_name, " [] ", "");
}

static void
check_key_parse (t_uchar const *input, t_uchar const *key, t_uchar const *value, t_uchar const * comment)
{
    check_parse_call (inifile_key_name, input, key);
    check_parse_call (inifile_value, input, value);
    check_parse_call (inifile_comment, input, comment);
}

static void
check_key_parsing (void)
{
    check_key_parse ("key1=", "key1", "", "");
    check_key_parse (" key2  = ", "key2", " ", "");
    check_key_parse ("  key3  =; ", "key3", "", " ");
    check_key_parse ("allowed_ids=john@example.com E123344", "allowed_ids", "john@example.com E123344", "");
    check_key_parse (" ## comment", "", "", " ## comment");
}

static t_uchar const *sample_default_ini=
"[Signing]\n"
"#use gnome-gpg\n"
"gpg_command=gnome-gpg\n";

static t_uchar const *sample_ini=
"# This file lists the locations that demo@example.com has been seen at\n"
"# with recorded performance and capabilities.\n"
"# It is a .ini format file. See the system documentation for the full format.\n"
"[Locations]\n"
"URL=archives/demo@example.com master;comment\n"
"URL=http://example.org/%7ejoepublic/archives/demo@example.com\n"
"[Signing]\n"
"# shared archive between two people\n"
"# allow john@example.com or key E123344 and also key with fingerprint E12...\n"
"allowed_ids=john@example.com E123344\n"
"allowed_fingerprints=E12345677627865429642964236266\n"
"validate_creator=error\n"
"validate_archivename=ignore\n"
"with_brackets_in_value=f(o)o\n";

static void
rambling_test (void)
{
    /* declare an inifile */
    inifile_t inifile;
    rel_table section_keys;
    rel_table key_values;
    
    /* bringin a disk file */
    inifile_init (&inifile);
    invariant (inifile.content == NULL);
    file_set_contents (",,testini", sample_default_ini);
    invariant_int_cmp (inifile_load (&inifile, ",,testini"), 0);
    rmrf_file(",,testini");
    section_keys = inifile_get_section (&inifile, "signing");
    invariant_int_cmp (2, rel_n_records (section_keys));
    rel_free_table (section_keys);
    inifile_finalise (&inifile);
    invariant (inifile.content == NULL);
    
    /* process a text chunk */
    inifile_init (&inifile);
    invariant_int_cmp (inifile_process_text (&inifile, sample_ini), 0);

    section_keys = inifile_get_section (&inifile, "locations");
    invariant_int_cmp (1, rel_n_records (section_keys));
    invariant_str_cmp ("URL", section_keys[0][0]);
    key_values = inifile_get_key_values (&inifile, "locations", "url");
    invariant_int_cmp (2, rel_n_records (key_values));
    invariant_str_cmp ("archives/demo@example.com master", key_values[0][0]);
    invariant_str_cmp ("comment", key_values[0][1]);
    invariant_str_cmp ("http://example.org/%7ejoepublic/archives/demo@example.com", key_values[1][0]);
    rel_free_table (key_values);
    rel_free_table (section_keys);
    
    section_keys = inifile_get_section (&inifile, "signing");
    invariant_int_cmp (6, rel_n_records (section_keys));
    invariant_str_cmp ("", section_keys[0][0]);
    key_values = inifile_get_key_values (&inifile, "signing", "");
    invariant_int_cmp (2, rel_n_records (key_values));
    invariant_str_cmp ("# shared archive between two people", key_values[0][1]);
    invariant_str_cmp ("# allow john@example.com or key E123344 and also key with fingerprint E12...", key_values[1][1]);
    rel_free_table (key_values);
    invariant_str_cmp ("allowed_ids", section_keys[1][0]);
    key_values = inifile_get_key_values (&inifile, "signing", "allowed_ids");
    invariant_int_cmp (1, rel_n_records (key_values));
    invariant_str_cmp ("john@example.com E123344", key_values[0][0]);
    invariant_str_cmp ("", key_values[0][1]);
    rel_free_table (key_values);
    invariant_str_cmp ("allowed_fingerprints", section_keys[2][0]);
    key_values = inifile_get_key_values (&inifile, "signing", "allowed_fingerprints");
    invariant_int_cmp (1, rel_n_records (key_values));
    invariant_str_cmp ("E12345677627865429642964236266", key_values[0][0]);
    invariant_str_cmp ("", key_values[0][1]);
    rel_free_table (key_values);
    invariant_str_cmp ("validate_creator", section_keys[3][0]);
    key_values = inifile_get_key_values (&inifile, "signing", "validate_creator");
    invariant_int_cmp (1, rel_n_records (key_values));
    invariant_str_cmp ("error", key_values[0][0]);
    invariant_str_cmp ("", key_values[0][1]);
    rel_free_table (key_values);
    invariant_str_cmp ("validate_archivename", section_keys[4][0]);
    key_values = inifile_get_key_values (&inifile, "signing", "validate_archivename");
    invariant_int_cmp (1, rel_n_records (key_values));
    invariant_str_cmp ("ignore", key_values[0][0]);
    invariant_str_cmp ("", key_values[0][1]);
    rel_free_table (key_values);
    invariant_str_cmp ("with_brackets_in_value", section_keys[5][0]);
    key_values = inifile_get_key_values (&inifile, "signing", "with_brackets_in_value");
    invariant_int_cmp (1, rel_n_records (key_values));
    invariant_str_cmp ("f(o)o", key_values[0][0]);
    invariant_str_cmp ("", key_values[0][1]);
    rel_free_table (key_values);
    rel_free_table (section_keys);

    inifile_finalise (&inifile);

    /* process two text chunks (default + override) */
    inifile_init (&inifile);
    invariant_int_cmp (inifile_process_text (&inifile, sample_default_ini), 0);
    invariant_int_cmp (inifile_process_text (&inifile, sample_ini), 0);
    
    section_keys = inifile_get_section (&inifile, "locations");
    invariant_int_cmp (1, rel_n_records (section_keys));
    invariant_str_cmp ("URL", section_keys[0][0]);
    key_values = inifile_get_key_values (&inifile, "locations", "url");
    invariant_int_cmp (2, rel_n_records (key_values));
    invariant_str_cmp ("archives/demo@example.com master", key_values[0][0]);
    invariant_str_cmp ("comment", key_values[0][1]);
    invariant_str_cmp ("http://example.org/%7ejoepublic/archives/demo@example.com", key_values[1][0]);
    /* leaks during the test, fix if needed */
    invariant_str_cmp (inifile_get_single_string (&inifile, "locations", "url", "foo"), "http://example.org/%7ejoepublic/archives/demo@example.com");
    rel_free_table (key_values);
    rel_free_table (section_keys);
    
    section_keys = inifile_get_section (&inifile, "signing");
    invariant_int_cmp (7, rel_n_records (section_keys));
    invariant_str_cmp ("", section_keys[0][0]);
    key_values = inifile_get_key_values (&inifile, "signing", "");
    invariant_int_cmp (3, rel_n_records (key_values));
    invariant_str_cmp ("#use gnome-gpg", key_values[0][1]);
    invariant_str_cmp ("# shared archive between two people", key_values[1][1]);
    invariant_str_cmp ("# allow john@example.com or key E123344 and also key with fingerprint E12...", key_values[2][1]);
    rel_free_table (key_values);
    invariant_str_cmp ("gpg_command", section_keys[1][0]);
    invariant_str_cmp ("allowed_ids", section_keys[2][0]);
    key_values = inifile_get_key_values (&inifile, "signing", "allowed_ids");
    invariant_int_cmp (1, rel_n_records (key_values));
    invariant_str_cmp ("john@example.com E123344", key_values[0][0]);
    invariant_str_cmp ("", key_values[0][1]);
    rel_free_table (key_values);
    invariant_str_cmp ("allowed_fingerprints", section_keys[3][0]);
    key_values = inifile_get_key_values (&inifile, "signing", "allowed_fingerprints");
    invariant_int_cmp (1, rel_n_records (key_values));
    invariant_str_cmp ("E12345677627865429642964236266", key_values[0][0]);
    invariant_str_cmp ("", key_values[0][1]);
    rel_free_table (key_values);
    invariant_str_cmp ("validate_creator", section_keys[4][0]);
    key_values = inifile_get_key_values (&inifile, "signing", "validate_creator");
    invariant_int_cmp (1, rel_n_records (key_values));
    invariant_str_cmp ("error", key_values[0][0]);
    invariant_str_cmp ("", key_values[0][1]);
    rel_free_table (key_values);
    invariant_str_cmp ("validate_archivename", section_keys[5][0]);
    key_values = inifile_get_key_values (&inifile, "signing", "validate_archivename");
    invariant_int_cmp (1, rel_n_records (key_values));
    invariant_str_cmp ("ignore", key_values[0][0]);
    invariant_str_cmp ("", key_values[0][1]);
    rel_free_table (key_values);
    rel_free_table (section_keys);

    /* note a URL as readonly */
    inifile_update_key (&inifile, "locations", "URL", 1, "http://example.org/%7ejoepublic/archives/demo@example.com readonly", "");
    
    /* leaks during the test. big whoop */
    invariant_str_cmp (inifile_get_text_merge (&inifile, 1), "# This file lists the locations that demo@example.com has been seen at\n"
                       "# with recorded performance and capabilities.\n"
                       "# It is a .ini format file. See the system documentation for the full format.\n"
                       "[Locations]\n"
                       "URL=archives/demo@example.com master;comment\n"
                       "URL=http://example.org/%7ejoepublic/archives/demo@example.com readonly\n"
                       "[Signing]\n"
                       "# shared archive between two people\n"
                       "# allow john@example.com or key E123344 and also key with fingerprint E12...\n"
                       "allowed_ids=john@example.com E123344\n"
                       "allowed_fingerprints=E12345677627865429642964236266\n"
                       "validate_creator=error\n"
                       "validate_archivename=ignore\n"
		       "with_brackets_in_value=f(o)o\n");

    /* nuke a URL */
    inifile_remove_key (&inifile, "locations", "URL", 1);
    /* leaks during the test. big whoop */
    invariant_str_cmp (inifile_get_text_merge (&inifile, 1), "# This file lists the locations that demo@example.com has been seen at\n"
                       "# with recorded performance and capabilities.\n"
                       "# It is a .ini format file. See the system documentation for the full format.\n"
                       "[Locations]\n"
                       "URL=archives/demo@example.com master;comment\n"
                       "[Signing]\n"
                       "# shared archive between two people\n"
                       "# allow john@example.com or key E123344 and also key with fingerprint E12...\n"
                       "allowed_ids=john@example.com E123344\n"
                       "allowed_fingerprints=E12345677627865429642964236266\n"
                       "validate_creator=error\n"
                       "validate_archivename=ignore\n"
		       "with_brackets_in_value=f(o)o\n");

    inifile_finalise (&inifile);

    /* make a new file, add a key to a missing section */
    inifile_init (&inifile);
    inifile_add_key (&inifile, "Demo", "", "", "# Comment");
    inifile_add_key (&inifile, "Demo", "sample", "value", "");
    key_values = inifile_get_key_values (&inifile, "demo", "sample");
    invariant_int_cmp (1, rel_n_records (key_values));
    invariant_str_cmp ("value", key_values[0][0]);
    invariant_str_cmp ("", key_values[0][1]);
    rel_free_table (key_values);
    /* leaks during the test, big whoop */
    invariant_str_cmp (inifile_get_text (&inifile), "[Demo]\n# Comment\nsample=value\n");
    inifile_save_merge (&inifile, 0, ",,inifile");
    inifile_finalise (&inifile);

    inifile_init (&inifile);
    invariant_int_cmp (inifile_load (&inifile, ",,inifile"), 0);
    key_values = inifile_get_key_values (&inifile, "demo", "sample");
    invariant_int_cmp (1, rel_n_records (key_values));
    invariant_str_cmp ("value", key_values[0][0]);
    invariant_str_cmp ("", key_values[0][1]);
    rel_free_table (key_values);
    /* leaks during the test, big whoop */
    invariant_str_cmp (inifile_get_text (&inifile), "[Demo]\n# Comment\nsample=value\n");
    rmrf_file(",,inifile");

    /* TODO test inifile_set_single_string */
}

int
main (int argc, char * argv[])
{
  check_line_types();
  check_section_parsing();
  check_key_parsing();
  rambling_test();
  invariant_int_cmp (0,0);
  invariant_str_cmp ("sftp", "sftp");
  return 0;
}



syntax highlighted by Code2HTML, v. 0.9.1