int test_create_label2node_map()
{
    const char *test_name = "test_create_label2node_map";

    struct rnode *n1, *n2, *n3;
    struct llist *node_list;
    struct hash *map;

    n1 = create_rnode("n1", "");
    n2 = create_rnode("n2", "");
    n3 = create_rnode("n3", "");
    node_list = create_llist();
    append_element(node_list, n1);
    append_element(node_list, n2);
    append_element(node_list, n3);
    map = create_label2node_map(node_list);

    if (NULL == map) {
        printf ("%s: map must not be NULL.\n", test_name);
        return 1;
    }
    if (NULL != hash_get(map, "not there")) {
        printf ("%s: inexistent label should return NULL.\n",
                test_name);
        return 1;
    }
    if (n1 != hash_get(map, "n1")) {
        printf ("%s: node with label 'n1' should be %p, not %p.\n",
                test_name, n1, hash_get(map, "n1"));
        return 1;
    }
    if (n2 != hash_get(map, "n2")) {
        printf ("%s: node with label 'n2' should be %p, not %p.\n",
                test_name, n2, hash_get(map, "n2"));
        return 1;
    }
    if (n3 != hash_get(map, "n3")) {
        printf ("%s: node with label 'n3' should be %p, not %p.\n",
                test_name, n3, hash_get(map, "n3"));
        return 1;
    }


    printf("%s ok.\n", test_name);
    return 0;
}
int test_tlt_grow_node()
{
	const char *test_name = "test_tlt_grow_node";
	double prior_remaining_time = 12.3; 	/* arbitrary units */
	struct rnode *parent = create_rnode("parent", "");
	struct rnode *kid = create_rnode("kid", "");
	kid->data = &prior_remaining_time;
	add_child(parent, kid);

	double posterior_remaining_time = tlt_grow_node(kid, 1.0, 0.5);
	double grown_length = strtod(kid->edge_length_as_string, NULL);

	double exp = prior_remaining_time - posterior_remaining_time;
	if (fabs(grown_length - exp) > TOLERANCE) {
		printf ("%s: expected %g, got %g\n", test_name, exp,
				grown_length);
		return 1;
	}

	printf("%s ok.\n", test_name);
	return 0;
}
int test_create_label2node_list_map()
{
    const char *test_name = "test_create_label2node_list_map";

    struct rnode *a1, *a2, *a3, *b1, *b2, *c1, *d1, *d2;
    struct llist *node_list;
    struct hash *map;
    struct llist *nodes_of_label;
    struct list_elem *el;

    a1 = create_rnode("a", "");
    a2 = create_rnode("a", "");
    a3 = create_rnode("a", "");
    b1 = create_rnode("b", "");
    b2 = create_rnode("b", "");
    c1 = create_rnode("c", "");
    d1 = create_rnode("d", "");
    d2 = create_rnode("d", "");

    node_list = create_llist();
    /* The order in which the nodes appear is unimportant, but it should be
     * preserved among nodes of the same label - which is why we test them
     * below in the same order (in a given label) */
    append_element(node_list, d2);
    append_element(node_list, b2);
    append_element(node_list, a2);
    append_element(node_list, a3);
    append_element(node_list, c1);
    append_element(node_list, d1);
    append_element(node_list, b1);
    append_element(node_list, a1);

    map = create_label2node_list_map(node_list);

    if (NULL == map) {
        printf ("%s: map must not be NULL.\n", test_name);
        return 1;
    }
    if (NULL != hash_get(map, "not there")) {
        printf ("%s: inexistent label should return NULL.\n",
                test_name);
        return 1;
    }

    nodes_of_label = hash_get(map, "a");
    if (NULL == nodes_of_label) {
        printf ("%s: there should be a list of nodes with label 'a'.\n",
                test_name);
        return 1;
    }
    if (nodes_of_label->count != 3) {
        printf ("%s: list of nodes with label 'a' should"
                " have length 3\n", test_name);
        return 1;
    }
    el = nodes_of_label->head;
    if (el->data != a2) {
        printf ("%s: expected node a2\n", test_name);
        return 1;
    }
    el = el->next;
    if (el->data != a3) {
        printf ("%s: expected node a3\n", test_name);
        return 1;
    }
    el = el->next;
    if (el->data != a1) {
        printf ("%s: expected node a1\n", test_name);
        return 1;
    }
    el = el->next;
    if (NULL != el) {
        printf ("%s: list of nodes with label 'a' is not terminated.\n",test_name);
        return 1;
    }


    nodes_of_label = hash_get(map, "b");
    if (NULL == nodes_of_label) {
        printf ("%s: there should be a list of nodes with label 'b'.\n",
                test_name);
        return 1;
    }
    if (nodes_of_label->count != 2) {
        printf ("%s: list of nodes with label 'b' should"
                " have length 2\n", test_name);
        return 1;
    }
    el = nodes_of_label->head;
    if (el->data != b2) {
        printf ("%s: expected node b2\n", test_name);
        return 1;
    }
    el = el->next;
    if (el->data != b1) {
        printf ("%s: expected node b1\n", test_name);
        return 1;
    }
    el = el->next;
    if (NULL != el) {
        printf ("%s: list of nodes with label 'b' is not terminated.\n",test_name);
        return 1;
    }

    nodes_of_label = hash_get(map, "c");
    if (NULL == nodes_of_label) {
        printf ("%s: there should be a list of nodes with label 'c'.\n",
                test_name);
        return 1;
    }
    if (nodes_of_label->count != 1) {
        printf ("%s: list of nodes with label 'c' should"
                " have length 1\n", test_name);
        return 1;
    }
    el = nodes_of_label->head;
    if (el->data != c1) {
        printf ("%s: expected node c1\n", test_name);
        return 1;
    }
    el = el->next;
    if (NULL != el) {
        printf ("%s: list of nodes with label 'b' is not terminated.\n",test_name);
        return 1;
    }

    nodes_of_label = hash_get(map, "d");
    if (NULL == nodes_of_label) {
        printf ("%s: there should be a list of nodes with label 'd'.\n",
                test_name);
        return 1;
    }
    if (nodes_of_label->count != 2) {
        printf ("%s: list of nodes with label 'd' should"
                " have length 2\n", test_name);
        return 1;
    }
    el = nodes_of_label->head;
    if (el->data != d2) {
        printf ("%s: expected node d2\n", test_name);
        return 1;
    }
    el = el->next;
    if (el->data != d1) {
        printf ("%s: expected node d1\n", test_name);
        return 1;
    }
    el = el->next;
    if (NULL != el) {
        printf ("%s: list of nodes with label 'b' is not terminated.\n",test_name);
        return 1;
    }

    printf("%s ok.\n", test_name);
    return 0;
}
int test_is_monophyletic()
{
	const char *test_name = __func__;

	struct rnode *node_a = create_rnode("a", NULL);
	struct rnode *node_b = create_rnode("b", NULL);
	struct rnode *node_c = create_rnode("c", NULL);
	struct rnode *node_d = create_rnode("", NULL);
	struct rnode *node_e = create_rnode("", NULL);
	struct rnode *node_f = create_rnode("", NULL);
	struct llist *descendants = create_llist();
	enum monophyly result;

	/* (a,(b,c)); */
	add_child(node_d, node_b);
	add_child(node_d, node_c);
	add_child(node_e, node_a);
	add_child(node_e, node_d);

	append_element(descendants, node_c);

	// TODO: test w/ empty list

	result = is_monophyletic(descendants, node_c);
	if (MONOPH_TRUE != result) {
		printf ("%s: c should be monophyletic in (c)\n", test_name);
		return 1;
	}

	result = is_monophyletic(descendants, node_d);
	if (MONOPH_FALSE != result) {
		printf ("%s: c should NOT be monophyletic in (c,b)\n",
				test_name);
		return 1;
	}

	append_element(descendants, node_b);
	result = is_monophyletic(descendants, node_d);
	if (MONOPH_TRUE != result) {
		printf ("%s: c,b should be monophyletic in (c,b)\n",
				test_name);
		return 1;
	}

	append_element(descendants, node_a);
	result = is_monophyletic(descendants, node_d);
	if (MONOPH_FALSE != result) {
		printf ("%s: a,c,b should NOT be monophyletic in (c,b)\n",
				test_name);
		return 1;
	}

	result = is_monophyletic(descendants, node_e);
	if (MONOPH_TRUE != result) {
		printf ("%s: a,c,b should be monophyletic in (a,(c,b))\n",
				test_name);
		return 1;
	}

	append_element(descendants, node_f);
	result = is_monophyletic(descendants, node_e);
	if (MONOPH_FALSE != result) {
		printf ("%s: a,c,b,f should NOT be monophyletic in (c,b)\n",
				test_name);
		return 1;
	}
	
	printf("%s ok.\n", test_name);
	return 0;
}