/test/brainfuckSpec.js

https://gitlab.com/bxt/brainfuck-debugger · JavaScript · 413 lines · 341 code · 72 blank · 0 comment · 6 complexity · 8e68546f42592316b18ecb1aafe7ed7d MD5 · raw file

  1. import { expect } from './helper'
  2. import { create, isComment, isDone, minify, restart, run, step } from '../src/brainfuck'
  3. describe('brainfuck', function () {
  4. describe('#create(input, instructions)', function () {
  5. const machine = create('test input', 'test instructions')
  6. it('sets machine\'s input to first param', function () {
  7. expect(machine.input).to.equal('test input')
  8. })
  9. it('creates a machine at input position 0', function () {
  10. expect(machine.inputPointer).to.equal(0)
  11. })
  12. it('creates a machine at instruction 0', function () {
  13. expect(machine.instructionPointer).to.equal(0)
  14. })
  15. it('sets machine\'s instructions to second param', function () {
  16. expect(machine.instructions).to.equal('test instructions')
  17. })
  18. it('creates a machine with just one zero memory cell', function () {
  19. expect(machine.memory).to.deep.equal([0])
  20. })
  21. it('creates a machine at memory 0', function () {
  22. expect(machine.memoryPointer).to.equal(0)
  23. })
  24. it('creates a machine with empty output', function () {
  25. expect(machine.output).to.equal('')
  26. })
  27. })
  28. describe('#isComment(instruction)', function () {
  29. ;[',', '.', '+', '-', '<', '>', '[', ']'].forEach((instruction) => {
  30. it(`returns false for "${instruction}"`, function () {
  31. expect(isComment(instruction)).to.be.false()
  32. })
  33. })
  34. ;['#', '?', 'a', 'A', '1', '9', '0', '❤️'].forEach((instruction) => {
  35. it(`returns true for "${instruction}"`, function () {
  36. expect(isComment(instruction)).to.be.true()
  37. })
  38. })
  39. })
  40. describe('#isDone(machine)', function () {
  41. it(`returns false for a freshly created machine`, function () {
  42. const machine = create('', '.--')
  43. expect(isDone(machine)).to.be.false()
  44. })
  45. it(`returns true for a machine after run`, function () {
  46. const machine = create('', '.--')
  47. run(machine)
  48. expect(isDone(machine)).to.be.true()
  49. })
  50. it(`returns true for a machine without instructions`, function () {
  51. const machine = create('', '')
  52. expect(isDone(machine)).to.be.true()
  53. })
  54. })
  55. describe('#minify(instructions)', function () {
  56. it(`does nothing for a straightforwad program`, function () {
  57. expect(minify(',-.+')).to.equal(',-.+')
  58. })
  59. it(`removes all the comments`, function () {
  60. expect(minify(',a-b.c+d')).to.equal(',-.+')
  61. })
  62. it(`optimizes some no-ops`, function () {
  63. expect(minify('... move back < and forth > or add + and subtract - even repeatedly <-<>+> ...')).to.equal('......')
  64. })
  65. })
  66. describe('#restart(machine)', function () {
  67. const machine = create('test input', '.+++,')
  68. run(machine)
  69. restart(machine)
  70. it('does not change machine\'s input', function () {
  71. expect(machine.input).to.equal('test input')
  72. })
  73. it('sets the machine input position to 0', function () {
  74. expect(machine.inputPointer).to.equal(0)
  75. })
  76. it('sets the machine instruction pointer to 0', function () {
  77. expect(machine.instructionPointer).to.equal(0)
  78. })
  79. it('does not change machine\'s instructions', function () {
  80. expect(machine.instructions).to.equal('.+++,')
  81. })
  82. it('resets the machine to just one zero memory cell', function () {
  83. expect(machine.memory).to.deep.equal([0])
  84. })
  85. it('resets the machine memory pointer to 0', function () {
  86. expect(machine.memoryPointer).to.equal(0)
  87. })
  88. it('restets the output to be empty', function () {
  89. expect(machine.output).to.equal('')
  90. })
  91. })
  92. describe('#run(machine)', function () {
  93. it('prints back an input character', function () {
  94. const machine = create('abc', ',.')
  95. const output = run(machine)
  96. expect(output).to.equal('a')
  97. })
  98. it('prints a few characters', function () {
  99. const machine = create('', new Array(66).join('+') + '.+.+.')
  100. const output = run(machine)
  101. expect(output).to.equal('ABC')
  102. })
  103. it('prints back input characters', function () {
  104. const machine = create('abc', ',+.,++.,-.')
  105. const output = run(machine)
  106. expect(output).to.equal('bdb')
  107. })
  108. it('moves around the memory', function () {
  109. const machine = create('abc', '<<<,+>,++>,-<<.>.>.')
  110. const output = run(machine)
  111. expect(output).to.equal('bdb')
  112. })
  113. it('can do loops', function () {
  114. const machine = create('', '++++[>++++[>++++<-]<-]>+++++[>+.<-]')
  115. const output = run(machine)
  116. expect(output).to.equal('ABCDE')
  117. })
  118. it('reverses the input', function () {
  119. const machine = create('rewers', '+[>,]<[<]>->[>]<[.<]')
  120. const output = run(machine)
  121. expect(output).to.equal('srewer')
  122. })
  123. it('reverses the input (2)', function () {
  124. const machine = create('rewers', '+[>,]<<[>.<<]')
  125. const output = run(machine)
  126. expect(output).to.equal('srewer')
  127. })
  128. })
  129. describe('#step(machine)', function () {
  130. context('instruction is "."', function () {
  131. const machine = create('', '.--')
  132. machine.memory = [65]
  133. machine.output = 't'
  134. step(machine)
  135. it('advances the instruction pointer', function () {
  136. expect(machine.instructionPointer).to.equal(1)
  137. })
  138. it('appends the current memory to the output', function () {
  139. expect(machine.output).to.deep.equal('tA')
  140. })
  141. })
  142. context('instruction is ","', function () {
  143. const machine = create('A', ',..')
  144. step(machine)
  145. it('advances the input pointer', function () {
  146. expect(machine.inputPointer).to.equal(1)
  147. })
  148. it('advances the instruction pointer', function () {
  149. expect(machine.instructionPointer).to.equal(1)
  150. })
  151. it('puts input in the memory', function () {
  152. expect(machine.memory).to.deep.equal([65])
  153. })
  154. })
  155. context('instruction is "+"', function () {
  156. context('machine is freshly created', function () {
  157. const machine = create('A', '+..')
  158. step(machine)
  159. it('advances the instruction pointer', function () {
  160. expect(machine.instructionPointer).to.equal(1)
  161. })
  162. it('increases the memory pointed to by 1', function () {
  163. expect(machine.memory).to.deep.equal([1])
  164. })
  165. })
  166. context('machine already has values', function () {
  167. const machine = create('A', '..+')
  168. machine.memory = [4, 5, 6]
  169. machine.memoryPointer = 1
  170. machine.instructionPointer = 2
  171. step(machine)
  172. it('advances the instruction pointer', function () {
  173. expect(machine.instructionPointer).to.equal(3)
  174. })
  175. it('increases the memory pointed to by 1', function () {
  176. expect(machine.memory).to.deep.equal([4, 6, 6])
  177. })
  178. })
  179. })
  180. context('instruction is "-"', function () {
  181. context('machine is freshly created', function () {
  182. const machine = create('A', '-..')
  183. step(machine)
  184. it('advances the instruction pointer', function () {
  185. expect(machine.instructionPointer).to.equal(1)
  186. })
  187. it('decreases the memory pointed to by 1', function () {
  188. expect(machine.memory).to.deep.equal([-1])
  189. })
  190. })
  191. context('machine already has values', function () {
  192. const machine = create('A', '..-')
  193. machine.memory = [4, 5, 6]
  194. machine.memoryPointer = 1
  195. machine.instructionPointer = 2
  196. step(machine)
  197. it('advances the instruction pointer', function () {
  198. expect(machine.instructionPointer).to.equal(3)
  199. })
  200. it('decreases the memory pointed to by 1', function () {
  201. expect(machine.memory).to.deep.equal([4, 4, 6])
  202. })
  203. })
  204. })
  205. context('instruction is ">"', function () {
  206. context('machine is freshly created', function () {
  207. const machine = create('A', '>..')
  208. step(machine)
  209. it('advances the instruction pointer', function () {
  210. expect(machine.instructionPointer).to.equal(1)
  211. })
  212. it('advances the memory pointer', function () {
  213. expect(machine.memoryPointer).to.equal(1)
  214. })
  215. it('adds a zero cell to the memory', function () {
  216. expect(machine.memory).to.deep.equal([0, 0])
  217. })
  218. })
  219. context('machine already has values', function () {
  220. const machine = create('A', '>..')
  221. machine.memory = [4, 5, 6]
  222. machine.memoryPointer = 1
  223. step(machine)
  224. it('advances the instruction pointer', function () {
  225. expect(machine.instructionPointer).to.equal(1)
  226. })
  227. it('advances the memory pointer', function () {
  228. expect(machine.memoryPointer).to.equal(2)
  229. })
  230. it('does not change the memory', function () {
  231. expect(machine.memory).to.deep.equal([4, 5, 6])
  232. })
  233. })
  234. })
  235. context('instruction is "<"', function () {
  236. context('machine is freshly created', function () {
  237. const machine = create('A', '<..')
  238. step(machine)
  239. it('advances the instruction pointer', function () {
  240. expect(machine.instructionPointer).to.equal(1)
  241. })
  242. it('does not change the memory pointer', function () {
  243. expect(machine.memoryPointer).to.equal(0)
  244. })
  245. it('adds a zero cell in front of the memory', function () {
  246. expect(machine.memory).to.deep.equal([0, 0])
  247. })
  248. })
  249. context('machine already has values', function () {
  250. context('memoryPointer is 0', function () {
  251. const machine = create('A', '<..')
  252. machine.memory = [4, 5, 6]
  253. machine.memoryPointer = 0
  254. step(machine)
  255. it('advances the instruction pointer', function () {
  256. expect(machine.instructionPointer).to.equal(1)
  257. })
  258. it('does not change the memory pointer', function () {
  259. expect(machine.memoryPointer).to.equal(0)
  260. })
  261. it('adds a zero cell in front of the memory', function () {
  262. expect(machine.memory).to.deep.equal([0, 4, 5, 6])
  263. })
  264. })
  265. context('memoryPointer is 1', function () {
  266. const machine = create('A', '<..')
  267. machine.memory = [4, 5, 6]
  268. machine.memoryPointer = 1
  269. step(machine)
  270. it('advances the instruction pointer', function () {
  271. expect(machine.instructionPointer).to.equal(1)
  272. })
  273. it('sets the memory pointer back to 0', function () {
  274. expect(machine.memoryPointer).to.equal(0)
  275. })
  276. it('does not change the memory', function () {
  277. expect(machine.memory).to.deep.equal([4, 5, 6])
  278. })
  279. })
  280. })
  281. })
  282. context('instruction is "["', function () {
  283. context('machine is freshly created', function () {
  284. const machine = create('A', '[-[.]-]...')
  285. step(machine)
  286. it('advances the instruction pointer to after the matching ]', function () {
  287. expect(machine.instructionPointer).to.equal(7)
  288. })
  289. })
  290. context('machine already has values', function () {
  291. const machine = create('A', '..[-[.]-]...')
  292. machine.memory = [1]
  293. machine.instructionPointer = 2
  294. step(machine)
  295. it('advances the instruction pointer', function () {
  296. expect(machine.instructionPointer).to.equal(3)
  297. })
  298. })
  299. })
  300. context('instruction is "]"', function () {
  301. context('the current cell is 0', function () {
  302. const machine = create('A', '..[-[.]-]...')
  303. machine.memory = [0]
  304. machine.instructionPointer = 8
  305. step(machine)
  306. it('advances the instruction pointer', function () {
  307. expect(machine.instructionPointer).to.equal(9)
  308. })
  309. })
  310. context('the current cell is 1', function () {
  311. const machine = create('A', '..[-[.]-]...')
  312. machine.memory = [1]
  313. machine.instructionPointer = 8
  314. step(machine)
  315. it('resets the instruction pointer to after the matching [', function () {
  316. expect(machine.instructionPointer).to.equal(3)
  317. })
  318. })
  319. })
  320. context('at a comment', function () {
  321. const machine = create('A', 'ccc+..')
  322. step(machine)
  323. it('advances the instruction pointer through the whole comment', function () {
  324. expect(machine.instructionPointer).to.equal(4)
  325. })
  326. it('runs the command after the comment', function () {
  327. expect(machine.memory).to.deep.equal([1])
  328. })
  329. })
  330. context('with comment after command', function () {
  331. const machine = create('A', 'ccc+cc..')
  332. step(machine)
  333. it('advances the instruction pointer through the comment afterwards', function () {
  334. expect(machine.instructionPointer).to.equal(6)
  335. })
  336. it('runs the command between the comments', function () {
  337. expect(machine.memory).to.deep.equal([1])
  338. })
  339. })
  340. })
  341. })