//! Integration tests.

mod common;

use common::{
    Hyperedge,
    Vertex,
};
use hypergraph::{
    HyperedgeIndex,
    Hypergraph,
    VertexIndex,
    errors::HypergraphError,
};

#[test]
fn integration_main() {
    // Create a new hypergraph.
    let mut graph = Hypergraph::<Vertex, Hyperedge>::new();

    // Create some vertices.
    let andrea = Vertex::new("Andrea");
    let bjǫrn = Vertex::new("Bjǫrn");
    let charlie = Vertex::new("Charlie");
    let dana = Vertex::new("Dana");
    let enola = Vertex::new("Enola");

    // Add those vertices to the hypergraph.
    assert_eq!(
        graph.add_vertex(andrea),
        Ok(VertexIndex(0)),
        "should add the first vertex"
    );
    assert_eq!(
        graph.add_vertex(bjǫrn),
        Ok(VertexIndex(1)),
        "should add the second vertex"
    );
    assert_eq!(
        graph.add_vertex(charlie),
        Ok(VertexIndex(2)),
        "should add the third vertex"
    );
    assert_eq!(
        graph.add_vertex(dana),
        Ok(VertexIndex(3)),
        "should add the fourth vertex"
    );
    assert_eq!(
        graph.add_vertex(enola),
        Ok(VertexIndex(4)),
        "should add the fifth vertex"
    );
    // Count the vertices.
    assert_eq!(graph.count_vertices(), 5, "should have 5 vertices");

    // Create some hyperedges.
    let first_hyperedge = Hyperedge::new("pass the pink ball", 1);
    let second_hyperedge = Hyperedge::new("pass the yellow ball", 1);
    let third_hyperedge = Hyperedge::new(
        "share the \"The Disordered Cosmos: A Journey into Dark Matter, Spacetime, and Dreams Deferred\" book",
        2,
    );
    let fourth_hyperedge = Hyperedge::new("meditate like a Jedi", 10);
    let fifth_hyperedge = Hyperedge::new("work out", 20);
    let sixth_hyperedge = Hyperedge::new("nope", 0);

    // Add those hyperedges to the hypergraph.
    assert_eq!(
        graph.add_hyperedge(
            vec![
                VertexIndex(0),
                VertexIndex(1),
                VertexIndex(1),
                VertexIndex(3)
            ],
            first_hyperedge
        ),
        Ok(HyperedgeIndex(0)),
        "should add a first hyperedge which contains a self-loop on the VertexIndex 1"
    );
    assert_eq!(
        graph.add_hyperedge(
            vec![
                VertexIndex(0),
                VertexIndex(1),
                VertexIndex(1),
                VertexIndex(3)
            ],
            second_hyperedge,
        ),
        Ok(HyperedgeIndex(1)),
        "should add a second hyperedge which contains the same vertices as the first one"
    );
    assert_eq!(
        graph.add_hyperedge(
            vec![
                VertexIndex(4),
                VertexIndex(0),
                VertexIndex(3),
                VertexIndex(2)
            ],
            third_hyperedge,
        ),
        Ok(HyperedgeIndex(2)),
        "should add a third hyperedge which is unique"
    );
    assert_eq!(
        graph.add_hyperedge(vec![VertexIndex(3)], fourth_hyperedge,),
        Ok(HyperedgeIndex(3)),
        "should add a fourth hyperedge which contains a unary"
    );
    assert_eq!(
        graph.add_hyperedge(vec![VertexIndex(3)], fourth_hyperedge,),
        Ok(HyperedgeIndex(3)),
        "should return the existing index since the (vertices, weight) key is identical"
    );
    assert_eq!(
        graph.add_hyperedge(vec![VertexIndex(3)], fifth_hyperedge),
        Ok(HyperedgeIndex(4)),
        "should add a fifth hyperedge which contains the same unary as the fourth one but with a different weight"
    );
    assert_eq!(
        graph.add_hyperedge(vec![VertexIndex(9)], sixth_hyperedge),
        Err(HypergraphError::VertexIndexNotFound(VertexIndex(9))),
        "should be out-of-bound and return an explicit error"
    );
    assert_eq!(
        graph.add_hyperedge(vec![], sixth_hyperedge),
        Err(HypergraphError::HyperedgeCreationNoVertices(
            Hyperedge::new("nope", 0)
        )),
        "should return an explicit error since the vertices are missing"
    );

    // Count the hyperedges.
    assert_eq!(graph.count_hyperedges(), 5, "should have 5 hyperedges");

    // Get the weights of some vertices.
    assert_eq!(
        graph.get_vertex_weight(VertexIndex(0)),
        Ok(&andrea),
        "should return Andrea"
    );
    assert_eq!(
        graph.get_vertex_weight(VertexIndex(4)),
        Ok(&enola),
        "should return Enola"
    );
    assert_eq!(
        graph.get_vertex_weight(VertexIndex(5)),
        Err(HypergraphError::VertexIndexNotFound(VertexIndex(5))),
        "should be out-of-bound and return an explicit error"
    );

    // Get the weights of some hyperedges.
    assert_eq!(
        graph.get_hyperedge_weight(HyperedgeIndex(0)),
        Ok(&Hyperedge::new("pass the pink ball", 1)),
        "should get the weight of the first hyperedge"
    );
    assert_eq!(
        graph.get_hyperedge_weight(HyperedgeIndex(4)),
        Ok(&Hyperedge::new("work out", 20)),
        "should get the weight of the fifth hyperedge"
    );
    assert_eq!(
        graph.get_hyperedge_weight(HyperedgeIndex(5)),
        Err(HypergraphError::HyperedgeIndexNotFound(HyperedgeIndex(5))),
        "should be out-of-bound and return an explicit error"
    );

    // Get the vertices of some hyperedges.
    assert_eq!(
        graph.get_hyperedge_vertices(HyperedgeIndex(0)),
        Ok(vec![
            VertexIndex(0),
            VertexIndex(1),
            VertexIndex(1),
            VertexIndex(3)
        ]),
        "should get the vertices of the first hyperedge"
    );
    assert_eq!(
        graph.get_hyperedge_vertices(HyperedgeIndex(5)),
        Err(HypergraphError::HyperedgeIndexNotFound(HyperedgeIndex(5))),
        "should be out-of-bound and return an explicit error"
    );

    // Get the hyperedges of some vertices as vectors of HyperedgeIndex
    // and vectors of vectors of VertexIndex (full version).
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(0)),
        Ok(vec![
            HyperedgeIndex(0),
            HyperedgeIndex(1),
            HyperedgeIndex(2)
        ]),
        "should get the hyperedges of the first vertex"
    );
    assert_eq!(
        graph.get_full_vertex_hyperedges(VertexIndex(0)),
        Ok(vec![
            vec![
                VertexIndex(0),
                VertexIndex(1),
                VertexIndex(1),
                VertexIndex(3)
            ],
            vec![
                VertexIndex(0),
                VertexIndex(1),
                VertexIndex(1),
                VertexIndex(3)
            ],
            vec![
                VertexIndex(4),
                VertexIndex(0),
                VertexIndex(3),
                VertexIndex(2)
            ]
        ]),
        "should get the hyperedges of the first vertex - full version"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(1)),
        Ok(vec![HyperedgeIndex(0), HyperedgeIndex(1),]),
        "should get the hyperedges of the second vertex"
    );
    assert_eq!(
        graph.get_full_vertex_hyperedges(VertexIndex(1)),
        Ok(vec![
            vec![
                VertexIndex(0),
                VertexIndex(1),
                VertexIndex(1),
                VertexIndex(3)
            ],
            vec![
                VertexIndex(0),
                VertexIndex(1),
                VertexIndex(1),
                VertexIndex(3)
            ]
        ]),
        "should get the hyperedges of the second vertex - full version"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(2)),
        Ok(vec![HyperedgeIndex(2)]),
        "should get the hyperedges of the third vertex"
    );
    assert_eq!(
        graph.get_full_vertex_hyperedges(VertexIndex(2)),
        Ok(vec![vec![
            VertexIndex(4),
            VertexIndex(0),
            VertexIndex(3),
            VertexIndex(2)
        ]]),
        "should get the hyperedges of the third vertex - full version"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(3)),
        Ok(vec![
            HyperedgeIndex(0),
            HyperedgeIndex(1),
            HyperedgeIndex(2),
            HyperedgeIndex(3),
            HyperedgeIndex(4)
        ]),
        "should get the hyperedges of the fourth vertex"
    );
    assert_eq!(
        graph.get_full_vertex_hyperedges(VertexIndex(3)),
        Ok(vec![
            vec![
                VertexIndex(0),
                VertexIndex(1),
                VertexIndex(1),
                VertexIndex(3)
            ],
            vec![
                VertexIndex(0),
                VertexIndex(1),
                VertexIndex(1),
                VertexIndex(3)
            ],
            vec![
                VertexIndex(4),
                VertexIndex(0),
                VertexIndex(3),
                VertexIndex(2)
            ],
            vec![VertexIndex(3)],
            vec![VertexIndex(3)]
        ]),
        "should get the hyperedges of the fourth vertex - full version"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(4)),
        Ok(vec![HyperedgeIndex(2)]),
        "should get the hyperedges of the fifth vertex"
    );
    assert_eq!(
        graph.get_full_vertex_hyperedges(VertexIndex(4)),
        Ok(vec![vec![
            VertexIndex(4),
            VertexIndex(0),
            VertexIndex(3),
            VertexIndex(2)
        ]]),
        "should get the hyperedges of the fifth vertex - full version"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(5)),
        Err(HypergraphError::VertexIndexNotFound(VertexIndex(5))),
        "should be out-of-bound and return an explicit error"
    );
    assert_eq!(
        graph.get_full_vertex_hyperedges(VertexIndex(5)),
        Err(HypergraphError::VertexIndexNotFound(VertexIndex(5))),
        "should be out-of-bound and return an explicit error"
    );

    // Check hyperedges intersections.
    assert_eq!(
        graph.get_hyperedges_intersections(vec![HyperedgeIndex(0), HyperedgeIndex(2)]),
        Ok(vec![VertexIndex(0), VertexIndex(3)]),
        "should get two intersections"
    );
    assert_eq!(
        graph.get_hyperedges_intersections(vec![
            HyperedgeIndex(0),
            HyperedgeIndex(2),
            HyperedgeIndex(3)
        ]),
        Ok(vec![VertexIndex(3)]),
        "should get one intersection"
    );
    assert_eq!(
        graph.get_hyperedges_intersections(vec![HyperedgeIndex(0), HyperedgeIndex(0),]),
        Ok(vec![VertexIndex(0), VertexIndex(1), VertexIndex(3)]),
        "should return all the vertices of a hyperedge intersecting itself"
    );
    assert_eq!(
        graph.get_hyperedges_intersections(vec![]),
        Err(HypergraphError::HyperedgesInvalidIntersections),
        "should fail since computing the intersections of less than two hyperedges is not possible"
    );
    assert_eq!(
        graph.get_hyperedges_intersections(vec![HyperedgeIndex(0)]),
        Err(HypergraphError::HyperedgesInvalidIntersections),
        "should fail since computing the intersections of less than two hyperedges is not possible"
    );
    assert_eq!(
        graph.get_hyperedges_intersections(vec![HyperedgeIndex(5), HyperedgeIndex(6)]),
        Err(HypergraphError::HyperedgeIndexNotFound(HyperedgeIndex(5))),
        "should be out-of-bound and return an explicit error"
    );

    // Get the hyperedges directly connecting a vertex to another.
    assert_eq!(
        graph.get_hyperedges_connecting(VertexIndex(1), VertexIndex(1)),
        Ok(vec![HyperedgeIndex(0), HyperedgeIndex(1)]),
        "should get two matches"
    );
    assert_eq!(
        graph.get_hyperedges_connecting(VertexIndex(4), VertexIndex(0)),
        Ok(vec![HyperedgeIndex(2)]),
        "should get one match"
    );
    assert_eq!(
        graph.get_hyperedges_connecting(VertexIndex(3), VertexIndex(0)),
        Ok(vec![]),
        "should get no match"
    );
    assert_eq!(
        graph.get_hyperedges_connecting(VertexIndex(5), VertexIndex(0)),
        Err(HypergraphError::VertexIndexNotFound(VertexIndex(5))),
        "should be out-of-bound and return an explicit error"
    );

    // Get the adjacent vertices from a vertex.
    assert_eq!(
        graph.get_adjacent_vertices_from(VertexIndex(0)),
        Ok(vec![VertexIndex(1), VertexIndex(3)])
    );
    assert_eq!(
        graph.get_full_adjacent_vertices_from(VertexIndex(0)),
        Ok(vec![
            (VertexIndex(1), vec![HyperedgeIndex(0), HyperedgeIndex(1)]),
            (VertexIndex(3), vec![HyperedgeIndex(2)]),
        ])
    );
    assert_eq!(
        graph.get_adjacent_vertices_from(VertexIndex(1)),
        Ok(vec![VertexIndex(1), VertexIndex(3)])
    );
    assert_eq!(
        graph.get_full_adjacent_vertices_from(VertexIndex(1)),
        Ok(vec![
            (VertexIndex(1), vec![HyperedgeIndex(0), HyperedgeIndex(1)]),
            (VertexIndex(3), vec![HyperedgeIndex(0), HyperedgeIndex(1)]),
        ])
    );
    assert_eq!(graph.get_adjacent_vertices_from(VertexIndex(2)), Ok(vec![]));
    assert_eq!(
        graph.get_full_adjacent_vertices_from(VertexIndex(2)),
        Ok(vec![])
    );
    assert_eq!(
        graph.get_adjacent_vertices_from(VertexIndex(3)),
        Ok(vec![VertexIndex(2)])
    );
    assert_eq!(
        graph.get_full_adjacent_vertices_from(VertexIndex(3)),
        Ok(vec![(VertexIndex(2), vec![HyperedgeIndex(2)])])
    );
    assert_eq!(
        graph.get_adjacent_vertices_from(VertexIndex(5)),
        Err(HypergraphError::VertexIndexNotFound(VertexIndex(5))),
        "should be out-of-bound and return an explicit error"
    );
    assert_eq!(
        graph.get_full_adjacent_vertices_from(VertexIndex(5)),
        Err(HypergraphError::VertexIndexNotFound(VertexIndex(5))),
        "should be out-of-bound and return an explicit error"
    );

    // Get the adjacent vertices to a vertex.
    assert_eq!(
        graph.get_adjacent_vertices_to(VertexIndex(0)),
        Ok(vec![VertexIndex(4)])
    );
    assert_eq!(
        graph.get_full_adjacent_vertices_to(VertexIndex(3)),
        Ok(vec![
            (VertexIndex(1), vec![HyperedgeIndex(0), HyperedgeIndex(1)]),
            (VertexIndex(0), vec![HyperedgeIndex(2)]),
        ])
    );
    assert_eq!(
        graph.get_adjacent_vertices_to(VertexIndex(1)),
        Ok(vec![VertexIndex(0), VertexIndex(1)])
    );
    assert_eq!(
        graph.get_full_adjacent_vertices_to(VertexIndex(1)),
        Ok(vec![
            (VertexIndex(0), vec![HyperedgeIndex(0), HyperedgeIndex(1)]),
            (VertexIndex(1), vec![HyperedgeIndex(0), HyperedgeIndex(1)]),
        ])
    );
    assert_eq!(
        graph.get_adjacent_vertices_to(VertexIndex(2)),
        Ok(vec![VertexIndex(3)])
    );
    assert_eq!(
        graph.get_full_adjacent_vertices_to(VertexIndex(2)),
        Ok(vec![(VertexIndex(3), vec![HyperedgeIndex(2)])])
    );
    assert_eq!(
        graph.get_adjacent_vertices_to(VertexIndex(3)),
        Ok(vec![VertexIndex(0), VertexIndex(1)])
    );
    assert_eq!(
        graph.get_full_adjacent_vertices_to(VertexIndex(3)),
        Ok(vec![
            (VertexIndex(1), vec![HyperedgeIndex(0), HyperedgeIndex(1)]),
            (VertexIndex(0), vec![HyperedgeIndex(2)])
        ])
    );
    assert_eq!(
        graph.get_adjacent_vertices_to(VertexIndex(5)),
        Err(HypergraphError::VertexIndexNotFound(VertexIndex(5))),
        "should be out-of-bound and return an explicit error"
    );
    assert_eq!(
        graph.get_full_adjacent_vertices_to(VertexIndex(5)),
        Err(HypergraphError::VertexIndexNotFound(VertexIndex(5))),
        "should be out-of-bound and return an explicit error"
    );

    // Get some paths via Dijkstra.
    assert_eq!(
        graph.get_dijkstra_connections(VertexIndex(4), VertexIndex(1)),
        Ok(vec![
            (VertexIndex(4), None),
            (VertexIndex(0), Some(HyperedgeIndex(2))),
            (VertexIndex(1), Some(HyperedgeIndex(0)))
        ]),
        "should get a path of three vertices"
    );
    assert_eq!(
        graph.get_dijkstra_connections(VertexIndex(0), VertexIndex(3)),
        Ok(vec![
            (VertexIndex(0), None),
            (VertexIndex(3), Some(HyperedgeIndex(2)))
        ]),
        "should get a path of two vertices"
    );
    assert_eq!(
        graph.get_dijkstra_connections(VertexIndex(0), VertexIndex(4)),
        Ok(vec![]),
        "should get an empty path"
    );
    assert_eq!(
        graph.get_dijkstra_connections(VertexIndex(1), VertexIndex(1)),
        Ok(vec![(VertexIndex(1), None)]),
        "should get a path of one vertex"
    );
    assert_eq!(
        graph.get_dijkstra_connections(VertexIndex(3), VertexIndex(3)),
        Ok(vec![(VertexIndex(3), None)]),
        "should get a path of one vertex"
    );
    assert_eq!(
        graph.get_dijkstra_connections(VertexIndex(3), VertexIndex(5)),
        Err(HypergraphError::VertexIndexNotFound(VertexIndex(5))),
        "should be out-of-bound and return an explicit error"
    );

    // Update the weight of a vertex.
    let bjǫrg = Vertex::new("Bjǫrg");
    assert_eq!(graph.update_vertex_weight(VertexIndex(1), bjǫrg), Ok(()));
    assert_eq!(
        graph.get_vertex_weight(VertexIndex(1)),
        Ok(&bjǫrg),
        "should return Bjǫrg instead of Bjǫrn"
    );
    assert_eq!(graph.count_vertices(), 5, "should still have 5 vertices");

    // Update a hyperedge's weight.
    // First case: the index is the last one, no internal index alteration
    // occurs.
    let fifth_hyperedge = Hyperedge::new("sleep", 0);
    assert_eq!(
        graph.update_hyperedge_weight(HyperedgeIndex(4), fifth_hyperedge),
        Ok(()),
        "should update the weight of the fifth hyperedge"
    );
    assert_eq!(
        graph.get_hyperedge_weight(HyperedgeIndex(4)),
        Ok(&fifth_hyperedge),
        "should get the new weight of the fifth hyperedge"
    );
    assert_eq!(
        graph.count_hyperedges(),
        5,
        "should still have 5 hyperedges"
    );
    // Second case: the index is not the last one, an internal index alteration
    // occurs but is anyway fixed by the insertion.
    let first_hyperedge = Hyperedge::new("pass the purple ball", 3);
    assert_eq!(
        graph.update_hyperedge_weight(HyperedgeIndex(0), first_hyperedge),
        Ok(()),
        "should update the weight of the first hyperedge"
    );
    assert_eq!(
        graph.get_hyperedge_weight(HyperedgeIndex(0)),
        Ok(&first_hyperedge),
        "should get the new weight of the first hyperedge"
    );
    assert_eq!(
        graph.count_hyperedges(),
        5,
        "should still have 5 hyperedges"
    );
    // Check the eventual errors.
    assert_eq!(
        graph.update_hyperedge_weight(HyperedgeIndex(0), first_hyperedge),
        Err(HypergraphError::HyperedgeWeightUnchanged {
            index: HyperedgeIndex(0),
            weight: first_hyperedge,
        }),
        "should return an explicit error since this weight has not changed"
    );
    assert_eq!(
        graph.update_hyperedge_weight(HyperedgeIndex(0), fourth_hyperedge),
        Ok(()),
        "should update the weight to fourth_hyperedge even though another hyperedge uses it"
    );

    // Update the vertices of some hyperedges.
    assert_eq!(
        graph.update_hyperedge_vertices(HyperedgeIndex(0), vec![VertexIndex(0), VertexIndex(4)]),
        Ok(()),
        "should update the vertices of the first hyperedge from [0, 1, 1, 3] to [0, 4]"
    );
    assert_eq!(
        graph.get_hyperedge_vertices(HyperedgeIndex(0)),
        Ok(vec![VertexIndex(0), VertexIndex(4)]),
        "should get the updated vertices of the first hyperedge"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(0)),
        Ok(vec![
            HyperedgeIndex(0),
            HyperedgeIndex(1),
            HyperedgeIndex(2)
        ]),
        "should get the same hyperedges for the first vertex"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(1)),
        Ok(vec![HyperedgeIndex(1)]),
        "should get different hyperedges for the second vertex - removed"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(3)),
        Ok(vec![
            HyperedgeIndex(4),
            HyperedgeIndex(1),
            HyperedgeIndex(2),
            HyperedgeIndex(3)
        ]),
        "should get different hyperedges for the fourth vertex - removed"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(4)),
        Ok(vec![HyperedgeIndex(2), HyperedgeIndex(0),]),
        "should get different hyperedges for the fifth vertex - added"
    );
    assert_eq!(
        graph.update_hyperedge_vertices(HyperedgeIndex(5), vec![VertexIndex(0), VertexIndex(4)]),
        Err(HypergraphError::HyperedgeIndexNotFound(HyperedgeIndex(5))),
        "should be out-of-bound and return an explicit error"
    );
    assert_eq!(
        graph.update_hyperedge_vertices(HyperedgeIndex(0), vec![]),
        Err(HypergraphError::HyperedgeUpdateNoVertices(HyperedgeIndex(
            0
        ))),
        "should return an explicit error since the vertices are missing"
    );
    assert_eq!(
        graph.update_hyperedge_vertices(HyperedgeIndex(0), vec![VertexIndex(0), VertexIndex(4)]),
        Err(HypergraphError::HyperedgeVerticesUnchanged(HyperedgeIndex(
            0
        ))),
        "should return an explicit error since the vertices have not changed"
    );

    // Check the hypergraph integrity.
    assert_eq!(graph.count_vertices(), 5);
    assert_eq!(graph.count_hyperedges(), 5);

    // Remove one hyperedge.
    // Start with the last one. No remapping is occurring internally.
    assert_eq!(
        graph.remove_hyperedge(HyperedgeIndex(4)),
        Ok(()),
        "should remove the fifth hyperedge"
    );
    assert_eq!(
        graph.get_hyperedge_vertices(HyperedgeIndex(4)),
        Err(HypergraphError::HyperedgeIndexNotFound(HyperedgeIndex(4))),
        "should return an explicit error since the hyperedge has been removed"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(0)),
        Ok(vec![
            HyperedgeIndex(0),
            HyperedgeIndex(1),
            HyperedgeIndex(2)
        ]),
        "should get the same hyperedges for the first vertex"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(1)),
        Ok(vec![HyperedgeIndex(1)]),
        "should get the same hyperedges for the second vertex"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(2)),
        Ok(vec![HyperedgeIndex(2)]),
        "should get the same hyperedges for the third vertex"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(3)),
        Ok(vec![
            HyperedgeIndex(3),
            HyperedgeIndex(1),
            HyperedgeIndex(2),
        ]),
        "should get different hyperedges for the fourth vertex - removed"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(4)),
        Ok(vec![HyperedgeIndex(2), HyperedgeIndex(0),]),
        "should get the same hyperedges for the fifth vertex"
    );

    // Check the hypergraph integrity.
    assert_eq!(graph.count_vertices(), 5);
    assert_eq!(graph.count_hyperedges(), 4);

    // Remove another hyperedge.
    // Now remove the first one. A remapping is occurring internally.
    assert_eq!(
        graph.remove_hyperedge(HyperedgeIndex(0)),
        Ok(()),
        "should remove the first hyperedge"
    );
    assert_eq!(
        graph.get_hyperedge_vertices(HyperedgeIndex(0)),
        Err(HypergraphError::HyperedgeIndexNotFound(HyperedgeIndex(0))),
        "should return an explicit error since the hyperedge has been removed"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(0)),
        Ok(vec![HyperedgeIndex(2), HyperedgeIndex(1),]),
        "should get different hyperedges for the first vertex - removed"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(1)),
        Ok(vec![HyperedgeIndex(1)]),
        "should get the same hyperedges for the second vertex"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(2)),
        Ok(vec![HyperedgeIndex(2)]),
        "should get the same hyperedges for the third vertex"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(3)),
        Ok(vec![
            HyperedgeIndex(3),
            HyperedgeIndex(1),
            HyperedgeIndex(2),
        ]),
        "should get the same hyperedges for the fourth vertex"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(4)),
        Ok(vec![HyperedgeIndex(2)]),
        "should get different hyperedges for the fifth vertex"
    );
    assert_eq!(
        graph.remove_hyperedge(HyperedgeIndex(0)),
        Err(HypergraphError::HyperedgeIndexNotFound(HyperedgeIndex(0))),
        "should be out-of-bound and return an explicit error"
    );

    // Check the hypergraph integrity.
    assert_eq!(graph.count_vertices(), 5);
    assert_eq!(graph.count_hyperedges(), 3);

    // Remove a vertex.
    // Start with the last one. No remapping is occurring internally.
    assert_eq!(graph.remove_vertex(VertexIndex(4)), Ok(()));
    assert_eq!(
        graph.get_vertex_weight(VertexIndex(4)),
        Err(HypergraphError::VertexIndexNotFound(VertexIndex(4))),
        "should be out-of-bound and return an explicit error - removed"
    );
    assert_eq!(
        graph.get_hyperedge_vertices(HyperedgeIndex(1)),
        Ok(vec![
            VertexIndex(0),
            VertexIndex(1),
            VertexIndex(1),
            VertexIndex(3)
        ]),
        "should get the same vertices for the second hyperedge"
    );
    assert_eq!(
        graph.get_hyperedge_vertices(HyperedgeIndex(2)),
        Ok(vec![VertexIndex(0), VertexIndex(3), VertexIndex(2)]),
        "should get different vertices for the third hyperedge - removed"
    );
    assert_eq!(
        graph.get_hyperedge_vertices(HyperedgeIndex(3)),
        Ok(vec![VertexIndex(3)]),
        "should get the same vertices for the fourth hyperedge"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(0)),
        Ok(vec![HyperedgeIndex(2), HyperedgeIndex(1)]),
        "should get the hyperedges of the first vertex"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(1)),
        Ok(vec![HyperedgeIndex(1)]),
        "should get the hyperedges of the second vertex"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(2)),
        Ok(vec![HyperedgeIndex(2)]),
        "should get the hyperedges of the third vertex"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(3)),
        Ok(vec![
            HyperedgeIndex(3),
            HyperedgeIndex(1),
            HyperedgeIndex(2)
        ]),
        "should get the hyperedges of the fourth vertex"
    );

    // Check the hypergraph integrity.
    assert_eq!(graph.count_vertices(), 4);
    assert_eq!(graph.count_hyperedges(), 3);

    // Remove another vertex.
    // Now remove the first one. A remapping is occurring internally.
    assert_eq!(graph.remove_vertex(VertexIndex(0)), Ok(()));
    assert_eq!(
        graph.get_vertex_weight(VertexIndex(0)),
        Err(HypergraphError::VertexIndexNotFound(VertexIndex(0))),
        "should be out-of-bound and return an explicit error - removed"
    );
    assert_eq!(
        graph.get_hyperedge_vertices(HyperedgeIndex(1)),
        Ok(vec![VertexIndex(1), VertexIndex(1), VertexIndex(3)]),
        "should get the different vertices for the second hyperedge - removed"
    );
    assert_eq!(
        graph.get_hyperedge_vertices(HyperedgeIndex(2)),
        Ok(vec![VertexIndex(3), VertexIndex(2)]),
        "should get different vertices for the third hyperedge - removed"
    );
    assert_eq!(
        graph.get_hyperedge_vertices(HyperedgeIndex(3)),
        Ok(vec![VertexIndex(3)]),
        "should get the same vertices for the fourth hyperedge"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(1)),
        Ok(vec![HyperedgeIndex(1)]),
        "should get the hyperedges of the second vertex"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(2)),
        Ok(vec![HyperedgeIndex(2)]),
        "should get the hyperedges of the third vertex"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(3)),
        Ok(vec![
            HyperedgeIndex(3),
            HyperedgeIndex(1),
            HyperedgeIndex(2)
        ]),
        "should get the hyperedges of the fourth vertex"
    );

    // Check the hypergraph integrity.
    assert_eq!(graph.count_vertices(), 3);
    assert_eq!(graph.count_hyperedges(), 3);

    // Reverse a hyperedge.
    assert_eq!(
        graph.reverse_hyperedge(HyperedgeIndex(1)),
        Ok(()),
        "should reverse the vertices of the second hyperedge"
    );
    assert_eq!(
        graph.get_hyperedge_vertices(HyperedgeIndex(1)),
        Ok(vec![VertexIndex(3), VertexIndex(1), VertexIndex(1)])
    );

    // Get the in-degree and the out-degree of some vertices.
    assert_eq!(
        graph.get_vertex_degree_in(VertexIndex(2)),
        Ok(1),
        "should get the in-degree of the third vertex"
    );
    assert_eq!(
        graph.get_vertex_degree_out(VertexIndex(2)),
        Ok(0),
        "should get the out-degree of the third vertex"
    );
    assert_eq!(
        graph.get_vertex_degree_in(VertexIndex(3)),
        Ok(0),
        "should get the in-degree of the fourth vertex"
    );
    assert_eq!(
        graph.get_vertex_degree_out(VertexIndex(3)),
        Ok(2),
        "should get the out-degree of the fourth vertex"
    );

    // Clear the hyperedges.
    assert_eq!(
        graph.clear_hyperedges(),
        Ok(()),
        "should remove all the hyperedges"
    );
    assert_eq!(graph.count_hyperedges(), 0, "should have no hyperedges");
    assert_eq!(
        graph.count_vertices(),
        3,
        "should still have three vertices"
    );
    assert_eq!(graph.count_hyperedges(), 0, "should have no hyperedges");
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(1)),
        Ok(vec![]),
        "should get no hyperedges for the second vertex"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(2)),
        Ok(vec![]),
        "should get no hyperedges for the third vertex"
    );
    assert_eq!(
        graph.get_vertex_hyperedges(VertexIndex(3)),
        Ok(vec![]),
        "should get no hyperedges for the fourth vertex"
    );

    // Clear the whole hypergraph.
    graph.clear();
    assert_eq!(graph.count_vertices(), 0, "should have no vertices");
    assert_eq!(graph.count_hyperedges(), 0, "should have no hyperedges");
}
