observable.lua 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. describe('Observable', function()
  2. describe('create', function()
  3. it('returns an Observable', function()
  4. local observable = Rx.Observable.create()
  5. expect(observable).to.be.an(Rx.Observable)
  6. end)
  7. it('sets _subscribe to the first argument it was passed', function()
  8. local subscribe = function() end
  9. local observable = Rx.Observable.create(subscribe)
  10. expect(observable._subscribe).to.equal(subscribe)
  11. end)
  12. end)
  13. describe('subscribe', function()
  14. it('passes the first argument to _subscribe if it is a table', function()
  15. local observable = Rx.Observable.of()
  16. local observer = Rx.Observer.create()
  17. local function run() observable:subscribe(observer) end
  18. expect(spy(observable, '_subscribe', run)).to.equal({{observer}})
  19. end)
  20. it('creates a new Observer using the first three arguments and passes it to _subscribe if the first argument is not a table', function()
  21. local observable = Rx.Observable.of()
  22. local a, b, c = function() end, function() end, function() end
  23. local function run() observable:subscribe(a, b, c) end
  24. local observer = spy(observable, '_subscribe', run)[1][1]
  25. expect(observer).to.be.an(Rx.Observer)
  26. expect(observer._onNext).to.equal(a)
  27. expect(observer._onError).to.equal(b)
  28. expect(observer._onCompleted).to.equal(c)
  29. end)
  30. end)
  31. describe('empty', function()
  32. it('returns an Observable that does not produce any values', function()
  33. local observable = Rx.Observable.empty()
  34. local onNext, onError, onCompleted = observableSpy(observable)
  35. expect(#onNext).to.equal(0)
  36. expect(#onError).to.equal(0)
  37. expect(#onCompleted).to.equal(1)
  38. end)
  39. end)
  40. describe('never', function()
  41. it('returns an Observable that does not produce values or complete', function()
  42. local observable = Rx.Observable.never()
  43. local onNext, onError, onCompleted = observableSpy(observable)
  44. expect(#onNext).to.equal(0)
  45. expect(#onError).to.equal(0)
  46. expect(#onCompleted).to.equal(0)
  47. end)
  48. end)
  49. describe('throw', function()
  50. it('returns an Observable that produces an error', function()
  51. local observable = Rx.Observable.throw('message')
  52. expect(function() observable:subscribe() end).to.fail()
  53. end)
  54. end)
  55. describe('of', function()
  56. it('returns an Observable that produces the supplied arguments and completes', function()
  57. local observable = Rx.Observable.of(1, 2, 3)
  58. expect(observable).to.produce(1, 2, 3)
  59. end)
  60. it('returns an Observable that produces nil and completes if nil is passed', function()
  61. local observable = Rx.Observable.of(nil)
  62. expect(observable).to.produce(nil)
  63. end)
  64. it('returns an Observable that produces nothing if no arguments are passed', function()
  65. local observable = Rx.Observable.of()
  66. expect(observable).to.produce.nothing()
  67. end)
  68. end)
  69. describe('fromRange', function()
  70. it('errors if no arguments are provided', function()
  71. local run = function() Rx.Observable.fromRange():subscribe() end
  72. expect(run).to.fail()
  73. end)
  74. describe('with one argument', function()
  75. it('returns an Observable that produces elements sequentially from 1 to the first argument', function()
  76. local observable = Rx.Observable.fromRange(5)
  77. expect(observable).to.produce(1, 2, 3, 4, 5)
  78. end)
  79. it('returns an Observable that produces no elements if the first argument is less than one', function()
  80. local observable = Rx.Observable.fromRange(0)
  81. expect(observable).to.produce.nothing()
  82. end)
  83. end)
  84. describe('with two arguments', function()
  85. it('returns an Observable that produces elements sequentially from the first argument to the second argument', function()
  86. local observable = Rx.Observable.fromRange(1, 5)
  87. expect(observable).to.produce(1, 2, 3, 4, 5)
  88. end)
  89. it('returns an Observable that produces no elements if the first argument is greater than the second argument', function()
  90. local observable = Rx.Observable.fromRange(1, -5)
  91. expect(observable).to.produce.nothing()
  92. end)
  93. end)
  94. describe('with three arguments', function()
  95. it('returns an Observable that produces elements sequentially from the first argument to the second argument, incrementing by the third argument', function()
  96. local observable = Rx.Observable.fromRange(1, 5, 2)
  97. expect(observable).to.produce(1, 3, 5)
  98. end)
  99. end)
  100. end)
  101. describe('fromTable', function()
  102. it('errors if the first argument is not a table', function()
  103. local function run() Rx.Observable.fromTable():subscribe() end
  104. expect(run).to.fail()
  105. end)
  106. describe('with one argument', function()
  107. it('returns an Observable that produces values by iterating the table using pairs', function()
  108. local input = {foo = 'bar', 1, 2, 3}
  109. local observable = Rx.Observable.fromTable(input)
  110. local result = {}
  111. for key, value in pairs(input) do table.insert(result, {value}) end
  112. expect(observable).to.produce(result)
  113. end)
  114. end)
  115. describe('with two arguments', function()
  116. it('returns an Observable that produces values by iterating the table using the second argument', function()
  117. local input = {foo = 'bar', 3, 4, 5}
  118. local observable = Rx.Observable.fromTable(input, ipairs)
  119. expect(observable).to.produce(3, 4, 5)
  120. end)
  121. end)
  122. describe('with three arguments', function()
  123. it('returns an Observable that produces value-key pairs by iterating the table if the third argument is true', function()
  124. local input = {foo = 'bar', 3, 4, 5}
  125. local observable = Rx.Observable.fromTable(input, ipairs, true)
  126. expect(observable).to.produce({{3, 1}, {4, 2}, {5, 3}})
  127. end)
  128. end)
  129. end)
  130. describe('fromCoroutine', function()
  131. it('returns an Observable that produces a value whenever the first argument yields a value', function()
  132. local coroutine = coroutine.create(function()
  133. coroutine.yield(1)
  134. coroutine.yield(2)
  135. return 3
  136. end)
  137. Rx.scheduler = Rx.CooperativeScheduler.create()
  138. local observable = Rx.Observable.fromCoroutine(coroutine, Rx.scheduler)
  139. local onNext, onError, onCompleted = observableSpy(observable)
  140. repeat Rx.scheduler:update()
  141. until Rx.scheduler:isEmpty()
  142. expect(onNext).to.equal({{1}, {2}, {3}})
  143. end)
  144. it('accepts a function as the first argument and wraps it into a coroutine', function()
  145. local coroutine = function()
  146. coroutine.yield(1)
  147. coroutine.yield(2)
  148. return 3
  149. end
  150. Rx.scheduler = Rx.CooperativeScheduler.create()
  151. local observable = Rx.Observable.fromCoroutine(coroutine, Rx.scheduler)
  152. local onNext, onError, onCompleted = observableSpy(observable)
  153. repeat Rx.scheduler:update()
  154. until Rx.scheduler:isEmpty()
  155. expect(onNext).to.equal({{1}, {2}, {3}})
  156. end)
  157. it('shares values among Observers when the first argument is a coroutine', function()
  158. local coroutine = coroutine.create(function()
  159. coroutine.yield(1)
  160. coroutine.yield(2)
  161. return 3
  162. end)
  163. Rx.scheduler = Rx.CooperativeScheduler.create()
  164. local observable = Rx.Observable.fromCoroutine(coroutine, Rx.scheduler)
  165. local onNextA = observableSpy(observable)
  166. local onNextB = observableSpy(observable)
  167. repeat Rx.scheduler:update()
  168. until Rx.scheduler:isEmpty()
  169. expect(onNextA).to.equal({{1}, {3}})
  170. expect(onNextB).to.equal({{2}})
  171. end)
  172. it('uses a unique coroutine for each Observer when the first argument is a function', function()
  173. local coroutine = function()
  174. coroutine.yield(1)
  175. coroutine.yield(2)
  176. return 3
  177. end
  178. Rx.scheduler = Rx.CooperativeScheduler.create()
  179. local observable = Rx.Observable.fromCoroutine(coroutine, Rx.scheduler)
  180. local onNextA = observableSpy(observable)
  181. local onNextB = observableSpy(observable)
  182. repeat Rx.scheduler:update()
  183. until Rx.scheduler:isEmpty()
  184. expect(onNextA).to.equal({{1}, {2}, {3}})
  185. expect(onNextB).to.equal({{1}, {2}, {3}})
  186. end)
  187. end)
  188. describe('fromFileByLine', function()
  189. local oldIO = _G['io']
  190. _G['io'] = {}
  191. local filename = 'file.txt'
  192. it('returns an observable', function()
  193. expect(Rx.Observable.fromFileByLine(filename)).to.be.an(Rx.Observable)
  194. end)
  195. it('errors if the file does not exist', function()
  196. io.open = function() return nil end
  197. local onError = spy()
  198. Rx.Observable.fromFileByLine(filename):subscribe(nil, onError, nil)
  199. expect(onError).to.equal({{ filename }})
  200. end)
  201. it('returns an Observable that produces the lines of the file', function()
  202. io.open = function() return { close = function() end } end
  203. io.lines = function()
  204. local lines = { 'line1', 'line2', 'line3' }
  205. local i = 0
  206. return function()
  207. i = i + 1
  208. return lines[i]
  209. end
  210. end
  211. expect(Rx.Observable.fromFileByLine(filename)).to.produce('line1', 'line2', 'line3')
  212. end)
  213. io = oldIO
  214. end)
  215. describe('defer', function()
  216. it('returns an Observable', function()
  217. expect(Rx.Observable.defer()).to.be.an(Rx.Observable)
  218. end)
  219. it('fails if no factory is specified', function()
  220. expect(Rx.Observable.defer().subscribe).to.fail()
  221. end)
  222. it('fails if the factory does not return an Observable', function()
  223. expect(Rx.Observable.defer(function() return nil end).subscribe).to.fail()
  224. end)
  225. it('uses the factory function to create a new Observable for each subscriber', function()
  226. local i = 0
  227. local function factory()
  228. i = i + 1
  229. return Rx.Observable.fromRange(i, 3)
  230. end
  231. expect(Rx.Observable.defer(factory)).to.produce(1, 2, 3)
  232. expect(Rx.Observable.defer(factory)).to.produce(2, 3)
  233. expect(Rx.Observable.defer(factory)).to.produce(3)
  234. end)
  235. it('returns Observables that return subscriptions from their subscribe function', function()
  236. local subscription = Rx.Subscription.create()
  237. local function factory()
  238. return Rx.Observable.create(function()
  239. return subscription
  240. end)
  241. end
  242. expect(Rx.Observable.defer(factory):subscribe()).to.equal(subscription)
  243. end)
  244. end)
  245. describe('replicate', function()
  246. it('returns an Observable', function()
  247. expect(Rx.Observable.replicate()).to.be.an(Rx.Observable)
  248. end)
  249. it('returns an Observable that produces the first argument a specified number of times', function()
  250. expect(Rx.Observable.replicate(1, 3)).to.produce(1, 1, 1)
  251. end)
  252. it('produces nothing if the count is less than or equal to zero', function()
  253. expect(Rx.Observable.replicate(1, 0)).to.produce.nothing()
  254. expect(Rx.Observable.replicate(1, -1)).to.produce.nothing()
  255. end)
  256. end)
  257. describe('dump', function()
  258. end)
  259. dofile('tests/all.lua')
  260. dofile('tests/amb.lua')
  261. dofile('tests/average.lua')
  262. dofile('tests/buffer.lua')
  263. dofile('tests/catch.lua')
  264. dofile('tests/combineLatest.lua')
  265. dofile('tests/compact.lua')
  266. dofile('tests/concat.lua')
  267. dofile('tests/contains.lua')
  268. dofile('tests/count.lua')
  269. dofile('tests/defaultIfEmpty.lua')
  270. dofile('tests/distinct.lua')
  271. dofile('tests/distinctUntilChanged.lua')
  272. dofile('tests/elementAt.lua')
  273. dofile('tests/filter.lua')
  274. dofile('tests/find.lua')
  275. dofile('tests/first.lua')
  276. dofile('tests/flatMap.lua')
  277. dofile('tests/flatMapLatest.lua')
  278. dofile('tests/flatten.lua')
  279. dofile('tests/ignoreElements.lua')
  280. dofile('tests/last.lua')
  281. dofile('tests/map.lua')
  282. dofile('tests/max.lua')
  283. dofile('tests/min.lua')
  284. dofile('tests/merge.lua')
  285. dofile('tests/pack.lua')
  286. dofile('tests/partition.lua')
  287. dofile('tests/pluck.lua')
  288. dofile('tests/reduce.lua')
  289. dofile('tests/reject.lua')
  290. dofile('tests/retry.lua')
  291. dofile('tests/sample.lua')
  292. dofile('tests/scan.lua')
  293. dofile('tests/skip.lua')
  294. dofile('tests/skipLast.lua')
  295. dofile('tests/skipUntil.lua')
  296. dofile('tests/skipWhile.lua')
  297. dofile('tests/startWith.lua')
  298. dofile('tests/sum.lua')
  299. dofile('tests/switch.lua')
  300. dofile('tests/take.lua')
  301. dofile('tests/takeLast.lua')
  302. dofile('tests/takeUntil.lua')
  303. dofile('tests/takeWhile.lua')
  304. dofile('tests/tap.lua')
  305. dofile('tests/unpack.lua')
  306. dofile('tests/unwrap.lua')
  307. dofile('tests/window.lua')
  308. dofile('tests/with.lua')
  309. dofile('tests/zip.lua')
  310. end)