data-structures
Version:
JavaScript data structures written in CoffeeScript.
400 lines (370 loc) • 16 kB
text/coffeescript
Graph = require('../source').Graph
# Shorthand for logging.
l = (x) -> console.log require('util').inspect x, true, 10
addNodesTo = (graph, addEdges = no) ->
initNodeSize = graph.nodeSize
graph.addNode "1"
graph.addNode "2"
graph.addNode "3"
graph.addNode "4"
graph.addNode "5"
graph.addNode "6"
expect(graph.nodeSize).toBe initNodeSize + 6
if addEdges
###
1 <- 2 <-> 3
|^ ^ ^
v \ | |
4 \5 6 <->
###
initEdgeSize = graph.edgeSize
expect(initEdgeSize).toBe 0
graph.addEdge "1", "4", 9
graph.addEdge "2", "1", 9
graph.addEdge "2", "3", 9
graph.addEdge "3", "2", 9
graph.addEdge "5", "1", 9
graph.addEdge "5", "2", 9
graph.addEdge "6", "3", 9
graph.addEdge "6", "6", 9
expect(graph.edgeSize).toBe initEdgeSize + 8
describe "Add node", ->
graph = new Graph()
it "should have 0 edge and 0 node initially", ->
expect(graph.nodeSize).toBe 0
expect(graph.edgeSize).toBe 0
it "should return the node object added, or undefined if the id exists", ->
expect((graph.addNode "item") instanceof Object).toBeTruthy()
expect((graph.addNode "1") instanceof Object).toBeTruthy()
expect((graph.addNode null) instanceof Object).toBeTruthy()
it "should return undefined if the node id already exists", ->
expect(graph.addNode "item").toBeUndefined()
expect(graph.addNode "1").toBeUndefined()
expect(graph.addNode null).toBeUndefined()
it "should have kept the node size constant with non-insertions", ->
expect(graph.nodeSize).toBe 3
describe "Get node", ->
graph = new Graph()
it "should return undefined if the node's not found", ->
expect(graph.getNode null).toBeUndefined()
expect(graph.getNode undefined).toBeUndefined()
expect(graph.getNode 2).toBeUndefined()
it "should return the added node", ->
addNodesTo graph
expect((graph.getNode "1") instanceof Object).toBeTruthy()
expect((graph.getNode "2") instanceof Object).toBeTruthy()
expect((graph.getNode "6") instanceof Object).toBeTruthy()
it "should return a defined object if null and undefined are found", ->
graph.addNode null
graph.addNode undefined
expect((graph.getNode null) instanceof Object).toBeTruthy()
expect((graph.getNode undefined) instanceof Object).toBeTruthy()
xit "should distinguish between id of '2' and 2", ->
expect(graph.getNode 2).toBeUndefined()
describe "Remove node", ->
graph = new Graph()
it "should return undefined if the node doesn't exist in the first place", ->
expect(graph.removeNode null).toBeUndefined()
expect(graph.removeNode 2).toBeUndefined()
it "should have kept the node size constant", ->
expect(graph.nodeSize).toBe 0
it "should return the value of node removed", ->
addNodesTo graph
expect((graph.removeNode "1") instanceof Object).toBeTruthy()
expect((graph.removeNode "3") instanceof Object).toBeTruthy()
expect((graph.removeNode "6") instanceof Object).toBeTruthy()
it "should have updated the node size", ->
expect(graph.nodeSize).toBe 3
it "should have removed the node", ->
expect(graph.getNode "1").toBeUndefined()
expect(graph.getNode "3").toBeUndefined()
expect(graph.getNode "6").toBeUndefined()
describe "Add edge", ->
graph = new Graph()
it "should return undefined if either/both nodes don't exist in the graph", ->
expect(graph.addEdge "7", "8").toBeUndefined()
expect(graph.addEdge "1", "8").toBeUndefined()
expect(graph.addEdge "99", "1").toBeUndefined()
addNodesTo graph
expect(graph.addEdge "7", "8").toBeUndefined()
expect(graph.addEdge "1", "8").toBeUndefined()
expect(graph.addEdge "99", "1").toBeUndefined()
it "should add the edge and return the edge object", ->
expect((graph.addEdge "1", "2") instanceof Object).toBeTruthy()
expect((graph.addEdge "2", "1") instanceof Object).toBeTruthy()
expect((graph.addEdge "3", "2") instanceof Object).toBeTruthy()
it "should have updated the edge size", ->
expect(graph.edgeSize).toBe 3
it "should have initiated the edge weight to 1", ->
expect(graph.addEdge("5", "2").weight).toBe 1
expect(graph.addEdge("5", "6").weight).toBe 1
expect(graph.addEdge("3", "6").weight).toBe 1
it "should allow the node to add an edge to itself", ->
expect((graph.addEdge "2", "2") instanceof Object).toBeTruthy()
expect((graph.addEdge "6", "6") instanceof Object).toBeTruthy()
it "should count a self-directing edge as a single one", ->
expect(graph.edgeSize).toBe 8
it "should return undefined if the edge already exists", ->
expect(graph.addEdge "1", "2").toBeUndefined()
expect(graph.addEdge "2", "2").toBeUndefined()
expect(graph.addEdge "2", "1").toBeUndefined()
describe "Get edge", ->
graph = new Graph()
it "should return undefined if the nodes aren't found", ->
expect(graph.getEdge "1", "2").toBeUndefined()
it "should return undefined if the edge isn't found", ->
addNodesTo graph, yes
expect(graph.getEdge "3", "5").toBeUndefined()
expect(graph.getEdge "1", "2").toBeUndefined()
it "should return the edge found", ->
expect((graph.getEdge "1", "4") instanceof Object).toBeTruthy()
expect((graph.getEdge "2", "1") instanceof Object).toBeTruthy()
expect((graph.getEdge "2", "3") instanceof Object).toBeTruthy()
expect((graph.getEdge "3", "2") instanceof Object).toBeTruthy()
expect((graph.getEdge "5", "1") instanceof Object).toBeTruthy()
expect((graph.getEdge "5", "2") instanceof Object).toBeTruthy()
expect((graph.getEdge "6", "3") instanceof Object).toBeTruthy()
expect((graph.getEdge "6", "6") instanceof Object).toBeTruthy()
describe "Tricky remove node and get node behavior", ->
# Internally, removing a node doesn't immediately remove all the edges
# concerned. This is to amortize the removal to O(1).
graph = undefined
beforeEach ->
graph = new Graph()
graph.addNode 1
graph.addNode 2
describe "Get edge from 1 to 2 after removal of node 2", ->
beforeEach ->
graph.addEdge 1, 2
it "should return undefined", ->
graph.removeNode 2
expect(graph.getEdge 1, 2).toBeUndefined()
expect(graph.edgeSize).toBe 0
it "should return undefined even if a new node 2 is added", ->
graph.removeNode 2
graph.addNode 2
expect(graph.getEdge 1, 2).toBeUndefined()
expect(graph.edgeSize).toBe 0
it "should add a new edge correctly if a new node 2 is added and the edge is
'reestablished'", ->
graph.removeNode 2
graph.addNode 2
graph.addEdge 1, 2, 5
expect(graph.getEdge(1, 2).weight).toBe 5
expect(graph.edgeSize).toBe 1
it "should return undefined after addition of an opposite edge", ->
graph.removeNode 2
graph.addNode 2
graph.addEdge 2, 1, 5
expect(graph.getEdge 1, 2).toBeUndefined()
expect(graph.getEdge(2, 1).weight).toBe 5
expect(graph.edgeSize).toBe 1
describe "Add edge from 2 to 1", ->
beforeEach ->
graph.addEdge 2, 1
it "should return undefined", ->
graph.removeNode 2
expect(graph.getEdge 2, 1).toBeUndefined()
expect(graph.edgeSize).toBe 0
it "should return undefined after remove of node 2", ->
graph.removeNode 2
graph.addNode 2
expect(graph.getEdge 2, 1).toBeUndefined()
expect(graph.edgeSize).toBe 0
it "should add a new edge correctly if a new node 2 is added and the edge is
'reestablished'", ->
graph.removeNode 2
graph.addNode 2
graph.addEdge 2, 1, 5
expect(graph.getEdge(2, 1).weight).toBe 5
expect(graph.edgeSize).toBe 1
it "should return undefined after addition of an opposite edge", ->
graph.removeNode 2
graph.addNode 2
graph.addEdge 1, 2, 5
expect(graph.getEdge 2, 1).toBeUndefined()
expect(graph.getEdge(1, 2).weight).toBe 5
expect(graph.edgeSize).toBe 1
graph2 = undefined
describe "Remove all edges except one, and check for its edges", ->
beforeEach ->
graph2 = new Graph()
addNodesTo graph2, yes
graph2.removeNode "2"
graph2.removeNode "3"
graph2.removeNode "4"
graph2.removeNode "5"
graph2.removeNode "6"
it "should return undefined", ->
expect(graph2.getEdge "2", "1").toBeUndefined()
expect(graph.edgeSize).toBe 0
it "should return undefined", ->
expect(graph2.getEdge "1", "4").toBeUndefined()
expect(graph.edgeSize).toBe 0
it "should return undefined", ->
expect(graph2.getEdge "5", "1").toBeUndefined()
expect(graph.edgeSize).toBe 0
describe "Remove edge", ->
graph = new Graph()
it "should return undefined if either node's not found", ->
expect(graph.removeEdge 1, 2).toBeUndefined()
expect(graph.removeEdge undefined, undefined).toBeUndefined()
it "should have kept the edge count at 0", ->
expect(graph.edgeSize).toBe 0
it "should return undefined if the edge doesn't exist", ->
addNodesTo graph, yes
###
1 <- 2 <-> 3
|^ ^ ^
v \ | |
4 \5 6 <->
###
expect(graph.removeEdge("1", "4").weight).toBe 9
expect(graph.removeEdge("2", "1").weight).toBe 9
expect(graph.removeEdge("2", "3").weight).toBe 9
expect(graph.removeEdge("3", "2").weight).toBe 9
expect(graph.removeEdge("5", "1").weight).toBe 9
expect(graph.removeEdge("5", "2").weight).toBe 9
expect(graph.removeEdge("6", "3").weight).toBe 9
it "should have kept track of the edge count", ->
expect(graph.edgeSize).toBe 1
it "should remove a self-directing correctly", ->
expect(graph.removeEdge("6", "6").weight).toBe 9
expect(graph.edgeSize).toBe 0
it "should leave an empty graph after removing all the edges", ->
expect(graph.removeEdge "1", "4").toBeUndefined()
expect(graph.removeEdge "2", "1").toBeUndefined()
expect(graph.removeEdge "2", "3").toBeUndefined()
expect(graph.removeEdge "3", "2").toBeUndefined()
expect(graph.removeEdge "5", "1").toBeUndefined()
expect(graph.removeEdge "5", "2").toBeUndefined()
expect(graph.removeEdge "6", "3").toBeUndefined()
expect(graph.removeEdge "6", "6").toBeUndefined()
describe "Get all in edges", ->
graph = new Graph()
it "should return empty array for a non-existant node", ->
expect(graph.getOutEdgesOf "6").toEqual []
expect(graph.getOutEdgesOf undefined).toEqual []
it "should return empty array for no edges", ->
addNodesTo graph
expect(graph.getInEdgesOf "1").toEqual []
expect(graph.getInEdgesOf "2").toEqual []
expect(graph.getInEdgesOf "6").toEqual []
graph2 = new Graph()
it "should return the in edges", ->
addNodesTo graph2, yes
###
1 <- 2 <-> 3
|^ ^ ^
v \ | |
4 \5 6 <->
###
expect(graph2.getInEdgesOf("1").length).toBe 2
expect(graph2.getInEdgesOf "1").toContain graph2.getEdge "2", "1"
expect(graph2.getInEdgesOf "1").toContain graph2.getEdge "5", "1"
expect(graph2.getInEdgesOf("2").length).toBe 2
expect(graph2.getInEdgesOf "2").toContain graph2.getEdge "3", "2"
expect(graph2.getInEdgesOf "2").toContain graph2.getEdge "5", "2"
expect(graph2.getInEdgesOf("3").length).toBe 2
expect(graph2.getInEdgesOf "3").toContain graph2.getEdge "2", "3"
expect(graph2.getInEdgesOf "3").toContain graph2.getEdge "6", "3"
expect(graph2.getInEdgesOf("4").length).toBe 1
expect(graph2.getInEdgesOf "4").toContain graph2.getEdge "1", "4"
expect(graph2.getInEdgesOf "5").toEqual []
expect(graph2.getInEdgesOf("6").length).toBe 1
expect(graph2.getInEdgesOf "6").toContain graph2.getEdge "6", "6"
describe "Get all out edges", ->
graph = new Graph()
it "should return empty array for a non-existant node", ->
expect(graph.getOutEdgesOf "6").toEqual []
expect(graph.getOutEdgesOf undefined).toEqual []
it "should return empty array for no edges", ->
addNodesTo graph
expect(graph.getOutEdgesOf "1").toEqual []
expect(graph.getOutEdgesOf "2").toEqual []
graph2 = new Graph()
it "should return the in edges", ->
addNodesTo graph2, yes
###
1 <- 2 <-> 3
|^ ^ ^
v \ | |
4 \5 6 <->
###
expect(graph2.getOutEdgesOf("1").length).toBe 1
expect(graph2.getOutEdgesOf "1").toContain graph2.getEdge "1", "4"
expect(graph2.getOutEdgesOf("2").length).toBe 2
expect(graph2.getOutEdgesOf "2").toContain graph2.getEdge "2", "1"
expect(graph2.getOutEdgesOf "2").toContain graph2.getEdge "2", "3"
expect(graph2.getOutEdgesOf("3").length).toBe 1
expect(graph2.getOutEdgesOf "3").toContain graph2.getEdge "3", "2"
expect(graph2.getOutEdgesOf "4").toEqual []
expect(graph2.getOutEdgesOf("5").length).toBe 2
expect(graph2.getOutEdgesOf "5").toContain graph2.getEdge "5", "1"
expect(graph2.getOutEdgesOf "5").toContain graph2.getEdge "5", "2"
expect(graph2.getOutEdgesOf("6").length).toBe 2
expect(graph2.getOutEdgesOf "6").toContain graph2.getEdge "6", "3"
expect(graph2.getOutEdgesOf "6").toContain graph2.getEdge "6", "6"
describe "Get all edges", ->
graph = new Graph()
it "should return an empty array if node doesn't exist", ->
expect(graph.getAllEdgesOf 1).toEqual []
expect(graph.getAllEdgesOf undefined).toEqual []
it "should return an empty array if the node doesn't have edges", ->
addNodesTo graph
expect(graph.getAllEdgesOf "1").toEqual []
expect(graph.getAllEdgesOf "2").toEqual []
expect(graph.getAllEdgesOf "6").toEqual []
graph2 = new Graph()
it "should return an array of edges", ->
addNodesTo graph2, yes
###
1 <- 2 <-> 3
|^ ^ ^
v \ | |
4 \5 6 <->
###
expect(graph2.getAllEdgesOf("1").length).toBe 3
expect(graph2.getAllEdgesOf "1").toContain graph2.getEdge "1", "4"
expect(graph2.getAllEdgesOf "1").toContain graph2.getEdge "2", "1"
expect(graph2.getAllEdgesOf "1").toContain graph2.getEdge "5", "1"
expect(graph2.getAllEdgesOf("2").length).toBe 4
expect(graph2.getAllEdgesOf "2").toContain graph2.getEdge "2", "1"
expect(graph2.getAllEdgesOf "2").toContain graph2.getEdge "2", "3"
expect(graph2.getAllEdgesOf "2").toContain graph2.getEdge "3", "2"
expect(graph2.getAllEdgesOf "2").toContain graph2.getEdge "5", "2"
expect(graph2.getAllEdgesOf("3").length).toBe 3
expect(graph2.getAllEdgesOf "3").toContain graph2.getEdge "3", "2"
expect(graph2.getAllEdgesOf "3").toContain graph2.getEdge "2", "3"
expect(graph2.getAllEdgesOf "3").toContain graph2.getEdge "6", "3"
expect(graph2.getAllEdgesOf("4").length).toBe 1
expect(graph2.getAllEdgesOf "4").toContain graph2.getEdge "1", "4"
expect(graph2.getAllEdgesOf("5").length).toBe 2
expect(graph2.getAllEdgesOf "5").toContain graph2.getEdge "5", "1"
expect(graph2.getAllEdgesOf "5").toContain graph2.getEdge "5", "2"
it "should not duplicate a self-pointing edge", ->
expect(graph2.getAllEdgesOf("6").length).toBe 2
expect(graph2.getAllEdgesOf "6").toContain graph2.getEdge "6", "3"
expect(graph2.getAllEdgesOf "6").toContain graph2.getEdge "6", "6"
describe "Traverse through each node", ->
graph = new Graph()
it "shouldn't call the callback for an empty graph", ->
callback = jasmine.createSpy()
graph.forEachNode callback
expect(callback).not.toHaveBeenCalled()
it "should reach each node once", ->
addNodesTo graph
callback = jasmine.createSpy()
graph.forEachNode callback
expect(callback.callCount).toBe 6
describe "Traverse through each edge", ->
graph = new Graph()
it "shouldn't call the callback for an empty graph", ->
callback = jasmine.createSpy()
graph.forEachEdge callback
expect(callback).not.toHaveBeenCalled()
it "should reach each edge once", ->
addNodesTo graph, yes
callback = jasmine.createSpy()
graph.forEachEdge callback
expect(callback.callCount).toBe 8