bjorn пре 10 година
родитељ
комит
d9f9a27a5d
3 измењених фајлова са 195 додато и 3 уклоњено
  1. 6 2
      tests/lust.lua
  2. 142 0
      tests/observable.lua
  3. 47 1
      tests/runner.lua

+ 6 - 2
tests/lust.lua

@@ -10,9 +10,10 @@ lust.errors = 0
 local red = string.char(27) .. '[31m'
 local red = string.char(27) .. '[31m'
 local green = string.char(27) .. '[32m'
 local green = string.char(27) .. '[32m'
 local normal = string.char(27) .. '[0m'
 local normal = string.char(27) .. '[0m'
+local function indent(level) return string.rep('\t', level or lust.level) end
 
 
 function lust.describe(name, fn)
 function lust.describe(name, fn)
-  print(string.rep('\t', lust.level) .. name)
+  print(indent() .. name)
   lust.level = lust.level + 1
   lust.level = lust.level + 1
   fn()
   fn()
   lust.level = lust.level - 1
   lust.level = lust.level - 1
@@ -25,7 +26,10 @@ function lust.it(name, fn)
   else lust.errors = lust.errors + 1 end
   else lust.errors = lust.errors + 1 end
   local color = success and green or red
   local color = success and green or red
   local label = success and 'PASS' or 'FAIL'
   local label = success and 'PASS' or 'FAIL'
-  print(string.rep('\t', lust.level) .. color .. label .. normal .. ' ' .. name)
+  print(indent() .. color .. label .. normal .. ' ' .. name)
+  if err then
+    print(indent(lust.level + 1) .. red .. err .. normal)
+  end
   if type(lust.onafter) == 'function' then lust.onafter(name) end
   if type(lust.onafter) == 'function' then lust.onafter(name) end
 end
 end
 
 

+ 142 - 0
tests/observable.lua

@@ -0,0 +1,142 @@
+describe('Observable', function()
+  describe('create', function()
+    it('returns an Observable', function()
+      local observable = Rx.Observable.create()
+      expect(observable).to.be.an(Rx.Observable)
+    end)
+
+    it('sets _subscribe to the first argument it was passed', function()
+      local subscribe = function() end
+      local observable = Rx.Observable.create(subscribe)
+      expect(observable._subscribe).to.equal(subscribe)
+    end)
+  end)
+
+  describe('subscribe', function()
+    it('passes the first argument to _subscribe if it is a table', function()
+      local observable = Rx.Observable.fromValue()
+      local observer = Rx.Observer.create()
+      local function run() observable:subscribe(observer) end
+      expect(spy(observable, '_subscribe', run)).to.equal({{observer}})
+    end)
+
+    it('creates a new Observer using the first three arguments and passes it to _subscribe if the first argument is not a table', function()
+      local observable = Rx.Observable.fromValue()
+      local a, b, c = function() end, function() end, function() end
+      local function run() observable:subscribe(a, b, c) end
+      local observer = spy(observable, '_subscribe', run)[1][1]
+      expect(observer).to.be.an(Rx.Observer)
+      expect(observer._onNext).to.equal(a)
+      expect(observer._onError).to.equal(b)
+      expect(observer._onComplete).to.equal(c)
+    end)
+  end)
+
+  describe('fromValue', function()
+    it('returns an Observable that produces the first argument and completes', function()
+      local observable = Rx.Observable.fromValue(1, 2, 3)
+      expect(observable).to.produce(1)
+    end)
+
+    it('returns an Observable that produces nil and completes if no arguments are passed', function()
+      local observable = Rx.Observable.fromValue()
+      expect(observable).to.produce(nil)
+    end)
+  end)
+
+  describe('fromRange', function()
+    it('errors if no arguments are provided', function()
+      local run = function() Rx.Observable.fromRange():subscribe() end
+      expect(run).to.fail()
+    end)
+
+    describe('with one argument', function()
+      it('returns an Observable that produces elements sequentially from 1 to the first argument', function()
+        local observable = Rx.Observable.fromRange(5)
+        expect(observable).to.produce(1, 2, 3, 4, 5)
+      end)
+
+      it('returns an Observable that produces no elements if the first argument is less than one', function()
+        local observable = Rx.Observable.fromRange(0)
+        expect(observable).to.produce.nothing()
+      end)
+    end)
+
+    describe('with two arguments', function()
+      it('returns an Observable that produces elements sequentially from the first argument to the second argument', function()
+        local observable = Rx.Observable.fromRange(1, 5)
+        expect(observable).to.produce(1, 2, 3, 4, 5)
+      end)
+
+      it('returns an Observable that produces no elements if the first argument is greater than the second argument', function()
+        local observable = Rx.Observable.fromRange(1, -5)
+        expect(observable).to.produce.nothing()
+      end)
+    end)
+
+    describe('with three arguments', function()
+      it('returns an Observable that produces elements sequentially from the first argument to the second argument, incrementing by the third argument', function()
+        local observable = Rx.Observable.fromRange(1, 5, 2)
+        expect(observable).to.produce(1, 3, 5)
+      end)
+    end)
+  end)
+
+  describe('fromTable', function()
+    it('errors if the first argument is not a table', function()
+      local function run() Rx.Observable.fromTable():subscribe() end
+      expect(run).to.fail()
+    end)
+
+    describe('with one argument', function()
+      it('returns an Observable that produces value-key pairs by iterating the table using pairs', function()
+        local input = {foo = 'bar', 1, 2, 3}
+        local observable = Rx.Observable.fromTable(input)
+        local result = {}
+        for key, value in pairs(input) do table.insert(result, {value, key}) end
+        expect(observable).to.produce(result)
+      end)
+    end)
+
+    describe('with two arguments', function()
+      it('returns an Observable that produces value-key pairs by iterating the table using the second argument', function()
+        local input = {foo = 'bar', 3, 4, 5}
+        local observable = Rx.Observable.fromTable(input, ipairs)
+        expect(observable).to.produce({{3, 1}, {4, 2}, {5, 3}})
+      end)
+    end)
+  end)
+
+  describe('fromCoroutine', function()
+    it('returns an Observable that produces a value whenever the first argument yields a value', function()
+      local coroutine = coroutine.create(function()
+        coroutine.yield(1)
+        coroutine.yield(2)
+        return 3
+      end)
+
+      local observable = Rx.Observable.fromCoroutine(coroutine)
+      local onNext, onError, onComplete = observableSpy(observable)
+      repeat Rx.scheduler:update()
+      until Rx.scheduler:isEmpty()
+      expect(onNext).to.equal({{1}, {2}, {3}})
+    end)
+
+    it('accepts a function as the first argument and wraps it into a coroutine', function()
+      local coroutine = function()
+        coroutine.yield(1)
+        coroutine.yield(2)
+        return 3
+      end
+
+      local observable = Rx.Observable.fromCoroutine(coroutine)
+      local onNext, onError, onComplete = observableSpy(observable)
+      repeat Rx.scheduler:update()
+      until Rx.scheduler:isEmpty()
+      expect(onNext).to.equal({{1}, {2}, {3}})
+    end)
+  end)
+
+  describe('dump', function()
+  end)
+end)

