Add graph references

This commit is contained in:
Abdelrahman Said
2026-06-28 13:49:01 +01:00
parent 0a9807e448
commit a11edf0c53
2578 changed files with 868045 additions and 0 deletions
@@ -0,0 +1,202 @@
/*
igraph library.
Copyright (C) 2022 The igraph development team <igraph@igraph.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <igraph.h>
#include "test_utilities.h"
/* This test attempts to verify that when adding vertices or edges to a graph fails,
* the graph, as well as its attribute table, are left in a consistent state.
* This test operates with the C attribute handler. Since this attribute table is
* not directly accessible, only limited checks are done to verify its consistency.
*
* We use the printignore() error handler insted of ignore() as this eases debugging.
* Thus, this test has not corresponding expected output file. All checks are done
* directly in the code.
*/
/* Check that the graph stays in a consistent state upon failure.
* This macro does not destroy the graph. */
#define CHECK1(funcall) \
do { \
igraph_int_t vcount = igraph_vcount(&graph); \
igraph_int_t ecount = igraph_ecount(&graph); \
igraph_error_handler_t *handler; \
handler = igraph_set_error_handler(igraph_error_handler_printignore); \
IGRAPH_ASSERT(funcall != IGRAPH_SUCCESS); \
igraph_set_error_handler(handler); \
verify_graph(&graph, vcount, ecount); \
} while (0)
/* Check that there is no invalid memory access if the graph is on the finally
* stack when failure occurs. This macro unrolls the finally stack and destroys
* the graph. */
#define CHECK2(funcall) \
do { \
igraph_error_handler_t *handler; \
IGRAPH_FINALLY(igraph_destroy, &graph); \
handler = igraph_set_error_handler(igraph_error_handler_printignore); \
IGRAPH_ASSERT(funcall != IGRAPH_SUCCESS); \
igraph_set_error_handler(handler); \
} while (0)
/* Do both checks, destroying the graph and resetting the finally stack in the process. */
#define CHECK_DESTROY(funcall) \
do { CHECK1(funcall); CHECK2(funcall); } while (0)
void verify_graph(const igraph_t *graph, igraph_int_t vcount, igraph_int_t ecount) {
IGRAPH_ASSERT(igraph_vector_int_size(&graph->from) == ecount);
IGRAPH_ASSERT(igraph_vector_int_size(&graph->to) == ecount);
IGRAPH_ASSERT(igraph_vector_int_size(&graph->oi) == ecount);
IGRAPH_ASSERT(igraph_vector_int_size(&graph->ii) == ecount);
IGRAPH_ASSERT(igraph_vector_int_size(&graph->os) == vcount + 1);
IGRAPH_ASSERT(igraph_vector_int_size(&graph->is) == vcount + 1);
}
int main(void) {
igraph_t graph;
/* Enable attribute handler */
igraph_set_attribute_table(&igraph_cattribute_table);
/* Helper vectors */
igraph_vector_t nvalues;
igraph_vector_init(&nvalues, 0);
igraph_strvector_t svalues;
igraph_strvector_init(&svalues, 0);
igraph_vector_bool_t bvalues;
igraph_vector_bool_init(&bvalues, 0);
const igraph_vector_int_t edges = IGRAPH_VECTOR_NULL; /* 2 edges */
igraph_vector_int_init_int((igraph_vector_int_t *) &edges, 4, 0,1, 1,2);
/* attr1, numeric, 3 values */
igraph_attribute_record_list_t attr1;
igraph_attribute_record_list_init(&attr1, 1);
igraph_attribute_record_t* a1 = igraph_attribute_record_list_get_ptr(&attr1, 0);
igraph_attribute_record_set_name(a1, "foo");
igraph_attribute_record_set_type(a1, IGRAPH_ATTRIBUTE_NUMERIC);
igraph_vector_t vec_a1;
igraph_vector_init_int(&vec_a1, 3, 1, 2, 3);
igraph_vector_update(a1->value.as_vector, &vec_a1);
igraph_vs_t vs1;
igraph_vs_vector_small(&vs1, 0, 1, 2, -1);
/* attr2, string, 2 values */
igraph_attribute_record_list_t attr2;
igraph_attribute_record_list_init(&attr2, 1);
igraph_attribute_record_t* a2 = igraph_attribute_record_list_get_ptr(&attr2, 0);
igraph_attribute_record_set_name(a2, "bar");
igraph_attribute_record_set_type(a2, IGRAPH_ATTRIBUTE_STRING);
igraph_strvector_t vec_a2;
igraph_strvector_init(&vec_a2, 2);
igraph_strvector_set(&vec_a2, 0, "one");
igraph_strvector_set(&vec_a2, 1, "two");
igraph_strvector_update(a2->value.as_strvector, &vec_a2);
/* attr3, boolean, 2 values */
igraph_attribute_record_list_t attr3;
igraph_attribute_record_list_init(&attr3, 1);
igraph_attribute_record_t* a3 = igraph_attribute_record_list_get_ptr(&attr3, 0);
igraph_attribute_record_set_name(a3, "baz");
igraph_attribute_record_set_type(a3, IGRAPH_ATTRIBUTE_BOOLEAN);
igraph_vector_bool_t vec_a3;
igraph_vector_bool_init_int(&vec_a3, 2, 1, 0);
igraph_vector_bool_update(a3->value.as_vector_bool, &vec_a3);
igraph_vs_t vs3;
igraph_vs_vector_small(&vs3, 3, 4, -1);
/* Perform tests */
igraph_empty(&graph, 0, IGRAPH_UNDIRECTED);
CHECK_DESTROY(igraph_add_vertices(&graph, 2, &attr1)); /* wrong number of vertices */
igraph_empty(&graph, 0, IGRAPH_UNDIRECTED);
igraph_add_vertices(&graph, 3, &attr1);
CHECK_DESTROY(igraph_add_edges(&graph, &edges, &attr1)); /* wrong number of edges */
igraph_empty(&graph, 0, IGRAPH_UNDIRECTED);
igraph_add_vertices(&graph, 3, &attr1);
igraph_add_edges(&graph, &edges, &attr2);
igraph_add_vertices(&graph, 2, &attr3);
CHECK1(igraph_add_vertices(&graph, 2, &attr1)); /* wrong number of vertices */
/* Attribute handling still works and graph has correct attributes after failure to add vertices? */
IGRAPH_ASSERT(igraph_cattribute_VANV(&graph, a1->name, vs1, &nvalues) == IGRAPH_SUCCESS);
IGRAPH_ASSERT(igraph_vector_all_e(&vec_a1, &nvalues));
IGRAPH_ASSERT(igraph_cattribute_EASV(&graph, a2->name, igraph_ess_all(IGRAPH_EDGEORDER_ID), &svalues) == IGRAPH_SUCCESS);
IGRAPH_ASSERT(igraph_strvector_size(&svalues) == igraph_strvector_size(&vec_a2));
for (igraph_int_t i=0; i < igraph_strvector_size(&svalues); ++i) {
IGRAPH_ASSERT(strcmp(igraph_strvector_get(&vec_a2, i), igraph_strvector_get(&svalues, i)) == 0);
}
IGRAPH_ASSERT(igraph_cattribute_VABV(&graph, a3->name, vs3, &bvalues) == IGRAPH_SUCCESS);
IGRAPH_ASSERT(igraph_vector_bool_all_e(&vec_a3, &bvalues));
CHECK1(igraph_add_edges(&graph, &edges, &attr1)); /* wrong number of edges */
/* Attribute handling still works and graph has correct attributes after failure to add vertices? */
IGRAPH_ASSERT(igraph_cattribute_VANV(&graph, a1->name, vs1, &nvalues) == IGRAPH_SUCCESS);
IGRAPH_ASSERT(igraph_vector_all_e(&vec_a1, &nvalues));
IGRAPH_ASSERT(igraph_cattribute_EASV(&graph, a2->name, igraph_ess_all(IGRAPH_EDGEORDER_ID), &svalues) == IGRAPH_SUCCESS);
IGRAPH_ASSERT(igraph_strvector_size(&svalues) == igraph_strvector_size(&vec_a2));
for (igraph_int_t i=0; i < igraph_strvector_size(&svalues); ++i) {
IGRAPH_ASSERT(strcmp(igraph_strvector_get(&vec_a2, i), igraph_strvector_get(&svalues, i)) == 0);
}
IGRAPH_ASSERT(igraph_cattribute_VABV(&graph, a3->name, vs3, &bvalues) == IGRAPH_SUCCESS);
IGRAPH_ASSERT(igraph_vector_bool_all_e(&vec_a3, &bvalues));
igraph_destroy(&graph);
/* Release attr1 */
igraph_attribute_record_list_destroy(&attr1);
igraph_vs_destroy(&vs1);
/* Release attr2 */
igraph_attribute_record_list_destroy(&attr2);
/* Release attr3 */
igraph_attribute_record_list_destroy(&attr3);
igraph_vs_destroy(&vs3);
/* Release helpers */
igraph_vector_destroy(&vec_a1);
igraph_strvector_destroy(&vec_a2);
igraph_vector_bool_destroy(&vec_a3);
igraph_vector_int_destroy((igraph_vector_int_t *) &edges);
igraph_strvector_destroy(&svalues);
igraph_vector_destroy(&nvalues);
igraph_vector_bool_destroy(&bvalues);
VERIFY_FINALLY_STACK();
return 0;
}