OTLoadedGraph { public Set<K> getTips() { return Stream.concat(levels.keySet().stream(), child2parent.keySet().stream()) .filter(node -> !parent2child.containsKey(node)) .collect(toSet()); } OTLoadedGraph(OTSystem<D> otSystem);  OTLoadedGraph(OTSystem<D> otSystem, @Nullable Function<K, String> idToString, @Nullable Function<D, String> diffToString); void addNode(K node, long level); void addNode(K child, long level, Map<K, List<D>> parents); void addEdge(K parent, K child, List<? extends D> diff); void removeNode(K node); void removeEdge(K parent, K child); void setLevel(K node, long level); boolean hasParent(K node); boolean hasChild(K node); Map<K, List<? extends D>> getParents(K child); Map<K, List<? extends D>> getChildren(K parent); Set<K> getRoots(); Set<K> getTips(); List<D> findParent(K parent, K child); Set<K> findRoots(K node); Set<K> excludeParents(Set<K> nodes); Map<K, List<D>> merge(Set<K> nodes); String toGraphViz(); String toGraphViz(@Nullable K currentCommit); @Override String toString();  }
@Test public void testIncrementalLoading() { repository.setGraph(g -> { g.add(0, 1, add(1)); g.add(1, 2, add(2)); g.add(2, 3, add(3)); g.add(3, 4, add(4)); g.add(4, 5, add(5)); g.add(5, 6, add(6)); g.add(6, 7, add(7)); }); Set<Integer> heads = await(repository.getHeads()); OTLoadedGraph<Integer, TestOp> graph = await(loadGraph(repository, SYSTEM, heads)); assertEquals(set(7), graph.getTips()); repository.addGraph(g -> g.add(7, 8, add(8))); heads = await(repository.getHeads()); await(loadGraph(repository, SYSTEM, heads, graph)); assertEquals(set(8), graph.getTips()); }