+ 47 - 1
tests/runner.lua

@@ -5,12 +5,58 @@ for _, fn in pairs({'describe', 'it', 'test', 'expect', 'spy', 'before', 'after'
   _G[fn] = lust[fn]
   _G[fn] = lust[fn]
 end
 end
 
 
+observableSpy = function(observable)
+  local observer = Rx.Observer.create(_, function() end, _)
+  local onNext = spy(observer, '_onNext')
+  local onError = spy(observer, '_onError')
+  local onComplete = spy(observer, '_onComplete')
+  observable:subscribe(observer)
+  return onNext, onError, onComplete
+end
+
+lust.paths['produce'] = {
+  'nothing',
+  f = function(observable, ...)
+    local args = {...}
+    local values
+    if type(args[1]) ~= 'table' then
+      values = {}
+      for i = 1, math.max(#args, 1) do
+        table.insert(values, {args[i]})
+      end
+    else
+      values = args[1]
+    end
+
+    local onNext, onError, onComplete = observableSpy(observable)
+    expect(observable).to.be.an(Rx.Observable)
+    expect(onNext).to.equal(values)
+    expect(#onError).to.equal(0)
+    expect(#onComplete).to.equal(1)
+    return true
+  end
+}
+
+lust.paths['nothing'] = {
+  f = function(observable)
+    local onNext, onError, onComplete = observableSpy(observable)
+    expect(observable).to.be.an(Rx.Observable)
+    expect(#onNext).to.equal(0)
+    expect(#onError).to.equal(0)
+    expect(#onComplete).to.equal(1)
+    return true
+  end
+}
+
+table.insert(lust.paths['to'], 'produce')
+
 if arg[1] then
 if arg[1] then
   arg[1] = arg[1]:gsub('^(tests/).+', ''):gsub('%.lua$', '')
   arg[1] = arg[1]:gsub('^(tests/).+', ''):gsub('%.lua$', '')
   dofile('tests/' .. arg[1] .. '.lua')
   dofile('tests/' .. arg[1] .. '.lua')
 else
 else
   local files = {
   local files = {
-    'observer'
+    'observer',
+    'observable'
   }
   }
 
 
   for i, file in ipairs(files) do
   for i, file in ipairs(files) do