unify
Version:
An Efficient Javascript Unification Library
264 lines (256 loc) • 10.1 kB
text/coffeescript
#General Util Functions
str=(obj)->
if obj == null then "null"
else if typeof obj == "undefined" then "undefined"
else obj.toString()
#General Testing Code
class Test
constructor:(, )->
= 0
expect:(num)->
= num
equal:(arg1, arg2, message="''")->
--
if arg1 != arg2 then throw "NotEqual: '#{str(arg1)}' does not equal '#{str(arg2)}'\n #{message}"
deepEqual:(arg1, arg2, message="")->
--
if not require('deep-equal')(arg1, arg2) then throw "NotEqual: '#{str(arg1)}' does not equal '#{str(arg2)}'\n #{message}"
ok:(bool,message="")->
--
if not bool then throw "NotOk: false was passed to ok\n #{message}"
done:(message="")->
if != 0 then throw "NotDone: #{str(@num)} more checks were expected before done was called\n #{message}"
run:()->
.call(this)
test=(name, func)->
t = new Test(name, func)
exports[name]=()->t.run()
exports.RunAll = (throwException)->
for name of exports
if name != "RunAll"
if throwException then exports[name]()
else
try
exports[name]()
catch ex
console.log "Error in Test '#{name}'"
console.log "Message: #{ex}"
console.log "Stack:\n#{ex.stack}"
console.log ''
return
#File specific test functions
unifylib=require("../lib/unify")
for prop of unifylib
global[prop] = unifylib[prop]
class UnifyTest extends Test
boxtest:(obj) ->
++
unifytest:(obj1, obj2) ->
++
obj1 = box(obj1)
obj2 = box(obj2)
ret = obj1.unify(obj2)
#console.dir(obj1.getAll())
unifyfailtest:(obj1, obj2) ->
++
obj1 = box(obj1)
obj2 = box(obj2)
gettest:(tin, varValueDict) ->
for v of varValueDict
++
if varValueDict[v] instanceof variable
else
fulltest:(obj1, obj2, varValueDict1, varValueDict2) ->
obj1 = box(obj1)
obj2 = box(obj2)
test=(name, func)->
t = new UnifyTest(name, func)
exports[name]=()->t.run()
#######################
#full tests
#######################
test "empty obj {} -> {}", ()->
test "empty obj {test:'test', cool:1},{test:'test', cool:1}", ()->
test "null test [null] -> [null]", ()->
test "variable equal [X] -> [1]", ()->
test "variable equal [X,X] -> [1,1]", ()->
test "variable equal [[1,2,3]] -> [y]", ()->
test "variable equal [[1,2,x],x] -> [y,3]", ()->
test "unbound variable [y]->[x]", ()->
test "variable equal [1,X,X] -> [Z,Z,1]", () ->
#######################
# type checking tests
#######################
test "type test [X:isNum,X] -> [1,1]", ()->
test "type test [X:isNum,X] -> ['str','str']", ()->
test "type test [X:isNum,Y:isNum] -> [1,[[1]]]", ()->
test "variable equal [X:isNum,X:isStr] -> ['str','str']", ()->
threw = false
try
catch ex # a var defined with two diffrent types should blow up
threw = true
#######################
# unify fail tests
#######################
test "variable equal [X,X] -> [1,2]", ()->
test "variable unequal [1,3,2] -> [Y,Y,2]", () ->
test "variable unequal [1,X,X] -> [Z,Z,3]", () ->
test "unify fail no state change", ()->
i1 = box([1,2,3])
i2a = [1,variable("a"),4]
i2b = box(i2a)
#######################
#misc tests
#######################
test "simple black box unify test", () ->
test "unbox bound variable", () ->
i1 = box([1,variable("a")])
i2 = box([1,1])
test "unbox with maxDepth", () ->
i1 = box([1,1])
test "seperate trees diff vars", ()->
i1 = box([1,variable("a")])
i2 = box([variable("a"),2])
test "possible infinite recursion", ()->
#######################
#bind tests
#######################
test "bind test with no var", ()->
i1 = box([1,variable("a")])
i2 = {test:"test", fun:"somthing"}
test "bind test with var", ()->
i1 = box([1,variable("a")])
i2 = [1,variable("b")]
i3 = [1,[1,2]]
test "bind rollback", ()->
i1 = [1,variable("a")]
i2 = box(i1)
i2.bind("a", {test:"test"})
i2.rollback()
#######################
#unify tests
#######################
test "variable equal [X,2,X] -> [1,2,1]", () ->
tins = box([variable("x"), 2, variable("x")]).unify([1,2,1])
#######################
#extract tests
#######################
test "simple variable extraction test", () ->
tins = box({a: [1,2,3]}).unify({a: [1,variable("b"),3]})
test "extract all variables test", () ->
tins = box({a: [1,2,3]}).unify({a: [1,variable("b"),3]})
#######################
#hidden variables tests
#######################
test "create hidden variable", () ->
test "simple hidden variable [_,X] -> [1,2]", () ->
test "multiple hidden variables [_,_,X] -> [1,2,3]", () ->
test "[[1,_,3],[1,2,3]] -> [X,X]", () ->
#######################
#list variable tests
#######################
test "simple list variable test [1,$a,b,5] -> [1,2,3,4,5]", () ->
test "both sides list variable test [1,$a,b,5] -> [1,b,3,5,b]", () ->
test "empty list variable test [1,$a,2]->[1,2] and [1,2]->[1,$a,2]", ()->
test "list variable in both test [1,$a,3]->[$b,2,3] and [$b,2,3]->[1,$a,3] and [$a,2,3]->[2,$a,3]", ()->
test "list variable in same place test [1,$a,3]->[1,$a,3]", ()->
test "list variable in same place different length [$a,1,2]->[$b,2]", ()->
test "list variable reference [$a,a]->[1,2,[1,2]]", ()->
test "list vairable ensure empty binding [$a,a]->[[]]", ()->
test "ensure only 1 list var in array", ()->
try
catch ex
#######################
#rollback tests
#######################
test "rollback successful unification", () ->
obj1 = [1,2,3]
obj2 = [variable("A"), variable("B"), 3]
cobj1 = box(obj1)
cobj2 = box(obj2)
cobj1.rollback()