Files
@ ba2f00912e20
Branch filter:
Location: light9/web/graph_test.coffee
ba2f00912e20
9.0 KiB
text/coffeescript
fix white output on RGBW devices
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 | log = console.log
assert = require('chai').assert
expect = require('chai').expect
SyncedGraph = require('./graph.js').SyncedGraph
describe 'SyncedGraph', ->
describe 'constructor', ->
it 'should successfully make an empty graph without connecting to rdfdb', ->
g = new SyncedGraph()
g.quads()
assert.equal(g.quads().length, 0)
describe 'auto dependencies', ->
graph = new SyncedGraph()
RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
U = (tail) -> graph.Uri('http://example.com/' + tail)
A1 = U('a1')
A2 = U('a2')
A3 = U('a3')
A4 = U('a4')
ctx = U('ctx')
quad = (s, p, o) -> graph.Quad(s, p, o, ctx)
beforeEach (done) ->
graph = new SyncedGraph()
graph.loadTrig("
@prefix : <http://example.com/> .
:ctx {
:a1 :a2 :a3 .
:a1 :someFloat 1.5 .
:a1 :someString \"hello\" .
:a1 :multipleObjects :a4, :a5 .
:a2 a :Type1 .
:a3 a :Type1 .
}
", done)
it 'calls a handler right away', ->
called = 0
hand = ->
called++
graph.runHandler(hand, 'run')
assert.equal(1, called)
it 'calls a handler a 2nd time if the graph is patched with relevant data', ->
called = 0
hand = ->
called++
graph.uriValue(A1, A2)
graph.runHandler(hand, 'run')
graph.applyAndSendPatch({
delQuads: [quad(A1, A2, A3)], addQuads: [quad(A1, A2, A4)]})
assert.equal(2, called)
it 'notices new queries a handler makes upon rerun', ->
called = 0
objsFound = []
hand = ->
called++
graph.uriValue(A1, A2)
if called > 1
objsFound.push(graph.objects(A1, A3))
graph.runHandler(hand, 'run')
# first run looked up A1,A2,*
graph.applyAndSendPatch({
delQuads: [quad(A1, A2, A3)], addQuads: [quad(A1, A2, A4)]})
# second run also looked up A1,A3,* (which matched none)
graph.applyAndSendPatch({
delQuads: [], addQuads: [quad(A1, A3, A4)]})
# third run should happen here, noticing the new A1,A3,* match
assert.equal(3, called)
assert.deepEqual([[], [A4]], objsFound)
it 'calls a handler again even if the handler throws an error', ->
called = 0
hand = ->
called++
graph.uriValue(A1, A2)
throw new Error('this test handler throws an error')
graph.runHandler(hand, 'run')
graph.applyAndSendPatch({
delQuads: [quad(A1, A2, A3)], addQuads: [quad(A1, A2, A4)]})
assert.equal(2, called)
describe 'works with nested handlers', ->
innerResults = []
inner = ->
console.log('\nninnerfetch')
innerResults.push(graph.uriValue(A1, A2))
console.log("innerResults #{JSON.stringify(innerResults)}\n")
outerResults = []
doRunInner = true
outer = ->
if doRunInner
graph.runHandler(inner, 'runinner')
console.log('push outer')
outerResults.push(graph.floatValue(A1, U('someFloat')))
beforeEach ->
innerResults = []
outerResults = []
doRunInner = true
affectInner = {
delQuads: [quad(A1, A2, A3)], addQuads: [quad(A1, A2, A4)]
}
affectOuter = {
delQuads: [
quad(A1, U('someFloat'), graph.Literal(1.5))
], addQuads: [
quad(A1, U('someFloat'), graph.LiteralRoundedFloat(2))
]}
affectBoth = {
delQuads: affectInner.delQuads.concat(affectOuter.delQuads),
addQuads: affectInner.addQuads.concat(affectOuter.addQuads)
}
it 'calls everything normally once', ->
graph.runHandler(outer, 'run')
assert.deepEqual([A3], innerResults)
assert.deepEqual([1.5], outerResults)
it.skip '[performance] reruns just the inner if its dependencies change', ->
console.log(graph.quads())
graph.runHandler(outer, 'run')
graph.applyAndSendPatch(affectInner)
assert.deepEqual([A3, A4], innerResults)
assert.deepEqual([1.5], outerResults)
it.skip '[performance] reruns the outer (and therefore inner) if its dependencies change', ->
graph.runHandler(outer, 'run')
graph.applyAndSendPatch(affectOuter)
assert.deepEqual([A3, A3], innerResults)
assert.deepEqual([1.5, 2], outerResults)
it.skip '[performance] does not send a redundant inner run if it is already rerunning outer', ->
# Note that outer may or may not call inner each time, and we
# don't want to redundantly call inner. We need to:
# 1. build the set of handlers to rerun,
# 2. call them from outside-in, and
# 3. any runHandler calls that happen, they need to count as reruns.
graph.runHandler(outer, 'run')
graph.applyAndSendPatch(affectBoth)
assert.deepEqual([A3, A4], innerResults)
assert.deepEqual([1.5, 2], outerResults)
it 'reruns the outer and the inner if all dependencies change, but outer omits calling inner this time', ->
graph.runHandler(outer, 'run')
doRunInner = false
graph.applyAndSendPatch(affectBoth)
assert.deepEqual([A3, A4], innerResults)
assert.deepEqual([1.5, 2], outerResults)
describe 'watches calls to:', ->
it 'floatValue', ->
values = []
hand = -> values.push(graph.floatValue(A1, U('someFloat')))
graph.runHandler(hand, 'run')
graph.patchObject(A1, U('someFloat'), graph.LiteralRoundedFloat(2), ctx)
assert.deepEqual([1.5, 2.0], values)
it 'stringValue', ->
values = []
hand = -> values.push(graph.stringValue(A1, U('someString')))
graph.runHandler(hand, 'run')
graph.patchObject(A1, U('someString'), graph.Literal('world'), ctx)
assert.deepEqual(['hello', 'world'], values)
it 'uriValue', ->
# covered above, but this one tests patchObject on a uri, too
values = []
hand = -> values.push(graph.uriValue(A1, A2))
graph.runHandler(hand, 'run')
graph.patchObject(A1, A2, A4, ctx)
assert.deepEqual([A3, A4], values)
it 'objects', ->
values = []
hand = -> values.push(graph.objects(A1, U('multipleObjects')))
graph.runHandler(hand, 'run')
graph.patchObject(A1, U('multipleObjects'), U('newOne'), ctx)
expect(values[0]).to.deep.have.members([U('a4'), U('a5')])
expect(values[1]).to.deep.have.members([U('newOne')])
it 'subjects', ->
values = []
rdfType = graph.Uri(RDF + 'type')
hand = -> values.push(graph.subjects(rdfType, U('Type1')))
graph.runHandler(hand, 'run')
graph.applyAndSendPatch(
{delQuads: [], addQuads: [quad(A4, rdfType, U('Type1'))]})
expect(values[0]).to.deep.have.members([A2, A3])
expect(values[1]).to.deep.have.members([A2, A3, A4])
describe 'items', ->
it 'when the list order changes', (done) ->
values = []
successes = 0
hand = ->
try
head = graph.uriValue(U('x'), U('y'))
catch
# graph goes empty between clearGraph and loadTrig
return
values.push(graph.items(head))
successes++
graph.clearGraph()
graph.loadTrig "
@prefix : <http://example.com/> .
:ctx { :x :y (:a1 :a2 :a3) } .
", () ->
graph.runHandler(hand, 'run')
graph.clearGraph()
graph.loadTrig "
@prefix : <http://example.com/> .
:ctx { :x :y (:a1 :a3 :a2) } .
", () ->
assert.deepEqual([[A1, A2, A3], [A1, A3, A2]], values)
assert.equal(2, successes)
done()
describe 'contains', ->
it 'when a new triple is added', ->
values = []
hand = -> values.push(graph.contains(A1, A1, A1))
graph.runHandler(hand, 'run')
graph.applyAndSendPatch(
{delQuads: [], addQuads: [quad(A1, A1, A1)]})
assert.deepEqual([false, true], values)
it 'when a relevant triple is removed', ->
values = []
hand = -> values.push(graph.contains(A1, A2, A3))
graph.runHandler(hand, 'run')
graph.applyAndSendPatch(
{delQuads: [quad(A1, A2, A3)], addQuads: []})
assert.deepEqual([true, false], values)
describe 'performs well', ->
it "[performance] doesn't call handler a 2nd time if the graph gets an unrelated patch", ->
called = 0
hand = ->
called++
graph.uriValue(A1, A2)
graph.runHandler(hand, 'run')
graph.applyAndSendPatch({
delQuads: [], addQuads: [quad(A2, A3, A4)]})
assert.equal(1, called)
it.skip '[performance] calls a handler 2x but then not again if the handler stopped caring about the data', ->
assert.fail()
it.skip "[performance] doesn't get slow if the handler makes tons of repetitive lookups", ->
assert.fail()
|