Browse Source

convert mispec tests to NTest and remove mispec (#3358)

* convert mispec tests to NTest and remove mispec

* fix luacheck
Gregor Hartmann 3 years ago
parent
commit
18d24364db

+ 0 - 159
lua_tests/mispec.lua

@@ -1,159 +0,0 @@
-local moduleName = ... or 'mispec'
-local M = {}
-_G[moduleName] = M
-
--- Helpers:
-function ok(expression, desc)
-    if expression == nil then expression = false end
-    desc = desc or 'expression is not ok'
-    if not expression then
-        error(desc .. '\n' .. debug.traceback())
-    end
-end
-
-function ko(expression, desc)
-    if expression == nil then expression = false end
-    desc = desc or 'expression is not ko'
-    if expression then
-        error(desc .. '\n' .. debug.traceback())
-    end
-end
-
-function eq(a, b)
-    if type(a) ~= type(b) then
-        error('type ' .. type(a) .. ' is not equal to ' .. type(b) .. '\n' .. debug.traceback())
-    end
-    if type(a) == 'function' then
-        return string.dump(a) == string.dump(b)
-    end
-    if a == b then return true end
-    if type(a) ~= 'table' then
-        error(string.format("%q",tostring(a)) .. ' is not equal to ' .. string.format("%q",tostring(b)) .. '\n' .. debug.traceback())
-    end
-    for k,v in pairs(a) do
-        if b[k] == nil or not eq(v, b[k]) then return false end
-    end
-    for k,v in pairs(b) do
-        if a[k] == nil or not eq(v, a[k]) then return false end
-    end
-    return true
-end
-
-function failwith(message, func, ...)
-    local status, err = pcall(func, ...)
-    if status then
-        local messagePart = ""
-        if message then
-            messagePart = " containing \"" .. message .. "\""
-        end
-        error("Error expected" .. messagePart .. '\n' .. debug.traceback())
-    end
-    if (message and not string.find(err, message)) then
-        error("expected errormessage \"" .. err .. "\" to contain \"" .. message .. "\"" .. '\n' .. debug.traceback() )
-    end
-    return true
-end
-
-function fail(func, ...)
-    return failwith(nil, func, ...)
-end
-
-local function eventuallyImpl(func, retries, delayMs)
-    local prevEventually = _G.eventually
-    _G.eventually = function() error("Cannot nest eventually/andThen.") end
-    local status, err = pcall(func)
-    _G.eventually = prevEventually
-    if status then
-        M.queuedEventuallyCount = M.queuedEventuallyCount - 1
-        M.runNextPending()
-    else
-        if retries > 0 then
-            local t = tmr.create()
-            t:register(delayMs, tmr.ALARM_SINGLE, M.runNextPending)
-            t:start()
-
-            table.insert(M.pending, 1, function() eventuallyImpl(func, retries - 1, delayMs) end)
-        else
-            M.failed = M.failed + 1
-            print("\n  ! it failed:", err)
-
-            -- remove all pending eventuallies as spec has failed at this point
-            for i = 1, M.queuedEventuallyCount - 1 do
-                table.remove(M.pending, 1)
-            end
-            M.queuedEventuallyCount = 0
-            M.runNextPending()
-        end
-    end
-end
-
-function eventually(func, retries, delayMs)
-    retries = retries or 10
-    delayMs = delayMs or 300
-
-    M.queuedEventuallyCount = M.queuedEventuallyCount + 1
-
-    table.insert(M.pending, M.queuedEventuallyCount, function()
-        eventuallyImpl(func, retries, delayMs)
-    end)
-end
-
-function andThen(func)
-    eventually(func, 0, 0)
-end
-
-function describe(name, itshoulds)
-    M.name = name
-    M.itshoulds = itshoulds
-end
-
--- Module:
-M.runNextPending = function()
-    local next = table.remove(M.pending, 1)
-    if next then
-        node.task.post(next)
-        next = nil
-    else
-        M.succeeded = M.total - M.failed
-        local elapsedSeconds = (tmr.now() - M.startTime) / 1000 / 1000
-        print(string.format(
-            '\n\nCompleted in %d seconds; %d failed out of %d.',
-            elapsedSeconds, M.failed, M.total))
-        M.pending = nil
-        M.queuedEventuallyCount = nil
-    end
-end
-
-M.run = function()
-    M.pending = {}
-    M.queuedEventuallyCount = 0
-    M.startTime = tmr.now()
-    M.total = 0
-    M.failed = 0
-    local it = {}
-    it.should = function(_, desc, func)
-        table.insert(M.pending, function()
-            print('\n  * ' .. desc)
-            M.total = M.total + 1
-            if M.pre then M.pre() end
-            local status, err = pcall(func)
-            if not status then
-                print("\n  ! it failed:", err)
-                M.failed = M.failed + 1
-            end
-            if M.post then M.post() end
-            M.runNextPending()
-        end)
-    end
-    it.initialize = function(_, pre) M.pre = pre end;
-    it.cleanup = function(_, post) M.post = post end;
-    M.itshoulds(it)
-
-    print('' .. M.name .. ', it should:')
-    M.runNextPending()
-
-    M.itshoulds = nil
-    M.name = nil
-end
-
-print ("loaded mispec")

+ 0 - 153
lua_tests/mispec_ws2812.lua

@@ -1,153 +0,0 @@
-require 'mispec'
-
-local buffer, buffer1, buffer2
-
-local function initBuffer(buffer, ...)
-  local i,v
-  for i,v in ipairs({...}) do
-    buffer:set(i, v, v*2, v*3, v*4)
-  end
-  return buffer
-end
-
-local function equalsBuffer(buffer1, buffer2)
-  return eq(buffer1:dump(), buffer2:dump())
-end
-
-
-describe('WS2812 buffers', function(it)
-
-    it:should('initialize a buffer', function()
-        buffer = ws2812.newBuffer(9, 3)
-        ko(buffer == nil)
-        ok(eq(buffer:size(), 9), "check size")
-        ok(eq(buffer:dump(), string.char(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)), "initialize with 0")
-
-        failwith("should be a positive integer", ws2812.newBuffer, 9, 0)
-        failwith("should be a positive integer", ws2812.newBuffer, 9, -1)
-        failwith("should be a positive integer", ws2812.newBuffer, 0, 3)
-        failwith("should be a positive integer", ws2812.newBuffer, -1, 3)
-    end)
-
-    it:should('have correct size', function()
-        buffer = ws2812.newBuffer(9, 3)
-        ok(eq(buffer:size(), 9), "check size")
-        buffer = ws2812.newBuffer(9, 22)
-        ok(eq(buffer:size(), 9), "check size")
-        buffer = ws2812.newBuffer(13, 1)
-        ok(eq(buffer:size(), 13), "check size")
-    end)
-
-    it:should('fill a buffer with one color', function()
-        buffer = ws2812.newBuffer(3, 3)
-        buffer:fill(1,222,55)
-        ok(eq(buffer:dump(), string.char(1,222,55,1,222,55,1,222,55)), "RGB")
-        buffer = ws2812.newBuffer(3, 4)
-        buffer:fill(1,222,55, 77)
-        ok(eq(buffer:dump(), string.char(1,222,55,77,1,222,55,77,1,222,55,77)), "RGBW")
-    end)
-
-    it:should('replace correctly', function()
-        buffer = ws2812.newBuffer(5, 3)
-        buffer:replace(string.char(3,255,165,33,0,244,12,87,255))
-        ok(eq(buffer:dump(), string.char(3,255,165,33,0,244,12,87,255,0,0,0,0,0,0)), "RGBW")
-
-        buffer = ws2812.newBuffer(5, 3)
-        buffer:replace(string.char(3,255,165,33,0,244,12,87,255), 2)
-        ok(eq(buffer:dump(), string.char(0,0,0,3,255,165,33,0,244,12,87,255,0,0,0)), "RGBW")
-
-        buffer = ws2812.newBuffer(5, 3)
-        buffer:replace(string.char(3,255,165,33,0,244,12,87,255), -5)
-        ok(eq(buffer:dump(), string.char(3,255,165,33,0,244,12,87,255,0,0,0,0,0,0)), "RGBW")
-
-        failwith("Does not fit into destination", function() buffer:replace(string.char(3,255,165,33,0,244,12,87,255), 4) end)
-    end)
-
-    it:should('replace correctly issue #2921', function()
-        local buffer = ws2812.newBuffer(5, 3)
-        buffer:replace(string.char(3,255,165,33,0,244,12,87,255), -7)
-        ok(eq(buffer:dump(), string.char(3,255,165,33,0,244,12,87,255,0,0,0,0,0,0)), "RGBW")
-    end)
-
-    it:should('get/set correctly', function()
-        buffer = ws2812.newBuffer(3, 4)
-        buffer:fill(1,222,55,13)
-        ok(eq({buffer:get(2)},{1,222,55,13}))
-        buffer:set(2, 4,53,99,0)
-        ok(eq({buffer:get(1)},{1,222,55,13}))
-        ok(eq({buffer:get(2)},{4,53,99,0}))
-        ok(eq(buffer:dump(), string.char(1,222,55,13,4,53,99,0,1,222,55,13)), "RGBW")
-
-        failwith("index out of range", function() buffer:get(0) end)
-        failwith("index out of range", function() buffer:get(4) end)
-        failwith("index out of range", function() buffer:set(0,1,2,3,4) end)
-        failwith("index out of range", function() buffer:set(4,1,2,3,4) end)
-        failwith("number expected, got no value", function() buffer:set(2,1,2,3) end)
---        failwith("extra values given", function() buffer:set(2,1,2,3,4,5) end)
-    end)
-
-    it:should('fade correctly', function()
-        buffer = ws2812.newBuffer(1, 3)
-        buffer:fill(1,222,55)
-        buffer:fade(2)
-        ok(buffer:dump() == string.char(0,111,27), "RGB")
-        buffer:fill(1,222,55)
-        buffer:fade(3, ws2812.FADE_OUT)
-        ok(buffer:dump() == string.char(0,222/3,55/3), "RGB")
-        buffer:fill(1,222,55)
-        buffer:fade(3, ws2812.FADE_IN)
-        ok(buffer:dump() == string.char(3,255,165), "RGB")
-        buffer = ws2812.newBuffer(1, 4)
-        buffer:fill(1,222,55, 77)
-        buffer:fade(2, ws2812.FADE_OUT)
-        ok(eq(buffer:dump(), string.char(0,111,27,38)), "RGBW")
-    end)
-
-    it:should('mix correctly issue #1736', function()
-        buffer1 = ws2812.newBuffer(1, 3) 
-        buffer2 = ws2812.newBuffer(1, 3)
-        buffer1:fill(10,22,54)
-        buffer2:fill(10,27,55)
-        buffer1:mix(256/8*7,buffer1,256/8,buffer2)
-        ok(eq({buffer1:get(1)}, {10,23,54}))
-    end)
-
-    it:should('mix saturation correctly ', function()
-        buffer1 = ws2812.newBuffer(1, 3) 
-        buffer2 = ws2812.newBuffer(1, 3) 
-
-        buffer1:fill(10,22,54)
-        buffer2:fill(10,27,55)
-        buffer1:mix(256/2,buffer1,-256,buffer2)
-        ok(eq({buffer1:get(1)}, {0,0,0}))
-
-        buffer1:fill(10,22,54)
-        buffer2:fill(10,27,55)
-        buffer1:mix(25600,buffer1,256/8,buffer2)
-        ok(eq({buffer1:get(1)}, {255,255,255}))
-
-        buffer1:fill(10,22,54)
-        buffer2:fill(10,27,55)
-        buffer1:mix(-257,buffer1,255,buffer2)
-        ok(eq({buffer1:get(1)}, {0,5,1}))
-    end)
-
-    it:should('mix with strings correctly ', function()
-        buffer1 = ws2812.newBuffer(1, 3) 
-        buffer2 = ws2812.newBuffer(1, 3) 
-
-        buffer1:fill(10,22,54)
-        buffer2:fill(10,27,55)
-        buffer1:mix(-257,buffer1:dump(),255,buffer2:dump())
-        ok(eq({buffer1:get(1)}, {0,5,1}))
-    end)
-    
-    it:should('power', function()
-        buffer = ws2812.newBuffer(2, 4)
-        buffer:fill(10,22,54,234)
-        ok(eq(buffer:power(), 2*(10+22+54+234)))
-    end)
-
-end)
-
-mispec.run()

+ 0 - 149
lua_tests/mispec_ws2812_2.lua

@@ -1,149 +0,0 @@
-require 'mispec'
-
-local buffer, buffer1, buffer2
-
-local function initBuffer(buffer, ...)
-  local i,v
-  for i,v in ipairs({...}) do
-    buffer:set(i, v, v*2, v*3, v*4)
-  end
-  return buffer
-end
-
-local function equalsBuffer(buffer1, buffer2)
-  return eq(buffer1:dump(), buffer2:dump())
-end
-
-
-describe('WS2812 buffers', function(it)
-
-    it:should('shift LOGICAL', function()
-
-        buffer1 = ws2812.newBuffer(4, 4)
-        buffer2 = ws2812.newBuffer(4, 4)
-
-        initBuffer(buffer1,7,8,9,12)
-        initBuffer(buffer2,0,0,7,8)
-        buffer1:shift(2)
-        ok(equalsBuffer(buffer1, buffer2), "shift right")
-        
-        initBuffer(buffer1,7,8,9,12)
-        initBuffer(buffer2,9,12,0,0)
-        buffer1:shift(-2)
-        ok(equalsBuffer(buffer1, buffer2), "shift left")
-        
-        initBuffer(buffer1,7,8,9,12)
-        initBuffer(buffer2,7,0,8,12)
-        buffer1:shift(1, nil, 2,3)
-        ok(equalsBuffer(buffer1, buffer2), "shift middle right")
-
-        initBuffer(buffer1,7,8,9,12)
-        initBuffer(buffer2,7,9,0,12)
-        buffer1:shift(-1, nil, 2,3)
-        ok(equalsBuffer(buffer1, buffer2), "shift middle left")
-
-        -- bounds checks, handle gracefully as string:sub does
-        initBuffer(buffer1,7,8,9,12)
-        initBuffer(buffer2,8,9,12,0)
-        buffer1:shift(-1, ws2812.SHIFT_LOGICAL, 0,5)
-        ok(equalsBuffer(buffer1, buffer2), "shift left out of bound")
-
-        initBuffer(buffer1,7,8,9,12)
-        initBuffer(buffer2,0,7,8,9)
-        buffer1:shift(1, ws2812.SHIFT_LOGICAL, 0,5)
-        ok(equalsBuffer(buffer1, buffer2), "shift right out of bound")
-
-    end)
-
-    it:should('shift LOGICAL issue #2946', function()
-        buffer1 = ws2812.newBuffer(4, 4)
-        buffer2 = ws2812.newBuffer(4, 4)
-        
-        initBuffer(buffer1,7,8,9,12)
-        initBuffer(buffer2,0,0,0,0)
-        buffer1:shift(4)
-        ok(equalsBuffer(buffer1, buffer2), "shift all right")
-
-        initBuffer(buffer1,7,8,9,12)
-        initBuffer(buffer2,0,0,0,0)
-        buffer1:shift(-4)
-        ok(equalsBuffer(buffer1, buffer2), "shift all left")
-
-        failwith("shifting more elements than buffer size", function() buffer1:shift(10) end)
-        failwith("shifting more elements than buffer size", function() buffer1:shift(-6) end)
-    end)
-
-    it:should('shift CIRCULAR', function()
-        buffer1 = ws2812.newBuffer(4, 4)
-        buffer2 = ws2812.newBuffer(4, 4)
-
-        initBuffer(buffer1,7,8,9,12)
-        initBuffer(buffer2,9,12,7,8)
-        buffer1:shift(2, ws2812.SHIFT_CIRCULAR)
-        ok(equalsBuffer(buffer1, buffer2), "shift right")
-        
-        initBuffer(buffer1,7,8,9,12)
-        initBuffer(buffer2,9,12,7,8)
-        buffer1:shift(-2, ws2812.SHIFT_CIRCULAR)
-        ok(equalsBuffer(buffer1, buffer2), "shift left")
-        
-        initBuffer(buffer1,7,8,9,12)
-        initBuffer(buffer2,7,9,8,12)
-        buffer1:shift(1, ws2812.SHIFT_CIRCULAR, 2,3)
-        ok(equalsBuffer(buffer1, buffer2), "shift middle right")
-
-        initBuffer(buffer1,7,8,9,12)
-        initBuffer(buffer2,7,9,8,12)
-        buffer1:shift(-1, ws2812.SHIFT_CIRCULAR, 2,3)
-        ok(equalsBuffer(buffer1, buffer2), "shift middle left")
-
-        -- bounds checks, handle gracefully as string:sub does
-        initBuffer(buffer1,7,8,9,12)
-        initBuffer(buffer2,8,9,12,7)
-        buffer1:shift(-1, ws2812.SHIFT_CIRCULAR, 0,5)
-        ok(equalsBuffer(buffer1, buffer2), "shift left out of bound")
-
-        initBuffer(buffer1,7,8,9,12)
-        initBuffer(buffer2,12,7,8,9)
-        buffer1:shift(1, ws2812.SHIFT_CIRCULAR, 0,5)
-        ok(equalsBuffer(buffer1, buffer2), "shift right out of bound")
-
-        initBuffer(buffer1,7,8,9,12)
-        initBuffer(buffer2,12,7,8,9)
-        buffer1:shift(1, ws2812.SHIFT_CIRCULAR, -12,12)
-        ok(equalsBuffer(buffer1, buffer2), "shift right way out of bound")
-
-    end)
-
-    it:should('sub', function()
-        buffer1 = ws2812.newBuffer(4, 4)
-        buffer2 = ws2812.newBuffer(4, 4)
-        initBuffer(buffer1,7,8,9,12)
-        buffer1 = buffer1:sub(4,3)
-        ok(eq(buffer1:size(), 0), "sub empty")
-
-        buffer1 = ws2812.newBuffer(4, 4)
-        buffer2 = ws2812.newBuffer(2, 4)
-        initBuffer(buffer1,7,8,9,12)
-        initBuffer(buffer2,9,12)
-        buffer1 = buffer1:sub(3,4)
-        ok(equalsBuffer(buffer1, buffer2), "sub")
-
-        buffer1 = ws2812.newBuffer(4, 4)
-        buffer2 = ws2812.newBuffer(4, 4)
-        initBuffer(buffer1,7,8,9,12)
-        initBuffer(buffer2,7,8,9,12)
-        buffer1 = buffer1:sub(-12,33)
-        ok(equalsBuffer(buffer1, buffer2), "out of bounds")
-    end)
-
-
-
-
---[[
-ws2812.buffer:__concat()
---]]
-
-end)
-
-mispec.run()

+ 0 - 31
lua_tests/mispec_ws2812_effects.lua

@@ -1,31 +0,0 @@
-require 'mispec'
-
-local buffer, buffer1, buffer2
-
-describe('WS2812_effects', function(it)
-
-    it:should('set_speed', function()
-        buffer = ws2812.newBuffer(9, 3)
-        ws2812_effects.init(buffer)
-
-        ws2812_effects.set_speed(0)
-        ws2812_effects.set_speed(255)
-
-        failwith("should be", ws2812_effects.set_speed, -1)
-        failwith("should be", ws2812_effects.set_speed, 256)
-    end)
-
-    it:should('set_brightness', function()
-        buffer = ws2812.newBuffer(9, 3)
-        ws2812_effects.init(buffer)
-
-        ws2812_effects.set_brightness(0)
-        ws2812_effects.set_brightness(255)
-
-        failwith("should be", ws2812_effects.set_brightness, -1)
-        failwith("should be", ws2812_effects.set_brightness, 256)
-    end)
-
-end)
-
-mispec.run()

+ 262 - 0
tests/NTest_ws2812.lua

@@ -0,0 +1,262 @@
+local N = ...
+N = (N or require "NTest")("ws2812 buffers")
+
+local buffer, buffer1, buffer2
+
+local function initBuffer(buf, ...)
+  for i,v in ipairs({...}) do
+    buf:set(i, v, v*2, v*3, v*4)
+  end
+  return buf
+end
+
+local function equalsBuffer(buf1, buf2)
+  return eq(buf1:dump(), buf2:dump())
+end
+
+
+N.test('initialize a buffer', function()
+  buffer = ws2812.newBuffer(9, 3)
+  nok(buffer == nil)
+  ok(eq(buffer:size(), 9), "check size")
+  ok(eq(buffer:dump(), string.char(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)), "initialize with 0")
+
+  fail(function() ws2812.newBuffer(9, 0) end, "should be a positive integer")
+  fail(function() ws2812.newBuffer(9, -1) end, "should be a positive integer")
+  fail(function() ws2812.newBuffer(0, 3) end, "should be a positive integer")
+  fail(function() ws2812.newBuffer(-1, 3) end, "should be a positive integer")
+end)
+
+N.test('have correct size', function()
+  buffer = ws2812.newBuffer(9, 3)
+  ok(eq(buffer:size(), 9), "check size")
+  buffer = ws2812.newBuffer(9, 22)
+  ok(eq(buffer:size(), 9), "check size")
+  buffer = ws2812.newBuffer(13, 1)
+  ok(eq(buffer:size(), 13), "check size")
+end)
+
+N.test('fill a buffer with one color', function()
+  buffer = ws2812.newBuffer(3, 3)
+  buffer:fill(1,222,55)
+  ok(eq(buffer:dump(), string.char(1,222,55,1,222,55,1,222,55)), "RGB")
+  buffer = ws2812.newBuffer(3, 4)
+  buffer:fill(1,222,55, 77)
+  ok(eq(buffer:dump(), string.char(1,222,55,77,1,222,55,77,1,222,55,77)), "RGBW")
+end)
+
+N.test('replace correctly', function()
+  buffer = ws2812.newBuffer(5, 3)
+  buffer:replace(string.char(3,255,165,33,0,244,12,87,255))
+  ok(eq(buffer:dump(), string.char(3,255,165,33,0,244,12,87,255,0,0,0,0,0,0)), "RGBW")
+
+  buffer = ws2812.newBuffer(5, 3)
+  buffer:replace(string.char(3,255,165,33,0,244,12,87,255), 2)
+  ok(eq(buffer:dump(), string.char(0,0,0,3,255,165,33,0,244,12,87,255,0,0,0)), "RGBW")
+
+  buffer = ws2812.newBuffer(5, 3)
+  buffer:replace(string.char(3,255,165,33,0,244,12,87,255), -5)
+  ok(eq(buffer:dump(), string.char(3,255,165,33,0,244,12,87,255,0,0,0,0,0,0)), "RGBW")
+
+  fail(function() buffer:replace(string.char(3,255,165,33,0,244,12,87,255), 4) end, "Does not fit into destination")
+end)
+
+N.test('replace correctly issue #2921', function()
+  buffer = ws2812.newBuffer(5, 3)
+  buffer:replace(string.char(3,255,165,33,0,244,12,87,255), -7)
+  ok(eq(buffer:dump(), string.char(3,255,165,33,0,244,12,87,255,0,0,0,0,0,0)), "RGBW")
+end)
+
+N.test('get/set correctly', function()
+  buffer = ws2812.newBuffer(3, 4)
+  buffer:fill(1,222,55,13)
+  ok(eq({buffer:get(2)},{1,222,55,13}))
+  buffer:set(2, 4,53,99,0)
+  ok(eq({buffer:get(1)},{1,222,55,13}))
+  ok(eq({buffer:get(2)},{4,53,99,0}))
+  ok(eq(buffer:dump(), string.char(1,222,55,13,4,53,99,0,1,222,55,13)), "RGBW")
+
+  fail(function() buffer:get(0) end, "index out of range")
+  fail(function() buffer:get(4) end, "index out of range")
+  fail(function() buffer:set(0,1,2,3,4) end, "index out of range")
+  fail(function() buffer:set(4,1,2,3,4) end, "index out of range")
+  fail(function() buffer:set(2,1,2,3) end, "number expected, got no value")
+--  fail(function() buffer:set(2,1,2,3,4,5) end, "extra values given")
+end)
+
+N.test('fade correctly', function()
+  buffer = ws2812.newBuffer(1, 3)
+  buffer:fill(1,222,55)
+  buffer:fade(2)
+  ok(buffer:dump() == string.char(0,111,27), "RGB")
+  buffer:fill(1,222,55)
+  buffer:fade(3, ws2812.FADE_OUT)
+  ok(buffer:dump() == string.char(0,222/3,55/3), "RGB")
+  buffer:fill(1,222,55)
+  buffer:fade(3, ws2812.FADE_IN)
+  ok(buffer:dump() == string.char(3,255,165), "RGB")
+  buffer = ws2812.newBuffer(1, 4)
+  buffer:fill(1,222,55, 77)
+  buffer:fade(2, ws2812.FADE_OUT)
+  ok(eq(buffer:dump(), string.char(0,111,27,38)), "RGBW")
+end)
+
+N.test('mix correctly issue #1736', function()
+  buffer1 = ws2812.newBuffer(1, 3)
+  buffer2 = ws2812.newBuffer(1, 3)
+  buffer1:fill(10,22,54)
+  buffer2:fill(10,27,55)
+  buffer1:mix(256/8*7,buffer1,256/8,buffer2)
+  ok(eq({buffer1:get(1)}, {10,23,54}))
+end)
+
+N.test('mix saturation correctly ', function()
+  buffer1 = ws2812.newBuffer(1, 3)
+  buffer2 = ws2812.newBuffer(1, 3)
+
+  buffer1:fill(10,22,54)
+  buffer2:fill(10,27,55)
+  buffer1:mix(256/2,buffer1,-256,buffer2)
+  ok(eq({buffer1:get(1)}, {0,0,0}))
+
+  buffer1:fill(10,22,54)
+  buffer2:fill(10,27,55)
+  buffer1:mix(25600,buffer1,256/8,buffer2)
+  ok(eq({buffer1:get(1)}, {255,255,255}))
+
+  buffer1:fill(10,22,54)
+  buffer2:fill(10,27,55)
+  buffer1:mix(-257,buffer1,255,buffer2)
+  ok(eq({buffer1:get(1)}, {0,5,1}))
+end)
+
+N.test('power', function()
+  buffer = ws2812.newBuffer(2, 4)
+  buffer:fill(10,22,54,234)
+  ok(eq(buffer:power(), 2*(10+22+54+234)))
+end)
+
+N.test('shift LOGICAL', function()
+
+  buffer1 = ws2812.newBuffer(4, 4)
+  buffer2 = ws2812.newBuffer(4, 4)
+
+  initBuffer(buffer1,7,8,9,12)
+  initBuffer(buffer2,0,0,7,8)
+  buffer1:shift(2)
+  ok(equalsBuffer(buffer1, buffer2), "shift right")
+
+  initBuffer(buffer1,7,8,9,12)
+  initBuffer(buffer2,9,12,0,0)
+  buffer1:shift(-2)
+  ok(equalsBuffer(buffer1, buffer2), "shift left")
+
+  initBuffer(buffer1,7,8,9,12)
+  initBuffer(buffer2,7,0,8,12)
+  buffer1:shift(1, nil, 2,3)
+  ok(equalsBuffer(buffer1, buffer2), "shift middle right")
+
+  initBuffer(buffer1,7,8,9,12)
+  initBuffer(buffer2,7,9,0,12)
+  buffer1:shift(-1, nil, 2,3)
+  ok(equalsBuffer(buffer1, buffer2), "shift middle left")
+
+  -- bounds checks, handle gracefully as string:sub does
+  initBuffer(buffer1,7,8,9,12)
+  initBuffer(buffer2,8,9,12,0)
+  buffer1:shift(-1, ws2812.SHIFT_LOGICAL, 0,5)
+  ok(equalsBuffer(buffer1, buffer2), "shift left out of bound")
+
+  initBuffer(buffer1,7,8,9,12)
+  initBuffer(buffer2,0,7,8,9)
+  buffer1:shift(1, ws2812.SHIFT_LOGICAL, 0,5)
+  ok(equalsBuffer(buffer1, buffer2), "shift right out of bound")
+
+end)
+
+N.test('shift LOGICAL issue #2946', function()
+  buffer1 = ws2812.newBuffer(4, 4)
+  buffer2 = ws2812.newBuffer(4, 4)
+
+  initBuffer(buffer1,7,8,9,12)
+  initBuffer(buffer2,0,0,0,0)
+  buffer1:shift(4)
+  ok(equalsBuffer(buffer1, buffer2), "shift all right")
+
+  initBuffer(buffer1,7,8,9,12)
+  initBuffer(buffer2,0,0,0,0)
+  buffer1:shift(-4)
+  ok(equalsBuffer(buffer1, buffer2), "shift all left")
+
+  fail(function() buffer1:shift(10) end, "shifting more elements than buffer size")
+  fail(function() buffer1:shift(-6) end, "shifting more elements than buffer size")
+end)
+
+N.test('shift CIRCULAR', function()
+  buffer1 = ws2812.newBuffer(4, 4)
+  buffer2 = ws2812.newBuffer(4, 4)
+
+  initBuffer(buffer1,7,8,9,12)
+  initBuffer(buffer2,9,12,7,8)
+  buffer1:shift(2, ws2812.SHIFT_CIRCULAR)
+  ok(equalsBuffer(buffer1, buffer2), "shift right")
+
+  initBuffer(buffer1,7,8,9,12)
+  initBuffer(buffer2,9,12,7,8)
+  buffer1:shift(-2, ws2812.SHIFT_CIRCULAR)
+  ok(equalsBuffer(buffer1, buffer2), "shift left")
+
+  initBuffer(buffer1,7,8,9,12)
+  initBuffer(buffer2,7,9,8,12)
+  buffer1:shift(1, ws2812.SHIFT_CIRCULAR, 2,3)
+  ok(equalsBuffer(buffer1, buffer2), "shift middle right")
+
+  initBuffer(buffer1,7,8,9,12)
+  initBuffer(buffer2,7,9,8,12)
+  buffer1:shift(-1, ws2812.SHIFT_CIRCULAR, 2,3)
+  ok(equalsBuffer(buffer1, buffer2), "shift middle left")
+
+  -- bounds checks, handle gracefully as string:sub does
+  initBuffer(buffer1,7,8,9,12)
+  initBuffer(buffer2,8,9,12,7)
+  buffer1:shift(-1, ws2812.SHIFT_CIRCULAR, 0,5)
+  ok(equalsBuffer(buffer1, buffer2), "shift left out of bound")
+
+  initBuffer(buffer1,7,8,9,12)
+  initBuffer(buffer2,12,7,8,9)
+  buffer1:shift(1, ws2812.SHIFT_CIRCULAR, 0,5)
+  ok(equalsBuffer(buffer1, buffer2), "shift right out of bound")
+
+  initBuffer(buffer1,7,8,9,12)
+  initBuffer(buffer2,12,7,8,9)
+  buffer1:shift(1, ws2812.SHIFT_CIRCULAR, -12,12)
+  ok(equalsBuffer(buffer1, buffer2), "shift right way out of bound")
+
+end)
+
+N.test('sub', function()
+  buffer1 = ws2812.newBuffer(4, 4)
+  buffer2 = ws2812.newBuffer(4, 4)
+  initBuffer(buffer1,7,8,9,12)
+  buffer1 = buffer1:sub(4,3)
+  ok(eq(buffer1:size(), 0), "sub empty")
+
+  buffer1 = ws2812.newBuffer(4, 4)
+  buffer2 = ws2812.newBuffer(2, 4)
+  initBuffer(buffer1,7,8,9,12)
+  initBuffer(buffer2,9,12)
+  buffer1 = buffer1:sub(3,4)
+  ok(equalsBuffer(buffer1, buffer2), "sub")
+
+  buffer1 = ws2812.newBuffer(4, 4)
+  buffer2 = ws2812.newBuffer(4, 4)
+  initBuffer(buffer1,7,8,9,12)
+  initBuffer(buffer2,7,8,9,12)
+  buffer1 = buffer1:sub(-12,33)
+  ok(equalsBuffer(buffer1, buffer2), "out of bounds")
+end)
+
+
+--[[
+ws2812.buffer:__concat()
+--]]

+ 27 - 0
tests/NTest_ws2812_effects.lua

@@ -0,0 +1,27 @@
+local N = ...
+N = (N or require "NTest")("ws2812_effects")
+
+local buffer
+
+
+N.test('set_speed', function()
+  buffer = ws2812.newBuffer(9, 3)
+  ws2812_effects.init(buffer)
+
+  ws2812_effects.set_speed(0)
+  ws2812_effects.set_speed(255)
+
+  fail(function() ws2812_effects.set_speed(-1) end, "should be")
+  fail(function() ws2812_effects.set_speed(256) end, "should be")
+end)
+
+N.test('set_brightness', function()
+  buffer = ws2812.newBuffer(9, 3)
+  ws2812_effects.init(buffer)
+
+  ws2812_effects.set_brightness(0)
+  ws2812_effects.set_brightness(255)
+
+  fail(function() ws2812_effects.set_brightness(-1) end, "should be")
+  fail(function() ws2812_effects.set_brightness(256) end, "should be")
+end)