public static List<Vertex> sortVertices(Graph g) throws UnexpectedGraphCycleError {
        if (g.getEdges().size() == 0) return new ArrayList<>(g.getVertices());

        List<Vertex> sorted = new ArrayList<>(g.getVertices().size());

        Deque<Vertex> pending = new LinkedList<>();
        pending.addAll(g.getRoots());

        Set<Edge> traversedEdges = new HashSet<>();

        while (!pending.isEmpty()) {
            Vertex currentVertex = pending.removeFirst();
            sorted.add(currentVertex);

            currentVertex.getOutgoingEdges().forEach(edge -> {
                traversedEdges.add(edge);
                Vertex toVertex = edge.getTo();
                if (toVertex.getIncomingEdges().stream().allMatch(traversedEdges::contains)) {
                    pending.add(toVertex);
                }
            });
        }

        // Check for cycles
        if (g.edges().noneMatch(traversedEdges::contains)) {
            throw new UnexpectedGraphCycleError(g);
        }

        return sorted;
    }
@Test
    public void testSortOrder() throws InvalidIRException, TopologicalSort.UnexpectedGraphCycleError {
        Graph g = Graph.empty();
        Vertex v1 = IRHelpers.createTestVertex();
        Vertex v2 = IRHelpers.createTestVertex();
        Vertex v3 = IRHelpers.createTestVertex();
        Vertex v4 = IRHelpers.createTestVertex();
        g.chainVertices(v3, v1, v2);
        g.chainVertices(v4, v1, v2);
        assertThat(TopologicalSort.sortVertices(g),
                anyOf(
                        is(Arrays.asList(v3,v4,v1,v2)),
                        is(Arrays.asList(v4,v3,v1,v2))
                ));
    }