~rootmos/lua-hack

cb42ad5c14a9ce2546c68ac44dd61a36aaa9b10f — Gustav Behm 2 months ago 5247b67 + 9a1c4e0 master
Merge branch 'duration'
4 files changed, 133 insertions(+), 0 deletions(-)

M .build.yml
M README.md
A duration.lua
A duration.test.lua
M .build.yml => .build.yml +4 -0
@@ 18,3 18,7 @@ tasks:
  - tests32: |
      cd lua-hack
      ./test -b32
triggers:
  - action: email
    condition: always
    to: builds@rootmos.io

M README.md => README.md +1 -0
@@ 8,6 8,7 @@ A set of Lua modules guaranteed to be public domain.
- [bits](bits.lua): utility module to determine the current Lua interpreter's integer bitwidth
- [char](char.lua): ASCII character utilities (e.g. `is_printable`)
- [deep](deep/init.lua): deep equality and copy operations
- [duration](duration.lua): Parse and render human-readable durations
- [execute](execute.lua): extend os.execute and io.popen to safely quote arguments, set environment variables and change directory
- [hex](hex.lua): [hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal#Base16_(transfer_encoding)) binary encoding
- [lamport-merkle](lamport-merkle/init.lua): implementation of the combined [Lamport-Merkle](https://en.wikipedia.org/wiki/Merkle_signature_scheme) signature scheme

A duration.lua => duration.lua +64 -0
@@ 0,0 1,64 @@
local M = {}

function M.parse(str)
    if str == "" then
        return 0
    end

    local sec = nil
    for q, u in string.gmatch(str, "(%d+)([dhms])") do
        if sec == nil then
            sec = 0
        end

        if u == "d" then
            sec = sec + tonumber(q) * 86400
        elseif u == "h" then
            sec = sec + tonumber(q) * 3600
        elseif u == "m" then
            sec = sec + tonumber(q) * 60
        elseif u == "s" then
            sec = sec + tonumber(q)
        end
    end

    return sec
end

function M.render(sec)
    local str = ""

    local s, f = math.modf(sec)

    if s >= 86400 then
        local d = s // 86400
        str = str .. string.format("%dd", d)
        s = s - d * 86400
    end

    if s >= 3600 then
        local h = s // 3600
        str = str .. string.format("%dh", h)
        s = s - h * 3600
    end

    if s >= 60 then
        local m = s // 60
        str = str .. string.format("%dm", m)
        s = s - m * 60
    end

    local ms = math.floor(f*1e3+0.5)

    if s > 0 or ms > 0 then
        if ms == 0 then
            str = str .. string.format("%ds", s)
        else
            str = str .. string.format("%.3fs", s + 0.001*ms)
        end
    end

    return str
end

return M

A duration.test.lua => duration.test.lua +64 -0
@@ 0,0 1,64 @@
local lu = require("luaunit")
local D = require("duration")

function test_parse_1()
    lu.assertEquals(D.parse("1s"), 1)
    lu.assertEquals(D.parse("1m"), 60)
    lu.assertEquals(D.parse("1h"), 60*60)
    lu.assertEquals(D.parse("1d"), 24*60*60)
end

function test_parse_2()
    lu.assertEquals(D.parse("1s2s"), 3)
    lu.assertEquals(D.parse("1m2s"), 60+2)
    lu.assertEquals(D.parse("1h2s"), 60*60+2)
    lu.assertEquals(D.parse("1d2m"), 24*60*60+2*60)
end

function test_render_1()
    lu.assertEquals("1s", D.render(1))
    lu.assertEquals("1m", D.render(60))
    lu.assertEquals("1h", D.render(60*60))
    lu.assertEquals("1d", D.render(24*60*60))
end

function test_render_2()
    lu.assertEquals("3s", D.render(3))
    lu.assertEquals("1m2s", D.render(60+2))
    lu.assertEquals("1h2s", D.render(60*60+2))
    lu.assertEquals("1d2m", D.render(24*60*60+2*60))
end

function test_parse_0()
    lu.assertEquals(D.parse(""), 0)
    lu.assertEquals(D.parse("0s"), 0)
    lu.assertEquals(D.parse("0m"), 0)
    lu.assertEquals(D.parse("0h"), 0)
    lu.assertEquals(D.parse("0d"), 0)
end

function test_render_0()
    lu.assertEquals(D.render(0), "")
end

function test_render_parse_roundtrip()
    for i=1,1000 do
        local sec = math.random(0, 3*24*3600*10)
        lu.assertEquals(D.parse(D.render(sec)), sec)
    end

    for i=1,1000 do
        local sec = math.random(0, math.maxinteger)
        lu.assertEquals(D.parse(D.render(sec)), sec)
    end
end

function test_render_ms()
    lu.assertEquals(D.render(7.1), "7.100s")
    lu.assertEquals(D.render(7.01), "7.010s")
    lu.assertEquals(D.render(7.0012), "7.001s")
    lu.assertEquals(D.render(7.0009), "7.001s")
    lu.assertEquals(D.render(7.0001), "7s")
end

os.exit(lu.LuaUnit.run())