Преглед изворни кода

Move 'assert' function to 'util/assert'. Added test for util/dfs. Fixed 'bug' in DFS implementation.

Joeri Exelmans пре 2 година
родитељ
комит
14e30ca091

+ 3 - 1
src/onion/composite_delta.test.ts

@@ -11,9 +11,11 @@ import {
 
 import {
   mockUuid,
-  assert,
 } from "./test_helpers";
 
+import {
+  assert,
+} from "../util/assert";
 
 describe("Composite delta", () => {
 

+ 2 - 1
src/onion/legacy/graph_state.test.ts

@@ -1,6 +1,7 @@
 import {GraphState} from "./graph_state"
 import {NodeId, PrimitiveValue, UUID, nodeIdsEqual} from "../types";
-import {mockUuid, assert} from "../test_helpers";
+import {mockUuid} from "../test_helpers";
+import {assert} from "../../util/assert";
 
 
 describe("CRUD operations", () => {

+ 4 - 1
src/onion/primitive_delta.test.ts

@@ -11,9 +11,12 @@ import {
 
 import {
   mockUuid,
-  assert,
 } from "./test_helpers";
 
+import {
+  assert,
+} from "../util/assert";
+
 
 describe("Delta", () => {
 

+ 0 - 6
src/onion/test_helpers.ts

@@ -7,9 +7,3 @@ export function mockUuid() {
     return new UUID(nextId++);
   }
 }
-
-export function assert(expression: boolean, msg: string) {
-  if (!expression) {
-    throw new Error(msg);
-  }
-}

+ 4 - 1
src/onion/version.test.ts

@@ -19,9 +19,12 @@ import {
 
 import {
   mockUuid,
-  assert,
 } from "./test_helpers";
 
+import {
+  assert,
+} from "../util/assert";
+
 describe("Version", () => {
 
   it("Get deltas", () => {

+ 7 - 0
src/util/assert.ts

@@ -2,3 +2,10 @@
 export function assertNever(x: never): never {
     throw new Error(`Unexpected object: ${x}`);
 }
+
+
+export function assert(expression: boolean, msg: string) {
+  if (!expression) {
+    throw new Error(msg);
+  }
+}

+ 39 - 0
src/util/dfs.test.ts

@@ -0,0 +1,39 @@
+import {
+  findDFS,
+} from "./dfs";
+
+import {
+  assert,
+} from "./assert";
+
+import * as _ from "lodash";
+
+const graph = new Map([
+  [0, new Map([['a', 1], ['b', 2]])], // meaning: node 0 has two outgoing links: --'a'--> node 1 and --'b'--> node 2
+  [1, new Map([['c', 0]])],
+  [2, new Map([['d', 3]])],
+]);
+
+function getNeighbors(node) {
+  const outgoing = graph.get(node);
+  if (outgoing === undefined) {
+    return [];
+  }
+  return [...outgoing.entries()]
+}
+
+describe("DFS", () => {
+
+  it("Find node", () => {
+    const path = findDFS(0, 3, getNeighbors);
+    
+    // There is more than one path from 0 to 3 (in fact, there are infinitely many, if we allow loops),
+    // but we don't allow visiting the same element more than once, so only one path is possible:
+    assert(_.isEqual(path, ['b', 'd']), "Expected node to be found.");
+  });
+
+  it("Find unreachable node", () => {
+    const path = findDFS(3, 0, getNeighbors);
+    assert(path === undefined, "Expected node to be unreachable.");
+  });
+});

+ 6 - 2
src/util/dfs.ts

@@ -1,7 +1,11 @@
 
-// Generic depth-first search
+// Generic depth-first search.
+// getNeighbors should return an array of 'outgoing links', where each link is a pair [label, neighboring_element]
+// neighbors are visited in the order that getNeighbors returns them, so getNeighbors can be optimized (e.g., via some heuristic) to find a short path.
+// If the element 'searchFor' was reachable from the 'start', returns a PATH, i.e., an array of link-labels to get from start to 'searchFor'.
+// If not reachable, returns undefined.
 export function findDFS<T,L>(start: T, searchFor: T, getNeighbors: (T)=>Array<[L,T]>): L[] | undefined {
-  const alreadyVisited = new Set<T>(); // only visit every 'thing' once
+  const alreadyVisited = new Set<T>([start]); // only visit every 'thing' once
 
   function findDFSRecursive(current: T, currentPath: L[]): L[] | undefined {
     const neighbors = getNeighbors(current);