169 lines
5.2 KiB
C
169 lines
5.2 KiB
C
/*
|
|
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 tries to ensure that property caching works correctly in the most
|
|
* "dangerous" scenarios (going from disconnected to connected graphs and
|
|
* back). Feel free to extend the file later on with regression tests for any
|
|
* issues that we might find related to caching.
|
|
*
|
|
* There are no direct APIs to reach into the cache internals (because the
|
|
* presence of the cache is an implementation detail). Therefore, we simply do
|
|
* the following:
|
|
*
|
|
* - perform some operation
|
|
* - query the value of certain properties that we know that are typically
|
|
* cached (e.g., connectedness, presence of multi- and loop edges) etc
|
|
* - invalidate the cache
|
|
* - perform the query again, check whether the results match
|
|
*
|
|
* The assumption is that functions like igraph_is_simple(), igraph_has_loops()
|
|
* etc work correctly if the cache is empty; correctness of these functions
|
|
* without a cache should be tested in other unit tests, not here.
|
|
*/
|
|
|
|
igraph_error_t has_mutual_nonloop_edge(const igraph_t* graph, igraph_bool_t* result) {
|
|
return igraph_has_mutual(graph, result, /* loops = */ false);
|
|
}
|
|
|
|
igraph_error_t has_mutual_edge(const igraph_t* graph, igraph_bool_t* result) {
|
|
return igraph_has_mutual(graph, result, /* loops = */ true);
|
|
}
|
|
|
|
igraph_error_t is_weakly_connected(const igraph_t* graph, igraph_bool_t* result) {
|
|
return igraph_is_connected(graph, result, IGRAPH_WEAK);
|
|
}
|
|
|
|
igraph_error_t is_strongly_connected(const igraph_t* graph, igraph_bool_t* result) {
|
|
return igraph_is_connected(graph, result, IGRAPH_STRONG);
|
|
}
|
|
|
|
igraph_error_t is_forest(const igraph_t* graph, igraph_bool_t* result) {
|
|
return igraph_is_forest(graph, result, /* roots = */ NULL, IGRAPH_ALL);
|
|
}
|
|
|
|
igraph_error_t is_simple(const igraph_t* graph, igraph_bool_t* result) {
|
|
return igraph_is_simple(graph, result, IGRAPH_DIRECTED);
|
|
}
|
|
|
|
igraph_error_t is_simple_ignoring_directions(const igraph_t* graph, igraph_bool_t* result) {
|
|
return igraph_is_simple(graph, result, IGRAPH_UNDIRECTED);
|
|
}
|
|
|
|
void validate_properties(const igraph_t* graph) {
|
|
igraph_bool_t result, cached_result, recalculated_result;
|
|
|
|
#define CHECK(func) { \
|
|
igraph_invalidate_cache(graph); \
|
|
func(graph, &result); \
|
|
func(graph, &cached_result); \
|
|
igraph_invalidate_cache(graph); \
|
|
func(graph, &recalculated_result); \
|
|
IGRAPH_ASSERT(result == cached_result); \
|
|
IGRAPH_ASSERT(recalculated_result == cached_result); \
|
|
}
|
|
|
|
CHECK(igraph_has_loop);
|
|
CHECK(igraph_has_multiple);
|
|
CHECK(igraph_is_dag);
|
|
CHECK(is_forest);
|
|
CHECK(is_simple);
|
|
CHECK(is_simple_ignoring_directions);
|
|
CHECK(is_weakly_connected);
|
|
CHECK(is_strongly_connected);
|
|
CHECK(has_mutual_edge);
|
|
CHECK(has_mutual_nonloop_edge);
|
|
}
|
|
|
|
void test_basic_operations(igraph_t* graph) {
|
|
validate_properties(graph);
|
|
igraph_add_vertices(graph, 1, /* attr = */ NULL);
|
|
validate_properties(graph);
|
|
igraph_add_vertices(graph, 2, /* attr = */ NULL);
|
|
validate_properties(graph);
|
|
igraph_add_edge(graph, 0, 1);
|
|
validate_properties(graph);
|
|
igraph_add_edge(graph, 0, 2);
|
|
validate_properties(graph);
|
|
igraph_add_edge(graph, 1, 2);
|
|
validate_properties(graph);
|
|
igraph_add_edge(graph, 2, 0);
|
|
validate_properties(graph);
|
|
igraph_delete_edges(graph, igraph_ess_all(IGRAPH_EDGEORDER_ID));
|
|
validate_properties(graph);
|
|
igraph_add_edge(graph, 0, 2);
|
|
validate_properties(graph);
|
|
igraph_delete_vertices(graph, igraph_vss_1(1));
|
|
validate_properties(graph);
|
|
igraph_delete_vertices(graph, igraph_vss_all());
|
|
validate_properties(graph);
|
|
}
|
|
|
|
int test_basic_operations_directed(void) {
|
|
igraph_t g;
|
|
|
|
igraph_empty(&g, 0, IGRAPH_DIRECTED);
|
|
test_basic_operations(&g);
|
|
igraph_destroy(&g);
|
|
|
|
VERIFY_FINALLY_STACK();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int test_basic_operations_undirected(void) {
|
|
igraph_t g;
|
|
|
|
igraph_empty(&g, 0, IGRAPH_UNDIRECTED);
|
|
test_basic_operations(&g);
|
|
igraph_destroy(&g);
|
|
|
|
VERIFY_FINALLY_STACK();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int test_multi_loops_adjlist_init(void) {
|
|
igraph_t g;
|
|
igraph_adjlist_t al;
|
|
igraph_bool_t multi;
|
|
|
|
igraph_small(&g, 1, IGRAPH_UNDIRECTED,
|
|
0,0, 0,0, -1);
|
|
igraph_adjlist_init(&g, &al, IGRAPH_ALL, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE);
|
|
igraph_has_multiple(&g, &multi);
|
|
IGRAPH_ASSERT(multi);
|
|
igraph_adjlist_destroy(&al);
|
|
igraph_destroy(&g);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main(void) {
|
|
|
|
RUN_TEST(test_basic_operations_directed);
|
|
RUN_TEST(test_basic_operations_undirected);
|
|
RUN_TEST(test_multi_loops_adjlist_init);
|
|
|
|
return 0;
|
|
}
|