love2d-community / love-api

The whole LÖVE wiki in a Lua table.
http://love2d-community.github.io/love-api/
300 stars 48 forks source link

Better Specs #20

Closed rm-code closed 8 years ago

rm-code commented 8 years ago

With busted and travis set up it makes sense to add some more fine-grained tests to this repo. This should include checking if values have the correct type, if arguments and return variables are formatted correctly etc.

Santos sent me this on the love forums, but I didn't have time to port it to busted yet:

local api = require( 'love_api' )

local function check(t, ok, info)
    for ok_i, ok_v in ipairs(ok) do
        if (ok_v.optional and t[ok_v.name] ~= nil) or (not ok_v.optional) then
            if not (type(t[ok_v.name]) == ok_v.type) then
            print()
            print('Trying to find: '..info.. ' > '..ok_v.name)
            if type(t) == 'table' then
               print()
               print('Table contains:')
               for k, v in pairs(t) do
                  print(k, v)
               end
               print()
            else
               error('Is not table')
            end
            print('Found: '..tostring(t[ok_v.name]))
            print('Should be type: '..ok_v.type)
            print('Is type: '..type(t[ok_v.name]))
            print('Optional: '..tostring(ok_v.optional))
            error('')
         end
        end
    end

    for k, v in pairs(t) do
        local contains = false
        for ok_i, ok_v in ipairs(ok) do
            if k == ok_v.name then
                contains = true
            end
        end
      if not (contains == true) then
         print('Found extra key: '..info..' > '..k)
      end
    end
end

local function check_functions(functions, info)
    if not functions then
        return
    end

    for _, f in ipairs(functions) do
        check(f, {
            {name = 'name', type = 'string'},
            {name = 'description', type = 'string'},
            {name = 'variants', type = 'table'},
        }, info)

        for _, variant in ipairs(f.variants) do
            check(variant, {
                {name = 'returns', type = 'table', optional = true},
                {name = 'arguments', type = 'table', optional = true},
                {name = 'description', type = 'string', optional = true},
            }, info .. ' > variants')

            local function check_returns_or_arguments(a, info)
                if a then
                    for _, r in pairs(a) do
                        check(r, {
                            {name = 'type', type = 'string'},
                            {name = 'name', type = 'string'},
                            {name = 'default', type = 'string', optional = true},
                            {name = 'description', type = 'string'},
                            {name = 'table', type = 'table', optional = true},
                        }, info)

                        if r.table then
                            for _, v in pairs(r.table) do
                                check(v, {
                                    {name = 'type', type = 'string'},
                                    {name = 'name', type = 'string'},
                                    {name = 'default', type = 'string', optional = true},
                                    {name = 'description', type = 'string'},
                                }, info .. ' > table')
                            end
                        end
                    end
                end
            end

            check_returns_or_arguments(variant.returns, info .. ' > '..f.name..' > variants > returns')
            check_returns_or_arguments(variant.arguments, info .. ' > '..f.name..' > variants > returns')
        end
    end
end

local function check_types(types, info)
    if not types then
        return
    end

    for _, t in ipairs(types) do
      check(t, {
         {name = 'name', type = 'string'},
         {name = 'description', type = 'string'},
         {name = 'functions', type = 'table', optional = true},
         {name = 'supertypes', type = 'table', optional = true},
         {name = 'constructors', type = 'table', optional = true},
      }, info)

        check_functions(t.functions, info ..' > '..t.name..' > functions')
    end
end

local function check_enums(enums, info)
    if not enums then
        return
    end

    for _, enum in ipairs(enums) do
        check(enum, {
            {name = 'name', type = 'string'},
            {name = 'description', type = 'string', optional = true},
            {name = 'constants', type = 'table'},
        }, info)

        for _, constant in ipairs(enum.constants) do
            check(constant, {
                {name = 'name', type = 'string'},
                {name = 'description', type = 'string'},
            {name = 'notes', type = 'string', optional = true},
            }, info..' > '..enum.name..' > constants')
        end
    end
end

check(api, {
    {name = 'functions', type = 'table'},
    {name = 'modules', type = 'table'},
    {name = 'types', type = 'table'},
    {name = 'callbacks', type = 'table'},
    {name = 'config', type = 'table'},
}, 'love')

check_functions(api.functions, 'love > functions')
check_functions(api.callbacks, 'love > callbacks')
check_types(api.types, 'love > types')

for _, m in ipairs(api.modules) do
    check(m, {
        {name = 'name', type = 'string'},
        {name = 'description', type = 'string'},
        {name = 'types', type = 'table', optional = true},
        {name = 'functions', type = 'table', optional = true},
        {name = 'enums', type = 'table', optional = true},
    }, 'love > modules')

    check_functions(m.functions, 'love > modules > '..m.name..' > functions')
    check_types(m.types, 'love > modules > '..m.name..' > types')
    check_enums(m.enums, 'love > modules > '..m.name..' > enums')
end
rm-code commented 8 years ago

Added some tests:

Helped to sort out two issues already.

More fine grained tests are still needed.