diff --git a/README.md b/README.md index 94b6ec0..c4c7e6f 100644 --- a/README.md +++ b/README.md @@ -1,171 +1,175 @@ -# pico-test - -
- -> **Note:** This project is still in its initial stages, so I'd love feedback about the API and issue reports. - -### Intro - -PICO-8 is great but debugging your code in this little vm can be a chore. - -If you're tired of riddling your carts with `printh`s or have given up on test-driven development, this tool should help you out. - -### Installation - - npm i -g pico-test - -> **Note:** you can also download it directly from the [releases section](https://github.com/jozanza/pico-test/releases) - -### Usage - -Copy/paste the following snippet into the cart you wish to test: - -```lua -function test(title,f) -local desc=function(msg,f) - printh('⚡:desc:'..msg) - f() -end -local it=function(msg,f) - printh('⚡:it:'..msg) - local xs={f()} - for i=1,#xs do - if xs[i] == true then - printh('⚡:assert:true') - else - printh('⚡:assert:false') - end - end - printh('⚡:it_end') -end -printh('⚡:test:'..title) -f(desc,it) -printh('⚡:test_end') -end -``` - -Next, be sure PICO-8 is aliased properly in your terminal. You may have to do something like the following: - - alias pico-8='/Applications/PICO-8.app/Contents/MacOS/pico8' - -Last, run Pico-8 from your terminal and pipe its output to `pico-test`. - - pico-8 | pico-test - -Each time your run your cart, test results will be printed to `stdout`. Now, you just have to write some tests! :) - -### API - -`pico-test`'s api is will be pretty familiar if you've ever used [mocha](https://mochajs.org/). There are only 3 functions to learn: `test()`, `desc()`, and `it()` - -#### test(title:string, fn:function) - -initiates testing, wraps around test descriptions and tests, providing the callback `fn` with two args: `desc` and `it` – the other two functions in this API. - -| Type | Param | Description | -|----------|-------|-------------| -| String | title | title of test suite -| Function | fn | callback to call with `desc` and `it` - -#### desc(description:string, fn:function) - -Describes a set of tests. This function is applied as the first argument of the callback function passed to `test` - -| Type | Param | Description | -|----------|-------------|-------------| -| String | description | description for tests to be run inside of param `fn` -| Function | fn | callback to call with `desc` and `it` - - -#### it(message:string, fn:function) - -Returns one or more boolean values representing test assertions. all returned values must be `true` or your test will fail. This function is applied as the second argument of the callback function passed to `test` - -| Type | Param | Description | -|----------|---------|-------------| -| String | message | message starting with "should" -| Function | fn | callback to return assertions from - - -### Example - -Here's what it looks like in action: - -```lua --- here's an object with methods we want to test -local math={ - gt=function(a,b) return a>b end, - lt=function(a,b) return a operator', function() - return gt(1,0) - end) - end) - - desc('math.lt()', function() - local lt = math.lt - it('should return type boolean',function() - return 'boolean' == type(lt(1,0)) - end) - it('should give same result as < operator',function() - return lt(1, 0) == false - end) - end) - - desc('math.mul()', function() - local mul = math.mul - it('should return type number', function() - local a = rnd(time()) - local b = rnd(time()) - return 'number' == type(mul(a,b)) - end) - it('should give same result as * operator', function() - local x=rnd(time()) - return - x*1 == mul(x,1), - x*2 == mul(x,2), - x*3 == mul(x,3) - end) - end) - - desc('math.div()', function() - local div = math.div - it('should return type number', function() - local a = rnd(time()) - local b = rnd(time()) - return 'number' == type(div(a,b)) - end) - it('should give same result as / operator', function() - local x=1+rnd(time()) - return - x/1 == div(x,1), - x/2 == div(x,2), - x/3 == div(x,3) - end) - end) - -end) -``` - -### License - -Copyright (c) 2015 Josiah Savary. Made available under The MIT License (MIT). +# pico-test + + + +> **Note:** This project is still in its initial stages, so I'd love feedback about the API and issue reports. + +### Intro + +PICO-8 is great but debugging your code in this little vm can be a chore. + +If you're tired of riddling your carts with `printh`s or have given up on test-driven development, this tool should help you out. + +### Installation + + npm i -g pico-test + +> **Note:** you can also download it directly from the [releases section](https://github.com/jozanza/pico-test/releases) + +### Usage + +Copy/paste `testrunner.lua` into the cart you wish to test: + +```lua +test = function (title,f) + local desc=function(msg,f) + printh('✽:desc:'..msg) + f() + end + local it=function(msg,f) + printh('✽:it:'..msg) + local xs=f and {f()} or {} + if #xs>0 then + for i=1,#xs do + if xs[i]==true then + printh('✽:assert:true') + else + printh('✽:assert:false') + end + end + else + printh('✽:pend:pend') + end + printh('✽:it_end') + end + printh('✽:test:'..title) + f(desc,it) + printh('✽:test_end') +end +``` + +Next, be sure PICO-8 is aliased properly in your terminal. You may have to do something like the following: + + alias pico-8='/Applications/PICO-8.app/Contents/MacOS/pico8' + +Last, run Pico-8 from your terminal and pipe its output to `pico-test`. + + pico-8 | pico-test + +Each time your run your cart, test results will be printed to `stdout`. Now, you just have to write some tests! :) + +### API + +`pico-test`'s api is will be pretty familiar if you've ever used [mocha](https://mochajs.org/). There are only 3 functions to learn: `test()`, `desc()`, and `it()` + +#### test(title:string, fn:function) + +initiates testing, wraps around test descriptions and tests, providing the callback `fn` with two args: `desc` and `it` – the other two functions in this API. + +| Type | Param | Description | +|----------|-------|-------------| +| String | title | title of test suite +| Function | fn | callback to call with `desc` and `it` + +#### desc(description:string, fn:function) + +Describes a set of tests. This function is applied as the first argument of the callback function passed to `test` + +| Type | Param | Description | +|----------|-------------|-------------| +| String | description | description for tests to be run inside of param `fn` +| Function | fn | callback to call with `desc` and `it` + + +#### it(message:string, fn:function) + +Returns one or more boolean values representing test assertions. all returned values must be `true` or your test will fail. This function is applied as the second argument of the callback function passed to `test` + +| Type | Param | Description | +|----------|---------|-------------| +| String | message | message starting with "should" +| Function | fn | callback to return assertions from + + +### Example + +Here's what it looks like in action: + +```lua +-- here's an object with methods we want to test +local math={ + gt=function(a,b) return a>b end, + lt=function(a,b) return a operator', function() + return gt(1,0) + end) + end) + + desc('math.lt()', function() + local lt = math.lt + it('should return type boolean',function() + return 'boolean' == type(lt(1,0)) + end) + it('should give same result as < operator',function() + return lt(1, 0) == false + end) + end) + + desc('math.mul()', function() + local mul = math.mul + it('should return type number', function() + local a = rnd(time()) + local b = rnd(time()) + return 'number' == type(mul(a,b)) + end) + it('should give same result as * operator', function() + local x=rnd(time()) + return + x*1 == mul(x,1), + x*2 == mul(x,2), + x*3 == mul(x,3) + end) + end) + + desc('math.div()', function() + local div = math.div + it('should return type number', function() + local a = rnd(time()) + local b = rnd(time()) + return 'number' == type(div(a,b)) + end) + it('should give same result as / operator', function() + local x=1+rnd(time()) + return + x/1 == div(x,1), + x/2 == div(x,2), + x/3 == div(x,3) + end) + end) + +end) +``` + +### License + +Copyright (c) 2015 Josiah Savary. Made available under The MIT License (MIT). diff --git a/index b/index.js similarity index 94% rename from index rename to index.js index bf279e4..0055957 100755 --- a/index +++ b/index.js @@ -50,7 +50,7 @@ const parseInput = curry((dispatch, write) => { let line = '' let concat = false return x => { - if (x[0] === '⚡') concat = true + if (x[0] === '✽') concat = true if (!concat) write(x) else { line += x @@ -189,6 +189,9 @@ function reducer (state, action) { nextState.failCount += 1 } break + case 'pend': + nextState.suites[i].cases[j].assertions.push(_[0]) + break default: break } return nextState @@ -228,16 +231,28 @@ function reporter (state, action) { const kase = test.cases[test.cases.length - 1] // const duration = kase.stopped - kase.started const failed = kase.assertions.reduce((next, x) => next || !x, false) + const pended = kase.assertions[0] == 'pend' const fails = kase.assertions.map((passed, i) => passed ? '' : `\n • failed assertion #${i + 1}` ).join('') - out = '\n ' + [ - (failed ? '✖' : '✔'), - kase.name, - ''// `(${!duration ? '<1' : duration}ms)\n`, - ].join(' ') + fails + if (pended) { + out = '\n ' + [ + '-', + kase.name, + '(pending)', + ''// `(${!duration ? '<1' : duration}ms)\n`, + ].join(' ') + fails + } else { + out = '\n ' + [ + (failed ? '✖' : '✔'), + kase.name + ' (+' + kase.assertions.length + ')', + '', + ''// `(${!duration ? '<1' : duration}ms)\n`, + ].join(' ') + fails + } if (failed) out = format('red')(out) + else if (pended) out = format('yellow')(out) else out = format('green')(out) break default: break diff --git a/someappcode.lua b/someappcode.lua new file mode 100644 index 0000000..a856dee --- /dev/null +++ b/someappcode.lua @@ -0,0 +1,100 @@ +range = function (start, finish, step) + local sequence = {} + for i=(start or 0), (finish or 0), (step or 1) do + add(sequence, i) + end + return sequence +end + +eq = function (a, b) + for i, v in ipairs(a) do + if not b or v ~= b[i] then + return false + end + end + for i, v in ipairs(b) do + if not a or v ~= a[i] then + return false + end + end + return true +end + +reduce = function (things, fn) + local out = nil + for i, thing in ipairs(things) do + out = fn(out, thing) + end + return out +end + +map = function (things, convert) + local mapped = {} + foreach(things, function(thing) + add(mapped, convert(thing)) + end) + return mapped +end + +msb = function (n) + n = n or 0 + if n <= 1 then + return n + end + return reduce(range(0, 15), function (acc, i) + return acc or + ((2 ^ (i - 1) <= n and 2 ^ i > n) + and i or false) + end) +end + +test("some app code", function (desc, it) + desc('pico-8 api', function () + it('should pget what it pset', function () + pset(0, 0, 8) + return pget(0, 0) == 8 + end) + end) + desc('eq', function () + it('should not crash', function () + eq() + return true + end) + end) + desc('reduce', function () + it('should do a sum', function () + return reduce(range(1, 3), function (a, b) + return (a or 0) + b + end) == 6 + end) + end) + desc('range', function () + it('should not crash.', function () + range() + return true + end) + it('should return an array of contiguous numbers', function () + return eq(range(1, 3), {1, 2, 3}) + , eq(range(5, 10), {5, 6, 7, 8, 9, 10}) + , eq(range(0, 3), {0, 1, 2, 3}) + end) + it('should accept different step params', function () + return eq(range(0, 4, 2), {0, 2, 4}) + end) + it('should accept different start params', function () + return eq(range(0, 3), {0, 1, 2, 3}) + , eq(range(-1, 1), {-1, 0, 1}) + end) + end) + desc('msb', function () + it('should not crash', function () + msb() + return true + end) + it('should get most significant bit',function () + return eq(map(range(0, 8), msb), {0, 1, 2, 2, 3, 3, 3, 3, 4}) + , eq(map({16, 32, 64, 128, 256, 512}, msb), {5, 6, 7, 8, 9, 10}) + , (0b1000000000 == 512 and msb(512) == 10) + end) + end) +end) diff --git a/someproject.p8 b/someproject.p8 new file mode 100644 index 0000000..cf909f7 --- /dev/null +++ b/someproject.p8 @@ -0,0 +1,6 @@ +pico-8 cartridge // http://www.pico-8.com +version 38 +__lua__ +cls() +#include testrunner.lua +#include someappcode.lua diff --git a/testrunner.lua b/testrunner.lua new file mode 100644 index 0000000..d67a5e3 --- /dev/null +++ b/testrunner.lua @@ -0,0 +1,34 @@ +-- rerun the tests every x seconds: +_update = function () + if t() >= 10 then + run() + end +end + +-- all-in-one drop-in test framework: +test = function (title,f) + local desc=function(msg,f) + printh('✽:desc:'..msg) + f() + end + local it=function(msg,f) + printh('✽:it:'..msg) + local xs=f and {f()} or {} + if #xs>0 then + for i=1,#xs do + if xs[i]==true then + printh('✽:assert:true') + else + printh('✽:assert:false') + end + end + else + printh('✽:pend:pend') + end + printh('✽:it_end') + end + printh('✽:test:'..title) + f(desc,it) + printh('✽:test_end') +end +