From 9048deeb9537e6fec647227c07cab4411ba9a9d3 Mon Sep 17 00:00:00 2001 From: hydraz Date: Thu, 30 May 2019 15:36:28 -0300 Subject: [PATCH] Add a function for type-checking arguments (#207) - Define an expect(index, actual_value, types...) helper function which takes an argument index, value and list of permissable types and ensures the value is of one of those types. If not, it will produce an error message with the expected and actual type, as well as the argument number and (if available) the function name. - Expose expect in the global scope as _G["~expect"], hopefully making it clear it is internal. - Replace most manual type checks with this helper method. - Write tests to ensure this argument validation works as expected Also fix a couple of bugs exposed by this refactor and the subsequent tests: - Make rednet checks a little more strict - rednet.close(false) is no longer valid. - Error when attempting to redirect the terminal to itself (term.redirect(term)). --- .../assets/computercraft/lua/bios.lua | 204 ++++++++---------- .../computercraft/lua/rom/apis/colors.lua | 38 +--- .../assets/computercraft/lua/rom/apis/gps.lua | 10 +- .../computercraft/lua/rom/apis/help.lua | 15 +- .../assets/computercraft/lua/rom/apis/io.lua | 17 +- .../computercraft/lua/rom/apis/keys.lua | 7 +- .../computercraft/lua/rom/apis/paintutils.lua | 53 +++-- .../computercraft/lua/rom/apis/peripheral.lua | 34 +-- .../computercraft/lua/rom/apis/rednet.lua | 55 ++--- .../computercraft/lua/rom/apis/settings.lua | 26 +-- .../computercraft/lua/rom/apis/term.lua | 7 +- .../computercraft/lua/rom/apis/textutils.lua | 41 +--- .../computercraft/lua/rom/apis/window.lua | 61 +++--- .../lua/rom/programs/advanced/multishell.lua | 25 +-- .../computercraft/lua/rom/programs/shell.lua | 53 ++--- .../core/computer/ComputerBootstrap.java | 6 +- src/test/resources/test-rom/mcfly.lua | 94 ++++++-- .../test-rom/spec/apis/colors_spec.lua | 48 ++++- .../resources/test-rom/spec/apis/fs_spec.lua | 14 ++ .../resources/test-rom/spec/apis/gps_spec.lua | 15 ++ .../test-rom/spec/apis/help_spec.lua | 22 ++ .../resources/test-rom/spec/apis/io_spec.lua | 23 +- .../test-rom/spec/apis/keys_spec.lua | 8 + .../resources/test-rom/spec/apis/os_spec.lua | 14 +- .../test-rom/spec/apis/paintutils_spec.lua | 60 ++++++ .../test-rom/spec/apis/peripheral_spec.lua | 47 ++++ .../test-rom/spec/apis/rednet_spec.lua | 78 +++++++ .../test-rom/spec/apis/settings_spec.lua | 43 ++++ .../test-rom/spec/apis/term_spec.lua | 12 ++ .../test-rom/spec/apis/textutils_spec.lua | 57 +++++ .../test-rom/spec/apis/window_spec.lua | 123 +++++++++++ .../resources/test-rom/spec/base_spec.lua | 81 ++++++- .../programs/advanced/multishell_spec.lua | 30 +++ .../test-rom/spec/programs/shell_spec.lua | 77 +++++++ 34 files changed, 1070 insertions(+), 428 deletions(-) create mode 100644 src/test/resources/test-rom/spec/apis/fs_spec.lua create mode 100644 src/test/resources/test-rom/spec/apis/gps_spec.lua create mode 100644 src/test/resources/test-rom/spec/apis/help_spec.lua create mode 100644 src/test/resources/test-rom/spec/apis/keys_spec.lua create mode 100644 src/test/resources/test-rom/spec/apis/paintutils_spec.lua create mode 100644 src/test/resources/test-rom/spec/apis/peripheral_spec.lua create mode 100644 src/test/resources/test-rom/spec/apis/rednet_spec.lua create mode 100644 src/test/resources/test-rom/spec/apis/settings_spec.lua create mode 100644 src/test/resources/test-rom/spec/apis/term_spec.lua create mode 100644 src/test/resources/test-rom/spec/apis/textutils_spec.lua create mode 100644 src/test/resources/test-rom/spec/apis/window_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/advanced/multishell_spec.lua diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index 84da535d6..5f24d94cb 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -1,5 +1,48 @@ +local native_select, native_type = select, type + +--- Expect an argument to have a specific type. +-- +-- @tparam int index The 1-based argument index. +-- @param value The argument's value. +-- @tparam string ... The allowed types of the argument. +-- @throws If the value is not one of the allowed types. +local function expect(index, value, ...) + local t = native_type(value) + for i = 1, native_select("#", ...) do + if t == native_select(i, ...) then return true end + end + + local types = table.pack(...) + for i = types.n, 1, -1 do + if types[i] == "nil" then table.remove(types, i) end + end + + local type_names + if #types <= 1 then + type_names = tostring(...) + else + type_names = table.concat(types, ", ", 1, #types - 1) .. " or " .. types[#types] + end + + -- If we can determine the function name with a high level of confidence, try to include it. + local name + if native_type(debug) == "table" and native_type(debug.getinfo) == "function" then + local ok, info = pcall(debug.getinfo, 3, "nS") + if ok and info.name and #info.name ~= "" and info.what ~= "C" then name = info.name end + end + + if name then + error( ("bad argument #%d to '%s' (expected %s, got %s)"):format(index, name, type_names, t), 3 ) + else + error( ("bad argument #%d (expected %s, got %s)"):format(index, type_names, t), 3 ) + end +end + +-- We expose expect in the global table as APIs need to access it, but give it +-- a non-identifier name - meaning it does not show up in auto-completion. +-- expect is an internal function, and should not be used by users. +_G["~expect"] = expect -local nativegetfenv = getfenv if _VERSION == "Lua 5.1" then -- If we're on Lua 5.1, install parts of the Lua 5.2/5.3 API so that programs can be written against it local type = type @@ -20,18 +63,11 @@ if _VERSION == "Lua 5.1" then end function load( x, name, mode, env ) - if type( x ) ~= "string" and type( x ) ~= "function" then - error( "bad argument #1 (expected string or function, got " .. type( x ) .. ")", 2 ) - end - if name ~= nil and type( name ) ~= "string" then - error( "bad argument #2 (expected string, got " .. type( name ) .. ")", 2 ) - end - if mode ~= nil and type( mode ) ~= "string" then - error( "bad argument #3 (expected string, got " .. type( mode ) .. ")", 2 ) - end - if env ~= nil and type( env) ~= "table" then - error( "bad argument #4 (expected table, got " .. type( env ) .. ")", 2 ) - end + expect(1, x, "function", "string") + expect(2, name, "string", "nil") + expect(3, mode, "string", "nil") + expect(4, env, "table", "nil") + local ok, p1, p2 = pcall( function() if type(x) == "string" then local result, err = nativeloadstring( x, name ) @@ -76,10 +112,9 @@ if _VERSION == "Lua 5.1" then math.log10 = nil table.maxn = nil else - loadstring = function(string, chunkname) return nativeloadstring(string, prefix( chunkname )) + loadstring = function(string, chunkname) return nativeloadstring(string, prefix( chunkname )) end -- Inject a stub for the old bit library - end _G.bit = { bnot = bit32.bnot, band = bit32.band, @@ -175,9 +210,7 @@ end -- Install globals function sleep( nTime ) - if nTime ~= nil and type( nTime ) ~= "number" then - error( "bad argument #1 (expected number, got " .. type( nTime ) .. ")", 2 ) - end + expect(1, nTime, "number", "nil") local timer = os.startTimer( nTime or 0 ) repeat local sEvent, param = os.pullEvent( "timer" ) @@ -185,9 +218,7 @@ function sleep( nTime ) end function write( sText ) - if type( sText ) ~= "string" and type( sText ) ~= "number" then - error( "bad argument #1 (expected string or number, got " .. type( sText ) .. ")", 2 ) - end + expect(1, sText, "string", "number") local w,h = term.getSize() local x,y = term.getCursorPos() @@ -275,18 +306,11 @@ function printError( ... ) end function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) - if _sReplaceChar ~= nil and type( _sReplaceChar ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _sReplaceChar ) .. ")", 2 ) - end - if _tHistory ~= nil and type( _tHistory ) ~= "table" then - error( "bad argument #2 (expected table, got " .. type( _tHistory ) .. ")", 2 ) - end - if _fnComplete ~= nil and type( _fnComplete ) ~= "function" then - error( "bad argument #3 (expected function, got " .. type( _fnComplete ) .. ")", 2 ) - end - if _sDefault ~= nil and type( _sDefault ) ~= "string" then - error( "bad argument #4 (expected string, got " .. type( _sDefault ) .. ")", 2 ) - end + expect(1, _sReplaceChar, "string", "nil") + expect(2, _tHistory, "table", "nil") + expect(3, _fnComplete, "function", "nil") + expect(4, _sDefault, "string", "nil") + term.setCursorBlink( true ) local sLine @@ -544,13 +568,10 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) return sLine end -loadfile = function( _sFile, _tEnv ) - if type( _sFile ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _sFile ) .. ")", 2 ) - end - if _tEnv ~= nil and type( _tEnv ) ~= "table" then - error( "bad argument #2 (expected table, got " .. type( _tEnv ) .. ")", 2 ) - end +function loadfile( _sFile, _tEnv ) + expect(1, _sFile, "string") + expect(2, _tEnv, "table", "nil") + local file = fs.open( _sFile, "r" ) if file then local func, err = load( file.readAll(), "@" .. fs.getName( _sFile ), "t", _tEnv ) @@ -560,10 +581,9 @@ loadfile = function( _sFile, _tEnv ) return nil, "File not found" end -dofile = function( _sFile ) - if type( _sFile ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _sFile ) .. ")", 2 ) - end +function dofile( _sFile ) + expect(1, _sFile, "string") + local fnFile, e = loadfile( _sFile, _G ) if fnFile then return fnFile() @@ -574,12 +594,9 @@ end -- Install the rest of the OS api function os.run( _tEnv, _sPath, ... ) - if type( _tEnv ) ~= "table" then - error( "bad argument #1 (expected table, got " .. type( _tEnv ) .. ")", 2 ) - end - if type( _sPath ) ~= "string" then - error( "bad argument #2 (expected string, got " .. type( _sPath ) .. ")", 2 ) - end + expect(1, _tEnv, "table") + expect(2, _sPath, "string") + local tArgs = table.pack( ... ) local tEnv = _tEnv setmetatable( tEnv, { __index = _G } ) @@ -604,9 +621,7 @@ end local tAPIsLoading = {} function os.loadAPI( _sPath ) - if type( _sPath ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _sPath ) .. ")", 2 ) - end + expect(1, _sPath, "string") local sName = fs.getName( _sPath ) if sName:sub(-4) == ".lua" then sName = sName:sub(1,-5) @@ -644,9 +659,7 @@ function os.loadAPI( _sPath ) end function os.unloadAPI( _sName ) - if type( _sName ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _sName ) .. ")", 2 ) - end + expect(1, _sName, "string") if _sName ~= "_G" and type(_G[_sName]) == "table" then _G[_sName] = nil end @@ -692,9 +705,11 @@ if http then local function checkOptions( options, body ) checkKey( options, "url", "string") - if body == false - then checkKey( options, "body", "nil" ) - else checkKey( options, "body", "string", not body ) end + if body == false then + checkKey( options, "body", "nil" ) + else + checkKey( options, "body", "string", not body ) + end checkKey( options, "headers", "table", true ) checkKey( options, "method", "string", true ) checkKey( options, "redirect", "boolean", true ) @@ -725,15 +740,9 @@ if http then return wrapRequest( _url.url, _url ) end - if type( _url ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _url ) .. ")", 2 ) - end - if _headers ~= nil and type( _headers ) ~= "table" then - error( "bad argument #2 (expected table, got " .. type( _headers ) .. ")", 2 ) - end - if _binary ~= nil and type( _binary ) ~= "boolean" then - error( "bad argument #3 (expected boolean, got " .. type( _binary ) .. ")", 2 ) - end + expect(1, _url, "string") + expect(2, _headers, "table", "nil") + expect(3, _binary, "boolean", "nil") return wrapRequest( _url, _url, nil, _headers, _binary ) end @@ -743,18 +752,10 @@ if http then return wrapRequest( _url.url, _url ) end - if type( _url ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _url ) .. ")", 2 ) - end - if type( _post ) ~= "string" then - error( "bad argument #2 (expected string, got " .. type( _post ) .. ")", 2 ) - end - if _headers ~= nil and type( _headers ) ~= "table" then - error( "bad argument #3 (expected table, got " .. type( _headers ) .. ")", 2 ) - end - if _binary ~= nil and type( _binary ) ~= "boolean" then - error( "bad argument #4 (expected boolean, got " .. type( _binary ) .. ")", 2 ) - end + expect(1, _url, "string") + expect(2, _post, "string") + expect(3, _headers, "table", "nil") + expect(4, _binary, "boolean", "nil") return wrapRequest( _url, _url, _post, _headers, _binary ) end @@ -764,19 +765,10 @@ if http then checkOptions( _url ) url = _url.url else - if type( _url ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _url ) .. ")", 2 ) - end - if _post ~= nil and type( _post ) ~= "string" then - error( "bad argument #2 (expected string, got " .. type( _post ) .. ")", 2 ) - end - if _headers ~= nil and type( _headers ) ~= "table" then - error( "bad argument #3 (expected table, got " .. type( _headers ) .. ")", 2 ) - end - if _binary ~= nil and type( _binary ) ~= "boolean" then - error( "bad argument #4 (expected boolean, got " .. type( _binary ) .. ")", 2 ) - end - + expect(1, _url, "string") + expect(2, _post, "string", "nil") + expect(3, _headers, "table", "nil") + expect(4, _binary, "boolean", "nil") url = _url.url end @@ -802,12 +794,9 @@ if http then local nativeWebsocket = http.websocket http.websocketAsync = nativeWebsocket http.websocket = function( _url, _headers ) - if type( _url ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _url ) .. ")", 2 ) - end - if _headers ~= nil and type( _headers ) ~= "table" then - error( "bad argument #2 (expected table, got " .. type( _headers ) .. ")", 2 ) - end + expect(1, _url, "string") + expect(2, _headers, "table", "nil") + local ok, err = nativeWebsocket( _url, _headers ) if not ok then return ok, err end @@ -825,18 +814,11 @@ end -- Install the lua part of the FS api local tEmpty = {} function fs.complete( sPath, sLocation, bIncludeFiles, bIncludeDirs ) - if type( sPath ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sPath ) .. ")", 2 ) - end - if type( sLocation ) ~= "string" then - error( "bad argument #2 (expected string, got " .. type( sLocation ) .. ")", 2 ) - end - if bIncludeFiles ~= nil and type( bIncludeFiles ) ~= "boolean" then - error( "bad argument #3 (expected boolean, got " .. type( bIncludeFiles ) .. ")", 2 ) - end - if bIncludeDirs ~= nil and type( bIncludeDirs ) ~= "boolean" then - error( "bad argument #4 (expected boolean, got " .. type( bIncludeDirs ) .. ")", 2 ) - end + expect(1, sPath, "string") + expect(2, sLocation, "string") + expect(3, bIncludeFiles, "boolean", "nil") + expect(4, bIncludeDirs, "boolean", "nil") + bIncludeFiles = (bIncludeFiles ~= false) bIncludeDirs = (bIncludeDirs ~= false) local sDir = sLocation diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua b/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua index 32d056253..1d0056395 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua @@ -1,3 +1,5 @@ +local expect = _G["~expect"] + -- Colors white = 1 orange = 2 @@ -19,48 +21,32 @@ black = 32768 function combine( ... ) local r = 0 for n,c in ipairs( { ... } ) do - if type( c ) ~= "number" then - error( "bad argument #"..n.." (expected number, got " .. type( c ) .. ")", 2 ) - end + expect(n, c, "number") r = bit32.bor(r,c) end return r end function subtract( colors, ... ) - if type( colors ) ~= "number" then - error( "bad argument #1 (expected number, got " .. type( colors ) .. ")", 2 ) - end + expect(1, colors, "number") local r = colors for n,c in ipairs( { ... } ) do - if type( c ) ~= "number" then - error( "bad argument #"..tostring( n+1 ).." (expected number, got " .. type( c ) .. ")", 2 ) - end + expect(n + 1, c, "number") r = bit32.band(r, bit32.bnot(c)) end return r end function test( colors, color ) - if type( colors ) ~= "number" then - error( "bad argument #1 (expected number, got " .. type( colors ) .. ")", 2 ) - end - if type( color ) ~= "number" then - error( "bad argument #2 (expected number, got " .. type( color ) .. ")", 2 ) - end + expect(1, colors, "number") + expect(2, color, "number") return bit32.band(colors, color) == color end function packRGB( r, g, b ) - if type( r ) ~= "number" then - error( "bad argument #1 (expected number, got " .. type( r ) .. ")", 2 ) - end - if type( g ) ~= "number" then - error( "bad argument #2 (expected number, got " .. type( g ) .. ")", 2 ) - end - if type( b ) ~= "number" then - error( "bad argument #3 (expected number, got " .. type( b ) .. ")", 2 ) - end + expect(1, r, "number") + expect(2, g, "number") + expect(3, b, "number") return bit32.band( r * 255, 0xFF ) * 2^16 + bit32.band( g * 255, 0xFF ) * 2^8 + @@ -68,9 +54,7 @@ function packRGB( r, g, b ) end function unpackRGB( rgb ) - if type( rgb ) ~= "number" then - error( "bad argument #1 (expected number, got " .. type( rgb ) .. ")", 2 ) - end + expect(1, rgb, "number") return bit32.band( bit32.rshift( rgb, 16 ), 0xFF ) / 255, bit32.band( bit32.rshift( rgb, 8 ), 0xFF ) / 255, diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua b/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua index 9b4eb1765..d27ba1beb 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua @@ -1,3 +1,5 @@ +local expect = _G["~expect"] + CHANNEL_GPS = 65534 local function trilaterate( A, B, C ) @@ -55,12 +57,8 @@ local function narrow( p1, p2, fix ) end function locate( _nTimeout, _bDebug ) - if _nTimeout ~= nil and type( _nTimeout ) ~= "number" then - error( "bad argument #1 (expected number, got " .. type( _nTimeout ) .. ")", 2 ) - end - if _bDebug ~= nil and type( _bDebug ) ~= "boolean" then - error( "bad argument #2 (expected boolean, got " .. type( _bDebug) .. ")", 2 ) - end + expect(1, _nTimeout, "number", "nil") + expect(2, _bDebug, "boolean", "nil") -- Let command computers use their magic fourth-wall-breaking special abilities if commands then return commands.getBlockPosition() diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/help.lua b/src/main/resources/assets/computercraft/lua/rom/apis/help.lua index 9776b0c03..63ca4d1d6 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/help.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/help.lua @@ -1,3 +1,4 @@ +local expect = _G["~expect"] local sPath = "/rom/help" @@ -6,17 +7,13 @@ function path() end function setPath( _sPath ) - if type( _sPath ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _sPath ) .. ")", 2 ) - end + expect(1, _sPath, "string") sPath = _sPath end function lookup( _sTopic ) - if type( _sTopic ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _sTopic ) .. ")", 2 ) - end - -- Look on the path variable + expect(1, _sTopic, "string") + -- Look on the path variable for sPath in string.gmatch(sPath, "[^:]+") do sPath = fs.combine( sPath, _sTopic ) if fs.exists( sPath ) and not fs.isDir( sPath ) then @@ -63,9 +60,7 @@ function topics() end function completeTopic( sText ) - if type( sText ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sText ) .. ")", 2 ) - end + expect(1, sText, "string") local tTopics = topics() local tResults = {} for n=1,#tTopics do diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/io.lua b/src/main/resources/assets/computercraft/lua/rom/apis/io.lua index 8bf12e5b5..cd8a02acb 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/io.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/io.lua @@ -1,5 +1,6 @@ -- Definition for the IO API -local typeOf = _G.type + +local expect, typeOf = _G["~expect"], _G.type --- If we return nil then close the file, as we've reached the end. -- We use this weird wrapper function as we wish to preserve the varargs @@ -65,7 +66,7 @@ handleMetatable = { local handle = self._handle if not handle.read and not handle.readLine then return nil, "Not opened for reading" end - local n = select('#', ...) + local n = select("#", ...) local output = {} for i = 1, n do local arg = select(i, ...) @@ -184,9 +185,7 @@ function input(_arg) end function lines(_sFileName) - if _sFileName ~= nil and typeOf(_sFileName) ~= "string" then - error("bad argument #1 (expected string, got " .. typeOf(_sFileName) .. ")", 2) - end + expect(1, _sFileName, "string", "nil") if _sFileName then local ok, err = open(_sFileName, "rb") if not ok then error(err, 2) end @@ -201,12 +200,8 @@ function lines(_sFileName) end function open(_sPath, _sMode) - if typeOf(_sPath) ~= "string" then - error("bad argument #1 (expected string, got " .. typeOf(_sPath) .. ")", 2) - end - if _sMode ~= nil and typeOf(_sMode) ~= "string" then - error("bad argument #2 (expected string, got " .. typeOf(_sMode) .. ")", 2) - end + expect(1, _sPath, "string") + expect(2, _sMode, "string", "nil") local sMode = _sMode and _sMode:gsub("%+", "") or "rb" local file, err = fs.open(_sPath, sMode) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua b/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua index 87d428840..6a7e035d9 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua @@ -1,7 +1,8 @@ - -- Minecraft key code bindings -- See http://www.minecraftwiki.net/wiki/Key_codes for more info +local expect = _G["~expect"] + local tKeys = { nil, "one", "two", "three", "four", -- 1 "five", "six", "seven", "eight", "nine", -- 6 @@ -58,8 +59,6 @@ keys.scollLock = keys.scrollLock keys.cimcumflex = keys.circumflex function getName( _nKey ) - if type( _nKey ) ~= "number" then - error( "bad argument #1 (expected number, got " .. type( _nKey ) .. ")", 2 ) - end + expect(1, _nKey, "number") return tKeys[ _nKey ] end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua b/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua index 82db7003d..fe475a6fa 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua @@ -1,3 +1,4 @@ +local expect = _G["~expect"] local function drawPixelInternal( xPos, yPos ) term.setCursorPos( xPos, yPos ) @@ -18,9 +19,7 @@ local function parseLine( tImageArg, sLine ) end function parseImage( sRawData ) - if type( sRawData ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sRawData ) .. ")" ) - end + expect(1, sRawData, "string") local tImage = {} for sLine in ( sRawData .. "\n" ):gmatch( "(.-)\n" ) do -- read each line like original file handling did parseLine( tImage, sLine ) @@ -29,9 +28,7 @@ function parseImage( sRawData ) end function loadImage( sPath ) - if type( sPath ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sPath ) .. ")", 2 ) - end + expect(1, sPath, "string") if fs.exists( sPath ) then local file = io.open( sPath, "r" ) @@ -43,21 +40,21 @@ function loadImage( sPath ) end function drawPixel( xPos, yPos, nColour ) - if type( xPos ) ~= "number" then error( "bad argument #1 (expected number, got " .. type( xPos ) .. ")", 2 ) end - if type( yPos ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( yPos ) .. ")", 2 ) end - if nColour ~= nil and type( nColour ) ~= "number" then error( "bad argument #3 (expected number, got " .. type( nColour ) .. ")", 2 ) end + expect(1, xPos, "number") + expect(2, yPos, "number") + expect(3, nColour, "number", "nil") if nColour then term.setBackgroundColor( nColour ) end - drawPixelInternal( xPos, yPos ) + return drawPixelInternal( xPos, yPos ) end function drawLine( startX, startY, endX, endY, nColour ) - if type( startX ) ~= "number" then error( "bad argument #1 (expected number, got " .. type( startX ) .. ")", 2 ) end - if type( startY ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( startY ) .. ")", 2 ) end - if type( endX ) ~= "number" then error( "bad argument #3 (expected number, got " .. type( endX ) .. ")", 2 ) end - if type( endY ) ~= "number" then error( "bad argument #4 (expected number, got " .. type( endY ) .. ")", 2 ) end - if nColour ~= nil and type( nColour ) ~= "number" then error( "bad argument #5 (expected number, got " .. type( nColour ) .. ")", 2 ) end + expect(1, startX, "number") + expect(2, startY, "number") + expect(3, endX, "number") + expect(4, endY, "number") + expect(5, nColour, "number", "nil") startX = math.floor(startX) startY = math.floor(startY) @@ -114,11 +111,11 @@ function drawLine( startX, startY, endX, endY, nColour ) end function drawBox( startX, startY, endX, endY, nColour ) - if type( startX ) ~= "number" then error( "bad argument #1 (expected number, got " .. type( startX ) .. ")", 2 ) end - if type( startY ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( startY ) .. ")", 2 ) end - if type( endX ) ~= "number" then error( "bad argument #3 (expected number, got " .. type( endX ) .. ")", 2 ) end - if type( endY ) ~= "number" then error( "bad argument #4 (expected number, got " .. type( endY ) .. ")", 2 ) end - if nColour ~= nil and type( nColour ) ~= "number" then error( "bad argument #5 (expected number, got " .. type( nColour ) .. ")", 2 ) end + expect(1, startX, "number") + expect(2, startY, "number") + expect(3, endX, "number") + expect(4, endY, "number") + expect(5, nColour, "number", "nil") startX = math.floor(startX) startY = math.floor(startY) @@ -159,11 +156,11 @@ function drawBox( startX, startY, endX, endY, nColour ) end function drawFilledBox( startX, startY, endX, endY, nColour ) - if type( startX ) ~= "number" then error( "bad argument #1 (expected number, got " .. type( startX ) .. ")", 2 ) end - if type( startY ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( startY ) .. ")", 2 ) end - if type( endX ) ~= "number" then error( "bad argument #3 (expected number, got " .. type( endX ) .. ")", 2 ) end - if type( endY ) ~= "number" then error( "bad argument #4 (expected number, got " .. type( endY ) .. ")", 2 ) end - if nColour ~= nil and type( nColour ) ~= "number" then error( "bad argument #5 (expected number, got " .. type( nColour ) .. ")", 2 ) end + expect(1, startX, "number") + expect(2, startY, "number") + expect(3, endX, "number") + expect(4, endY, "number") + expect(5, nColour, "number", "nil") startX = math.floor(startX) startY = math.floor(startY) @@ -198,9 +195,9 @@ function drawFilledBox( startX, startY, endX, endY, nColour ) end function drawImage( tImage, xPos, yPos ) - if type( tImage ) ~= "table" then error( "bad argument #1 (expected table, got " .. type( tImage ) .. ")", 2 ) end - if type( xPos ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( xPos ) .. ")", 2 ) end - if type( yPos ) ~= "number" then error( "bad argument #3 (expected number, got " .. type( yPos ) .. ")", 2 ) end + expect(1, tImage, "table") + expect(2, xPos, "number") + expect(3, yPos, "number") for y=1,#tImage do local tLine = tImage[y] for x=1,#tLine do diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua b/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua index 661f5e0f3..c34a59eb8 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua @@ -1,3 +1,5 @@ +local expect = _G["~expect"] + local native = peripheral function getNames() @@ -17,9 +19,7 @@ function getNames() end function isPresent( _sSide ) - if type( _sSide ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _sSide ) .. ")", 2 ) - end + expect(1, _sSide, "string") if native.isPresent( _sSide ) then return true end @@ -34,9 +34,7 @@ function isPresent( _sSide ) end function getType( _sSide ) - if type( _sSide ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _sSide ) .. ")", 2 ) - end + expect(1, _sSide, "string") if native.isPresent( _sSide ) then return native.getType( _sSide ) end @@ -51,9 +49,7 @@ function getType( _sSide ) end function getMethods( _sSide ) - if type( _sSide ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _sSide ) .. ")", 2 ) - end + expect(1, _sSide, "string") if native.isPresent( _sSide ) then return native.getMethods( _sSide ) end @@ -68,12 +64,8 @@ function getMethods( _sSide ) end function call( _sSide, _sMethod, ... ) - if type( _sSide ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _sSide ) .. ")", 2 ) - end - if type( _sSide ) ~= "string" then - error( "bad argument #2 (expected string, got " .. type( _sMethod ) .. ")", 2 ) - end + expect(1, _sSide, "string") + expect(2, _sMethod, "string") if native.isPresent( _sSide ) then return native.call( _sSide, _sMethod, ... ) end @@ -88,9 +80,7 @@ function call( _sSide, _sMethod, ... ) end function wrap( _sSide ) - if type( _sSide ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _sSide ) .. ")", 2 ) - end + expect(1, _sSide, "string") if peripheral.isPresent( _sSide ) then local tMethods = peripheral.getMethods( _sSide ) local tResult = {} @@ -105,12 +95,8 @@ function wrap( _sSide ) end function find( sType, fnFilter ) - if type( sType ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sType ) .. ")", 2 ) - end - if fnFilter ~= nil and type( fnFilter ) ~= "function" then - error( "bad argument #2 (expected function, got " .. type( fnFilter ) .. ")", 2 ) - end + expect(1, sType, "string") + expect(2, fnFilter, "function", "nil") local tResults = {} for n,sName in ipairs( peripheral.getNames() ) do if peripheral.getType( sName ) == sType then diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua b/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua index 58a18cd2a..412ce4d0d 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua @@ -1,3 +1,4 @@ +local expect = _G["~expect"] CHANNEL_BROADCAST = 65535 CHANNEL_REPEAT = 65533 @@ -7,9 +8,7 @@ local tReceivedMessageTimeouts = {} local tHostnames = {} function open( sModem ) - if type( sModem ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sModem ) .. ")", 2 ) - end + expect(1, sModem, "string") if peripheral.getType( sModem ) ~= "modem" then error( "No such modem: "..sModem, 2 ) end @@ -18,11 +17,9 @@ function open( sModem ) end function close( sModem ) + expect(1, sModem, "string", "nil") if sModem then -- Close a specific modem - if type( sModem ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sModem ) .. ")", 2 ) - end if peripheral.getType( sModem ) ~= "modem" then error( "No such modem: "..sModem, 2 ) end @@ -39,11 +36,9 @@ function close( sModem ) end function isOpen( sModem ) + expect(1, sModem, "string", "nil") if sModem then -- Check if a specific modem is open - if type( sModem ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sModem ) .. ")", 2 ) - end if peripheral.getType( sModem ) == "modem" then return peripheral.call( sModem, "isOpen", os.getComputerID() ) and peripheral.call( sModem, "isOpen", CHANNEL_BROADCAST ) end @@ -59,12 +54,8 @@ function isOpen( sModem ) end function send( nRecipient, message, sProtocol ) - if type( nRecipient ) ~= "number" then - error( "bad argument #1 (expected number, got " .. type( nRecipient ) .. ")", 2 ) - end - if sProtocol ~= nil and type( sProtocol ) ~= "string" then - error( "bad argument #3 (expected string, got " .. type( sProtocol ) .. ")", 2 ) - end + expect(1, nRecipient, "number") + expect(3, sProtocol, "string", "nil") -- Generate a (probably) unique message ID -- We could do other things to guarantee uniqueness, but we really don't need to -- Store it to ensure we don't get our own messages back @@ -96,14 +87,12 @@ function send( nRecipient, message, sProtocol ) end end end - + return sent end function broadcast( message, sProtocol ) - if sProtocol ~= nil and type( sProtocol ) ~= "string" then - error( "bad argument #2 (expected string, got " .. type( sProtocol ) .. ")", 2 ) - end + expect(2, sProtocol, "string", "nil") send( CHANNEL_BROADCAST, message, sProtocol ) end @@ -112,12 +101,8 @@ function receive( sProtocolFilter, nTimeout ) if type(sProtocolFilter) == "number" and nTimeout == nil then sProtocolFilter, nTimeout = nil, sProtocolFilter end - if sProtocolFilter ~= nil and type( sProtocolFilter ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sProtocolFilter ) .. ")", 2 ) - end - if nTimeout ~= nil and type( nTimeout ) ~= "number" then - error( "bad argument #2 (expected number, got " .. type( nTimeout ) .. ")", 2 ) - end + expect(1, sProtocolFilter, "string", "nil") + expect(2, nTimeout, "number", "nil") -- Start the timer local timer = nil @@ -148,12 +133,8 @@ function receive( sProtocolFilter, nTimeout ) end function host( sProtocol, sHostname ) - if type( sProtocol ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sProtocol ) .. ")", 2 ) - end - if type( sHostname ) ~= "string" then - error( "bad argument #2 (expected string, got " .. type( sHostname ) .. ")", 2 ) - end + expect(1, sProtocol, "string") + expect(2, sHostname, "string") if sHostname == "localhost" then error( "Reserved hostname", 2 ) end @@ -166,19 +147,13 @@ function host( sProtocol, sHostname ) end function unhost( sProtocol ) - if type( sProtocol ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sProtocol ) .. ")", 2 ) - end + expect(1, sProtocol, "string") tHostnames[ sProtocol ] = nil end function lookup( sProtocol, sHostname ) - if type( sProtocol ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sProtocol ) .. ")", 2 ) - end - if sHostname ~= nil and type( sHostname ) ~= "string" then - error( "bad argument #2 (expected string, got " .. type( sHostname ) .. ")", 2 ) - end + expect(1, sProtocol, "string") + expect(2, sHostname, "string") -- Build list of host IDs local tResults = nil diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua index be8b5a156..3290a03d3 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua @@ -1,14 +1,12 @@ +local expect = _G["~expect"] local tSettings = {} function set( sName, value ) - if type( sName ) ~= "string" then error( "bad argument #1 (expected string, got " .. type( sName ) .. ")", 2 ) end + expect(1, sName, "string") + expect(2, value, "number", "string", "boolean", "table") - local sValueTy = type(value) - if sValueTy ~= "number" and sValueTy ~= "string" and sValueTy ~= "boolean" and sValueTy ~= "table" then - error( "bad argument #2 (expected value, got " .. sValueTy .. ")", 2 ) - end - if sValueTy == "table" then + if type(value) == "table" then -- Ensure value is serializeable value = textutils.unserialize( textutils.serialize(value) ) end @@ -29,9 +27,7 @@ function copy( value ) end function get( sName, default ) - if type(sName) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sName ) .. ")", 2 ) - end + expect(1, sName, "string") local result = tSettings[ sName ] if result ~= nil then return copy(result) @@ -41,9 +37,7 @@ function get( sName, default ) end function unset( sName ) - if type(sName) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sName ) .. ")", 2 ) - end + expect(1, sName, "string") tSettings[ sName ] = nil end @@ -61,9 +55,7 @@ function getNames() end function load( sPath ) - if type(sPath) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sPath ) .. ")", 2 ) - end + expect(1, sPath, "string") local file = fs.open( sPath, "r" ) if not file then return false @@ -88,9 +80,7 @@ function load( sPath ) end function save( sPath ) - if type(sPath) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sPath ) .. ")", 2 ) - end + expect(1, sPath, "string") local file = fs.open( sPath, "w" ) if not file then return false diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/term.lua b/src/main/resources/assets/computercraft/lua/rom/apis/term.lua index 0edaf623f..d93c3f367 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/term.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/term.lua @@ -1,3 +1,4 @@ +local expect = _G["~expect"] local native = (term.native and term.native()) or term local redirectTarget = native @@ -11,10 +12,8 @@ end local term = {} term.redirect = function( target ) - if type( target ) ~= "table" then - error( "bad argument #1 (expected table, got " .. type( target ) .. ")", 2 ) - end - if target == term then + expect(1, target, "table") + if target == term or target == _G.term then error( "term is not a recommended redirect target, try term.current() instead", 2 ) end for k,v in pairs( native ) do diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua index 7b0555b7d..fb5282e0f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua @@ -1,8 +1,7 @@ +local expect = _G["~expect"] function slowWrite( sText, nRate ) - if nRate ~= nil and type( nRate ) ~= "number" then - error( "bad argument #2 (expected number, got " .. type( nRate ) .. ")", 2 ) - end + expect(2, nRate, "number", "nil") nRate = nRate or 20 if nRate < 0 then error( "Rate must be positive", 2 ) @@ -28,12 +27,8 @@ function slowPrint( sText, nRate ) end function formatTime( nTime, bTwentyFourHour ) - if type( nTime ) ~= "number" then - error( "bad argument #1 (expected number, got " .. type( nTime ) .. ")", 2 ) - end - if bTwentyFourHour ~= nil and type( bTwentyFourHour ) ~= "boolean" then - error( "bad argument #2 (expected boolean, got " .. type( bTwentyFourHour ) .. ")", 2 ) - end + expect(1, nTime, "number") + expect(2, bTwentyFourHour, "boolean", "nil") local sTOD = nil if not bTwentyFourHour then if nTime >= 12 then @@ -77,9 +72,7 @@ local function makePagedScroll( _term, _nFreeLines ) end function pagedPrint( _sText, _nFreeLines ) - if _nFreeLines ~= nil and type( _nFreeLines ) ~= "number" then - error( "bad argument #2 (expected number, got " .. type( _nFreeLines ) .. ")", 2 ) - end + expect(2, _nFreeLines, "number", "nil") -- Setup a redirector local oldTerm = term.current() local newTerm = {} @@ -321,9 +314,7 @@ function serialize( t ) end function unserialize( s ) - if type( s ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( s ) .. ")", 2 ) - end + expect(1, s, "string") local func = load( "return "..s, "unserialize", "t", {} ) if func then local ok, result = pcall( func ) @@ -335,20 +326,14 @@ function unserialize( s ) end function serializeJSON( t, bNBTStyle ) - if type( t ) ~= "table" and type( t ) ~= "string" and type( t ) ~= "number" and type( t ) ~= "boolean" then - error( "bad argument #1 (expected table/string/number/boolean, got " .. type( t ) .. ")", 2 ) - end - if bNBTStyle ~= nil and type( bNBTStyle ) ~= "boolean" then - error( "bad argument #2 (expected boolean, got " .. type( bNBTStyle ) .. ")", 2 ) - end + expect(1, t, "table", "string", "number", "boolean") + expect(2, bNBTStyle, "boolean", "nil") local tTracking = {} return serializeJSONImpl( t, tTracking, bNBTStyle or false ) end function urlEncode( str ) - if type( str ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( str ) .. ")", 2 ) - end + expect(1, str, "string") if str then str = string.gsub(str, "\n", "\r\n") str = string.gsub(str, "([^A-Za-z0-9 %-%_%.])", function(c) @@ -370,12 +355,8 @@ end local tEmpty = {} function complete( sSearchText, tSearchTable ) - if type( sSearchText ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sSearchText ) .. ")", 2 ) - end - if tSearchTable ~= nil and type( tSearchTable ) ~= "table" then - error( "bad argument #2 (expected table, got " .. type( tSearchTable ) .. ")", 2 ) - end + expect(1, sSearchText, "string") + expect(2, tSearchTable, "table", "nil") if g_tLuaKeywords[sSearchText] then return tEmpty end local nStart = 1 diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua index d53ec711b..6d9ab38ec 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua @@ -1,3 +1,4 @@ +local expect = _G["~expect"] local tHex = { [ colors.white ] = "0", @@ -21,15 +22,14 @@ local tHex = { local type = type local string_rep = string.rep local string_sub = string.sub -local table_unpack = table.unpack function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) - if type( parent ) ~= "table" then error( "bad argument #1 (expected table, got " .. type( parent ) .. ")", 2 ) end - if type( nX ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( nX ) .. ")", 2 ) end - if type( nY ) ~= "number" then error( "bad argument #3 (expected number, got " .. type( nY ) .. ")", 2 ) end - if type( nWidth ) ~= "number" then error( "bad argument #4 (expected number, got " .. type( nWidth ) .. ")", 2 ) end - if type( nHeight ) ~= "number" then error( "bad argument #5 (expected number, got " .. type( nHeight ) .. ")", 2 ) end - if bStartVisible ~= nil and type( bStartVisible ) ~= "boolean" then error( "bad argument #6 (expected boolean, got " .. type( bStartVisible ) .. ")", 2 ) end + expect(1, parent, "table") + expect(2, nX, "number") + expect(3, nY, "number") + expect(4, nWidth, "number") + expect(5, nHeight, "number") + expect(6, bStartVisible, "boolean", "nil") if parent == term then error( "term is not a recommended window parent, try term.current() instead", 2 ) @@ -191,9 +191,9 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) end function window.blit( sText, sTextColor, sBackgroundColor ) - if type( sText ) ~= "string" then error( "bad argument #1 (expected string, got " .. type( sText ) .. ")", 2 ) end - if type( sTextColor ) ~= "string" then error( "bad argument #2 (expected string, got " .. type( sTextColor ) .. ")", 2 ) end - if type( sBackgroundColor ) ~= "string" then error( "bad argument #3 (expected string, got " .. type( sBackgroundColor ) .. ")", 2 ) end + if type(sText) ~= "string" then expect(1, sText, "string") end + if type(sTextColor) ~= "string" then expect(2, sTextColor, "string") end + if type(sBackgroundColor) ~= "string" then expect(3, sBackgroundColor, "string") end if #sTextColor ~= #sText or #sBackgroundColor ~= #sText then error( "Arguments must be the same length", 2 ) end @@ -241,8 +241,8 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) end function window.setCursorPos( x, y ) - if type( x ) ~= "number" then error( "bad argument #1 (expected number, got " .. type( x ) .. ")", 2 ) end - if type( y ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( y ) .. ")", 2 ) end + if type(x) ~= "number" then expect(1, x, "number") end + if type(y) ~= "number" then expect(2, y, "number") end nCursorX = math.floor( x ) nCursorY = math.floor( y ) if bVisible then @@ -251,7 +251,7 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) end function window.setCursorBlink( blink ) - if type( blink ) ~= "boolean" then error( "bad argument #1 (expected boolean, got " .. type( blink ) .. ")", 2 ) end + if type(blink) ~= "boolean" then expect(1, blink, "boolean") end bCursorBlink = blink if bVisible then updateCursorBlink() @@ -275,11 +275,11 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) end local function setTextColor( color ) - if type( color ) ~= "number" then - error( "bad argument #1 (expected number, got " .. type( color ) .. ")", 2 ) - elseif tHex[color] == nil then + if type(color) ~= "number" then expect(1, color, "number") end + if tHex[color] == nil then error( "Invalid color (got " .. color .. ")" , 2 ) end + nTextColor = color if bVisible then updateCursorColor() @@ -290,7 +290,7 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) window.setTextColour = setTextColor function window.setPaletteColour( colour, r, g, b ) - if type( colour ) ~= "number" then error( "bad argument #1 (expected number, got " .. type( colour ) .. ")", 2 ) end + if type(colour) ~= "number" then expect(1, colour, "number") end if tHex[colour] == nil then error( "Invalid color (got " .. colour .. ")" , 2 ) @@ -301,9 +301,9 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) tCol = { colours.unpackRGB( r ) } tPalette[ colour ] = tCol else - if type( r ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( r ) .. ")", 2 ) end - if type( g ) ~= "number" then error( "bad argument #3 (expected number, got " .. type( g ) .. ")", 2 ) end - if type( b ) ~= "number" then error( "bad argument #4 (expected number, got " .. type( b ) .. ")", 2 ) end + if type(r) ~= "number" then expect(2, r, "number") end + if type(g) ~= "number" then expect(3, g, "number") end + if type(b) ~= "number" then expect(4, b, "number") end tCol = tPalette[ colour ] tCol[1] = r @@ -319,7 +319,7 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) window.setPaletteColor = window.setPaletteColour function window.getPaletteColour( colour ) - if type( colour ) ~= "number" then error( "bad argument #1 (expected number, got " .. type( colour ) .. ")", 2 ) end + if type(colour) ~= "number" then expect(1, colour, "number") end if tHex[colour] == nil then error( "Invalid color (got " .. colour .. ")" , 2 ) end @@ -330,9 +330,8 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) window.getPaletteColor = window.getPaletteColour local function setBackgroundColor( color ) - if type( color ) ~= "number" then - error( "bad argument #1 (expected number, got " .. type( color ) .. ")", 2 ) - elseif tHex[color] == nil then + if type(color) ~= "number" then expect(1, color, "number") end + if tHex[color] == nil then error( "Invalid color (got " .. color .. ")", 2 ) end nBackgroundColor = color @@ -346,7 +345,7 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) end function window.scroll( n ) - if type( n ) ~= "number" then error( "bad argument #1 (expected number, got " .. type( n ) .. ")", 2 ) end + if type(n) ~= "number" then expect(1, n, "number") end if n ~= 0 then local tNewLines = {} local sEmptyText = sEmptySpaceLine @@ -391,7 +390,7 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) -- Other functions function window.setVisible( bVis ) - if type( bVis ) ~= "boolean" then error( "bad argument #1 (expected boolean, got " .. type( bVis ) .. ")", 2 ) end + if type(bVis) ~= "boolean" then expect(1, bVis, "boolean") end if bVisible ~= bVis then bVisible = bVis if bVisible then @@ -423,11 +422,11 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) end function window.reposition( nNewX, nNewY, nNewWidth, nNewHeight ) - if type( nNewX ) ~= "number" then error( "bad argument #1 (expected number, got " .. type( nNewX ) .. ")", 2 ) end - if type( nNewY ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( nNewY ) .. ")", 2 ) end - if nNewWidth ~= nil or nNewHeight ~= nil then - if type( nNewWidth ) ~= "number" then error( "bad argument #3 (expected number, got " .. type( nNewWidth ) .. ")", 2 ) end - if type( nNewHeight ) ~= "number" then error( "bad argument #4 (expected number, got " .. type( nNewHeight ) .. ")", 2 ) end + if type(nNewX) ~= "number" then expect(1, nNewX, "number") end + if type(nNewY) ~= "number" then expect(2, nNewY, "number") end + if nNewWidth ~= nil or nNewHeight ~= nil then + expect(3, nNewWidth, "number") + expect(4, nNewHeight, "number") end nX = nNewX diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua index d30c2c3ff..00988eb27 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua @@ -1,3 +1,4 @@ +local expect = _G["~expect"] -- Setup process switching local parentTerm = term.current() @@ -197,9 +198,7 @@ function multishell.getFocus() end function multishell.setFocus( n ) - if type( n ) ~= "number" then - error( "bad argument #1 (expected number, got " .. type( n ) .. ")", 2 ) - end + expect(1, n, "number") if n >= 1 and n <= #tProcesses then selectProcess( n ) redrawMenu() @@ -209,9 +208,7 @@ function multishell.setFocus( n ) end function multishell.getTitle( n ) - if type( n ) ~= "number" then - error( "bad argument #1 (expected number, got " .. type( n ) .. ")", 2 ) - end + expect(1, n, "number") if n >= 1 and n <= #tProcesses then return tProcesses[n].sTitle end @@ -219,12 +216,8 @@ function multishell.getTitle( n ) end function multishell.setTitle( n, sTitle ) - if type( n ) ~= "number" then - error( "bad argument #1 (expected number, got " .. type( n ) .. ")", 2 ) - end - if type( sTitle ) ~= "string" then - error( "bad argument #2 (expected string, got " .. type( sTitle ) .. ")", 2 ) - end + expect(1, n, "number") + expect(2, sTitle, "string") if n >= 1 and n <= #tProcesses then setProcessTitle( n, sTitle ) redrawMenu() @@ -236,12 +229,8 @@ function multishell.getCurrent() end function multishell.launch( tProgramEnv, sProgramPath, ... ) - if type( tProgramEnv ) ~= "table" then - error( "bad argument #1 (expected table, got " .. type( tProgramEnv ) .. ")", 2 ) - end - if type( sProgramPath ) ~= "string" then - error( "bad argument #2 (expected string, got " .. type( sProgramPath ) .. ")", 2 ) - end + expect(1, tProgramEnv, "table") + expect(2, sProgramPath, "string") local previousTerm = term.current() setMenuVisible( (#tProcesses + 1) >= 2 ) local nResult = launchProcess( false, tProgramEnv, sProgramPath, ... ) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua index ef071be64..bc95dbf2e 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua @@ -1,3 +1,4 @@ +local expect = _G["~expect"] local multishell = multishell local parentShell = shell @@ -74,9 +75,7 @@ local function createShellEnv( sDir ) local sentinel = {} local function require( name ) - if type( name ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( name ) .. ")", 2 ) - end + expect(1, name, "string") if package.loaded[name] == sentinel then error("loop or previous error loading module '" .. name .. "'", 0) end @@ -191,9 +190,7 @@ function shell.dir() end function shell.setDir( _sDir ) - if type( _sDir ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _sDir ) .. ")", 2 ) - end + expect(1, _sDir, "string") if not fs.isDir( _sDir ) then error( "Not a directory", 2 ) end @@ -205,16 +202,12 @@ function shell.path() end function shell.setPath( _sPath ) - if type( _sPath ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _sPath ) .. ")", 2 ) - end + expect(1, _sPath, "string") sPath = _sPath end function shell.resolve( _sPath ) - if type( _sPath ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _sPath ) .. ")", 2 ) - end + expect(1, _sPath, "string") local sStartChar = string.sub( _sPath, 1, 1 ) if sStartChar == "/" or sStartChar == "\\" then return fs.combine( "", _sPath ) @@ -234,9 +227,7 @@ local function pathWithExtension( _sPath, _sExt ) end function shell.resolveProgram( _sCommand ) - if type( _sCommand ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _sCommand ) .. ")", 2 ) - end + expect(1, _sCommand, "string") -- Substitute aliases firsts if tAliases[ _sCommand ] ~= nil then _sCommand = tAliases[ _sCommand ] @@ -361,9 +352,7 @@ local function completeProgramArgument( sProgram, nArgument, sPart, tPreviousPar end function shell.complete( sLine ) - if type( sLine ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sLine ) .. ")", 2 ) - end + expect(1, sLine, "string") if #sLine > 0 then local tWords = tokenise( sLine ) local nIndex = #tWords @@ -400,19 +389,13 @@ function shell.complete( sLine ) end function shell.completeProgram( sProgram ) - if type( sProgram ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sProgram ) .. ")", 2 ) - end + expect(1, sProgram, "string") return completeProgram( sProgram ) end function shell.setCompletionFunction( sProgram, fnComplete ) - if type( sProgram ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sProgram ) .. ")", 2 ) - end - if type( fnComplete ) ~= "function" then - error( "bad argument #2 (expected function, got " .. type( fnComplete ) .. ")", 2 ) - end + expect(1, sProgram, "string") + expect(2, fnComplete, "function") tCompletionInfo[ sProgram ] = { fnComplete = fnComplete } @@ -430,19 +413,13 @@ function shell.getRunningProgram() end function shell.setAlias( _sCommand, _sProgram ) - if type( _sCommand ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _sCommand ) .. ")", 2 ) - end - if type( _sProgram ) ~= "string" then - error( "bad argument #2 (expected string, got " .. type( _sProgram ) .. ")", 2 ) - end + expect(1, _sCommand, "string") + expect(2, _sProgram, "string") tAliases[ _sCommand ] = _sProgram end function shell.clearAlias( _sCommand ) - if type( _sCommand ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( _sCommand ) .. ")", 2 ) - end + expect(1, _sCommand, "string") tAliases[ _sCommand ] = nil end @@ -472,9 +449,7 @@ if multishell then end function shell.switchTab( nID ) - if type( nID ) ~= "number" then - error( "bad argument #1 (expected number, got " .. type( nID ) .. ")", 2 ) - end + expect(1, nID, "number") multishell.setFocus( nID ) end end diff --git a/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java index 2a7c9e551..1f4151244 100644 --- a/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java +++ b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java @@ -20,6 +20,7 @@ import org.junit.jupiter.api.Assertions; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.Arrays; import java.util.function.Consumer; /** @@ -122,7 +123,7 @@ public class ComputerBootstrap @Override public String[] getMethodNames() { - return new String[] { "assert" }; + return new String[] { "assert", "log" }; } @Nullable @@ -144,6 +145,9 @@ public class ComputerBootstrap return arguments; } + case 1: + ComputerCraft.log.info( "[Computer] {}", Arrays.toString( arguments ) ); + return null; default: return null; diff --git a/src/test/resources/test-rom/mcfly.lua b/src/test/resources/test-rom/mcfly.lua index 25e8ab155..cb70113d0 100644 --- a/src/test/resources/test-rom/mcfly.lua +++ b/src/test/resources/test-rom/mcfly.lua @@ -27,6 +27,43 @@ local function check(func, arg, ty, val) end end +local active_stubs = {} + +--- Stub a global variable with a specific value +-- +-- @tparam string var The variable to stub +-- @param value The value to stub it with +local function stub(var, value) + if not active_stubs[var] then + active_stubs[var] = { value = _G[var] } + end + + _G[var] = value +end + + +--- Capture the current global state of the computer +local function push_state() + local stubs = active_stubs + active_stubs = {} + return { + term = term.current(), + input = io.input(), + output = io.output(), + stubs = stubs, + } +end + +--- Restore the global state of the computer to a previous version +local function pop_state(state) + for k, v in pairs(active_stubs) do _G[k] = v.value end + active_stubs = state.stubs + + term.redirect(state.term) + io.input(state.input) + io.output(state.output) +end + local error_mt = { __tostring = function(self) return self.message end } --- Attempt to execute the provided function, gathering a stack trace when it @@ -50,10 +87,6 @@ local function try(fn) return { message = err, trace = debug.traceback(nil, 2) } end) - -- Restore a whole bunch of state - io.input(io.stdin) - io.output(io.stdout) - -- If we succeeded, propagate it if ok then return ok, err end @@ -196,13 +229,32 @@ function expect_mt:matches(value) return self end ---- Construct a new expectation from the provided value --- --- @param value The value to apply assertions to --- @return The new expectation -local function expect(value) - return setmetatable({ value = value}, expect_mt) -end +local expect = setmetatable( { + --- Construct an expectation on the error message calling this function + -- produces + -- + -- @tparam fun The function to call + -- @param ... The function arguments + -- @return The new expectation + error = function(fun, ...) + local ok, res = pcall(fun, ...) local _, line = pcall(error, "", 2) + if ok then fail("expected function to error") end + if res:sub(1, #line) == line then + res = res:sub(#line + 1) + elseif res:sub(1, 7) == "pcall: " then + res = res:sub(8) + end + return setmetatable({ value = res }, expect_mt) + end, +}, { + --- Construct a new expectation from the provided value + -- + -- @param value The value to apply assertions to + -- @return The new expectation + __call = function(_, value) + return setmetatable({ value = value }, expect_mt) + end +}) --- The stack of "describe"s. local test_stack = { n = 0 } @@ -302,10 +354,15 @@ end do -- Load in the tests from all our files - local env = setmetatable({ - expect = expect, fail = fail, - describe = describe, it = it, pending = pending - }, { __index = _ENV }) + local env = setmetatable({}, { __index = _ENV }) + + local function set_env(tbl) + for k in pairs(env) do env[k] = nil end + for k, v in pairs(tbl) do env[k] = v end + end + + -- When declaring tests, you shouldn't be able to use test methods + set_env { describe = describe, it = it, pending = pending } local suffix = "_spec.lua" local function run_in(sub_dir) @@ -326,6 +383,9 @@ do end run_in(root_dir) + + -- When running tests, you shouldn't be able to declare new ones. + set_env { expect = expect, fail = fail, stub = stub } end -- Error if we've found no tests @@ -359,9 +419,13 @@ local function do_run(test) err = test.error status = "error" elseif test.action then + local state = push_state() + local ok ok, err = try(test.action) status = ok and "pass" or (err.fail and "fail" or "error") + + pop_state(state) end -- If we've a boolean status, then convert it into a string diff --git a/src/test/resources/test-rom/spec/apis/colors_spec.lua b/src/test/resources/test-rom/spec/apis/colors_spec.lua index d1271b625..91ebefc51 100644 --- a/src/test/resources/test-rom/spec/apis/colors_spec.lua +++ b/src/test/resources/test-rom/spec/apis/colors_spec.lua @@ -1,9 +1,24 @@ describe("The colors library", function() - it("colors.combine", function() - expect(colors.combine(colors.red, colors.brown, colors.green)):equals(0x7000) + describe("colors.combine", function() + it("validates arguments", function() + -- FIXME: Error when last argument is nil - use table.pack instead. + expect.error(colors.combine, 1, false):eq("bad argument #2 (expected number, got boolean)") + expect.error(colors.combine, 1, 1, false):eq("bad argument #3 (expected number, got boolean)") + end) + + it("combines colours", function() + expect(colors.combine()):eq(0) + expect(colors.combine(colors.red, colors.brown, colors.green)):eq(0x7000) + end) end) describe("colors.subtract", function() + it("validates arguments", function() + expect.error(colors.subtract, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(colors.subtract, 1, false):eq("bad argument #2 (expected number, got boolean)") + expect.error(colors.subtract, 1, 1, false):eq("bad argument #3 (expected number, got boolean)") + end) + it("subtracts colours", function() expect(colors.subtract(0x7000, colors.green)):equals(0x5000) expect(colors.subtract(0x5000, colors.red)):equals(0x1000) @@ -17,6 +32,11 @@ describe("The colors library", function() end) describe("colors.test", function() + it("validates arguments", function() + expect.error(colors.test, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(colors.test, 1, nil):eq("bad argument #2 (expected number, got nil)") + end) + it("returns true when present", function() expect(colors.test(0x7000, colors.green)):equals(true) end) @@ -28,16 +48,30 @@ describe("The colors library", function() end) end) - it("colors.packRGB", function() - expect(colors.packRGB(0.3, 0.5, 0.6)):equals(0x4c7f99) + describe("colors.packRGB", function() + it("validates arguments", function() + expect.error(colors.packRGB, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(colors.packRGB, 1, nil):eq("bad argument #2 (expected number, got nil)") + expect.error(colors.packRGB, 1, 1, nil):eq("bad argument #3 (expected number, got nil)") + end) + + it("packs colours", function() + expect(colors.packRGB(0.3, 0.5, 0.6)):equals(0x4c7f99) + end) end) - it("colors.unpackRGB", function() - expect({ colors.unpackRGB(0x4c7f99) }):same { 0x4c / 0xFF, 0x7f / 0xFF, 0.6 } + describe("colors.unpackRGB", function() + it("validates arguments", function() + expect.error(colors.unpackRGB, nil):eq("bad argument #1 (expected number, got nil)") + end) + + it("unpacks colours", function() + expect({ colors.unpackRGB(0x4c7f99) }):same { 0x4c / 0xFF, 0x7f / 0xFF, 0.6 } + end) end) it("colors.rgb8", function() expect(colors.rgb8(0.3, 0.5, 0.6)):equals(0x4c7f99) expect({ colors.rgb8(0x4c7f99) }):same { 0x4c / 0xFF, 0x7f / 0xFF, 0.6 } end) -end ) +end) diff --git a/src/test/resources/test-rom/spec/apis/fs_spec.lua b/src/test/resources/test-rom/spec/apis/fs_spec.lua new file mode 100644 index 000000000..883b8c575 --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/fs_spec.lua @@ -0,0 +1,14 @@ +describe("The fs library", function() + describe("fs.complete", function() + it("validates arguments", function() + fs.complete("", "") + fs.complete("", "", true) + fs.complete("", "", nil, true) + + expect.error(fs.complete, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(fs.complete, "", nil):eq("bad argument #2 (expected string, got nil)") + expect.error(fs.complete, "", "", 1):eq("bad argument #3 (expected boolean, got number)") + expect.error(fs.complete, "", "", true, 1):eq("bad argument #4 (expected boolean, got number)") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/gps_spec.lua b/src/test/resources/test-rom/spec/apis/gps_spec.lua new file mode 100644 index 000000000..e1602dfc7 --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/gps_spec.lua @@ -0,0 +1,15 @@ +describe("The gps library", function() + describe("gps.locate", function() + it("validates arguments", function() + stub("commands", { getBlockPosition = function() + end }) + + gps.locate() + gps.locate(1) + gps.locate(1, true) + + expect.error(gps.locate, ""):eq("bad argument #1 (expected number, got string)") + expect.error(gps.locate, 1, ""):eq("bad argument #2 (expected boolean, got string)") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/help_spec.lua b/src/test/resources/test-rom/spec/apis/help_spec.lua new file mode 100644 index 000000000..d7ecb923f --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/help_spec.lua @@ -0,0 +1,22 @@ +describe("The help library", function() + describe("help.setPath", function() + it("validates arguments", function() + help.setPath(help.path()) + expect.error(help.setPath, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("help.lookup", function() + it("validates arguments", function() + help.lookup("") + expect.error(help.lookup, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("help.completeTopic", function() + it("validates arguments", function() + help.completeTopic("") + expect.error(help.completeTopic, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/io_spec.lua b/src/test/resources/test-rom/spec/apis/io_spec.lua index fe539b5c1..9dad5f7ec 100644 --- a/src/test/resources/test-rom/spec/apis/io_spec.lua +++ b/src/test/resources/test-rom/spec/apis/io_spec.lua @@ -18,13 +18,32 @@ describe("The io library", function() expect(io.type(handle)):equals("file") end) - it("returns nil on values", function() expect(io.type(8)):equals(nil) end) + it("returns nil on values", function() + expect(io.type(8)):equals(nil) + end) + it("returns nil on tables", function() expect(io.type(setmetatable({}, {}))):equals(nil) end) end) + describe("io.lines", function() + it("validates arguments", function() + io.lines(nil) + expect.error(io.lines, ""):eq("/: No such file") + expect.error(io.lines, false):eq("bad argument #1 (expected string, got boolean)") + end) + end) + describe("io.open", function() + it("validates arguments", function() + io.open("") + io.open("", "r") + + expect.error(io.open, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(io.open, "", false):eq("bad argument #2 (expected string, got boolean)") + end) + it("returns an error message on non-existent files", function() local a, b = io.open('xuxu_nao_existe') expect(a):equals(nil) @@ -42,7 +61,7 @@ describe("The io library", function() expect(io.output():seek()):equal(0) assert(io.write("alo alo")) expect(io.output():seek()):equal(#("alo alo")) - expect(io.output():seek("cur", -3)):equal(#("alo alo")-3) + expect(io.output():seek("cur", -3)):equal(#("alo alo") - 3) assert(io.write("joao")) expect(io.output():seek("end"):equal(#("alo joao"))) diff --git a/src/test/resources/test-rom/spec/apis/keys_spec.lua b/src/test/resources/test-rom/spec/apis/keys_spec.lua new file mode 100644 index 000000000..8983543bc --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/keys_spec.lua @@ -0,0 +1,8 @@ +describe("The keys library", function() + describe("keys.getName", function() + it("validates arguments", function() + keys.getName(1) + expect.error(keys.getName, nil):eq("bad argument #1 (expected number, got nil)") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/os_spec.lua b/src/test/resources/test-rom/spec/apis/os_spec.lua index 5c4515a46..7fc1add53 100644 --- a/src/test/resources/test-rom/spec/apis/os_spec.lua +++ b/src/test/resources/test-rom/spec/apis/os_spec.lua @@ -1,4 +1,4 @@ -describe("The os api", function() +describe("The os library", function() describe("os.date and os.time", function() it("round trips correctly", function() local t = math.floor(os.epoch("local") / 1000) @@ -118,4 +118,16 @@ describe("The os api", function() expect(t1 - t2):eq(60 * 2 - 2) end) end) + + describe("os.loadAPI", function() + it("validates arguments", function() + expect.error(os.loadAPI, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("os.unloadAPI", function() + it("validates arguments", function() + expect.error(os.loadAPI, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) end) diff --git a/src/test/resources/test-rom/spec/apis/paintutils_spec.lua b/src/test/resources/test-rom/spec/apis/paintutils_spec.lua new file mode 100644 index 000000000..fc72eece2 --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/paintutils_spec.lua @@ -0,0 +1,60 @@ +describe("The paintutils library", function() + describe("paintutils.parseImage", function() + it("validates arguments", function() + paintutils.parseImage("") + expect.error(paintutils.parseImage, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("paintutils.loadImage", function() + it("validates arguments", function() + expect.error(paintutils.loadImage, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("paintutils.drawPixel", function() + it("validates arguments", function() + expect.error(paintutils.drawPixel, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(paintutils.drawPixel, 1, nil):eq("bad argument #2 (expected number, got nil)") + expect.error(paintutils.drawPixel, 1, 1, false):eq("bad argument #3 (expected number, got boolean)") + end) + end) + + describe("paintutils.drawLine", function() + it("validates arguments", function() + expect.error(paintutils.drawLine, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(paintutils.drawLine, 1, nil):eq("bad argument #2 (expected number, got nil)") + expect.error(paintutils.drawLine, 1, 1, nil):eq("bad argument #3 (expected number, got nil)") + expect.error(paintutils.drawLine, 1, 1, 1, nil):eq("bad argument #4 (expected number, got nil)") + expect.error(paintutils.drawLine, 1, 1, 1, 1, false):eq("bad argument #5 (expected number, got boolean)") + end) + end) + + describe("paintutils.drawBox", function() + it("validates arguments", function() + expect.error(paintutils.drawBox, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(paintutils.drawBox, 1, nil):eq("bad argument #2 (expected number, got nil)") + expect.error(paintutils.drawBox, 1, 1, nil):eq("bad argument #3 (expected number, got nil)") + expect.error(paintutils.drawBox, 1, 1, 1, nil):eq("bad argument #4 (expected number, got nil)") + expect.error(paintutils.drawBox, 1, 1, 1, 1, false):eq("bad argument #5 (expected number, got boolean)") + end) + end) + + describe("paintutils.drawFilledBox", function() + it("validates arguments", function() + expect.error(paintutils.drawFilledBox, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(paintutils.drawFilledBox, 1, nil):eq("bad argument #2 (expected number, got nil)") + expect.error(paintutils.drawFilledBox, 1, 1, nil):eq("bad argument #3 (expected number, got nil)") + expect.error(paintutils.drawFilledBox, 1, 1, 1, nil):eq("bad argument #4 (expected number, got nil)") + expect.error(paintutils.drawFilledBox, 1, 1, 1, 1, false):eq("bad argument #5 (expected number, got boolean)") + end) + end) + + describe("paintutils.drawImage", function() + it("validates arguments", function() + expect.error(paintutils.drawImage, nil):eq("bad argument #1 (expected table, got nil)") + expect.error(paintutils.drawImage, {}, nil):eq("bad argument #2 (expected number, got nil)") + expect.error(paintutils.drawImage, {}, 1, nil):eq("bad argument #3 (expected number, got nil)") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/peripheral_spec.lua b/src/test/resources/test-rom/spec/apis/peripheral_spec.lua new file mode 100644 index 000000000..8fca583e1 --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/peripheral_spec.lua @@ -0,0 +1,47 @@ +describe("The peripheral library", function() + describe("peripheral.isPresent", function() + it("validates arguments", function() + peripheral.isPresent("") + expect.error(peripheral.isPresent, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("peripheral.getType", function() + it("validates arguments", function() + peripheral.getType("") + expect.error(peripheral.getType, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("peripheral.getMethods", function() + it("validates arguments", function() + peripheral.getMethods("") + expect.error(peripheral.getMethods, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("peripheral.call", function() + it("validates arguments", function() + peripheral.call("", "") + expect.error(peripheral.call, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(peripheral.call, "", nil):eq("bad argument #2 (expected string, got nil)") + end) + end) + + describe("peripheral.wrap", function() + it("validates arguments", function() + peripheral.wrap("") + expect.error(peripheral.wrap, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("peripheral.find", function() + it("validates arguments", function() + peripheral.find("") + peripheral.find("", function() + end) + expect.error(peripheral.find, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(peripheral.find, "", false):eq("bad argument #2 (expected function, got boolean)") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/rednet_spec.lua b/src/test/resources/test-rom/spec/apis/rednet_spec.lua new file mode 100644 index 000000000..4c9e2824a --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/rednet_spec.lua @@ -0,0 +1,78 @@ +describe("The rednet library", function() + describe("rednet.open", function() + it("validates arguments", function() + expect.error(rednet.open, nil):eq("bad argument #1 (expected string, got nil)") + end) + + it("requires a modem to be present", function() + expect.error(rednet.open, "not_there"):eq("No such modem: not_there") + end) + end) + + describe("rednet.close", function() + it("validates arguments", function() + rednet.close() + expect.error(rednet.close, 1):eq("bad argument #1 (expected string, got number)") + expect.error(rednet.close, false):eq("bad argument #1 (expected string, got boolean)") + end) + + it("requires a modem to be present", function() + expect.error(rednet.close, "not_there"):eq("No such modem: not_there") + end) + end) + + describe("rednet.isOpen", function() + it("validates arguments", function() + rednet.isOpen() + rednet.isOpen("") + expect.error(rednet.isOpen, 1):eq("bad argument #1 (expected string, got number)") + expect.error(rednet.isOpen, false):eq("bad argument #1 (expected string, got boolean)") + end) + end) + + describe("rednet.send", function() + it("validates arguments", function() + rednet.send(1) + rednet.send(1, nil, "") + expect.error(rednet.send, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(rednet.send, 1, nil, false):eq("bad argument #3 (expected string, got boolean)") + end) + end) + + describe("rednet.broadcast", function() + it("validates arguments", function() + rednet.broadcast(nil) + rednet.broadcast(nil, "") + expect.error(rednet.broadcast, nil, false):eq("bad argument #2 (expected string, got boolean)") + end) + end) + + describe("rednet.receive", function() + it("validates arguments", function() + expect.error(rednet.receive, false):eq("bad argument #1 (expected string, got boolean)") + expect.error(rednet.receive, "", false):eq("bad argument #2 (expected number, got boolean)") + end) + end) + + describe("rednet.host", function() + it("validates arguments", function() + expect.error(rednet.host, "", "localhost"):eq("Reserved hostname") + expect.error(rednet.host, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(rednet.host, "", nil):eq("bad argument #2 (expected string, got nil)") + end) + end) + + describe("rednet.unhost", function() + it("validates arguments", function() + rednet.unhost("") + expect.error(rednet.unhost, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("rednet.lookup", function() + it("validates arguments", function() + expect.error(rednet.lookup, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(rednet.lookup, "", false):eq("bad argument #2 (expected string, got boolean)") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/settings_spec.lua b/src/test/resources/test-rom/spec/apis/settings_spec.lua new file mode 100644 index 000000000..b54e24e67 --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/settings_spec.lua @@ -0,0 +1,43 @@ +describe("The settings library", function() + describe("settings.set", function() + it("validates arguments", function() + settings.set("test", 1) + settings.set("test", "") + settings.set("test", {}) + settings.set("test", false) + + expect.error(settings.set, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(settings.set, "", nil):eq("bad argument #2 (expected number, string, boolean or table, got nil)") + end) + + it("prevents storing unserialisable types", function() + expect.error(settings.set, "", { print }):eq("Cannot serialize type function") + end) + end) + + describe("settings.get", function() + it("validates arguments", function() + settings.get("test") + expect.error(settings.get, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("settings.unset", function() + it("validates arguments", function() + settings.unset("test") + expect.error(settings.unset, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("settings.load", function() + it("validates arguments", function() + expect.error(settings.load, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("settings.save", function() + it("validates arguments", function() + expect.error(settings.save, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/term_spec.lua b/src/test/resources/test-rom/spec/apis/term_spec.lua new file mode 100644 index 000000000..769fcb867 --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/term_spec.lua @@ -0,0 +1,12 @@ +describe("The term library", function() + describe("term.redirect", function() + it("validates arguments", function() + expect.error(term.redirect, nil):eq("bad argument #1 (expected table, got nil)") + end) + + it("prevents redirecting to term", function() + expect.error(term.redirect, term) + :eq("term is not a recommended redirect target, try term.current() instead") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/textutils_spec.lua b/src/test/resources/test-rom/spec/apis/textutils_spec.lua new file mode 100644 index 000000000..5b13220b4 --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/textutils_spec.lua @@ -0,0 +1,57 @@ +describe("The textutils library", function() + describe("textutils.slowWrite", function() + it("validates arguments", function() + expect.error(textutils.slowWrite, nil, false):eq("bad argument #2 (expected number, got boolean)") + end) + end) + + describe("textutils.formatTime", function() + it("validates arguments", function() + textutils.formatTime(0) + textutils.formatTime(0, false) + expect.error(textutils.formatTime, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(textutils.formatTime, 1, 1):eq("bad argument #2 (expected boolean, got number)") + end) + end) + + describe("textutils.pagedPrint", function() + it("validates arguments", function() + expect.error(textutils.pagedPrint, nil, false):eq("bad argument #2 (expected number, got boolean)") + end) + end) + + describe("textutils.unserialise", function() + it("validates arguments", function() + textutils.unserialise("") + expect.error(textutils.unserialise, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("textutils.serialiseJSON", function() + it("validates arguments", function() + textutils.serialiseJSON("") + textutils.serialiseJSON(1) + textutils.serialiseJSON({}) + textutils.serialiseJSON(false) + textutils.serialiseJSON("", true) + expect.error(textutils.serialiseJSON, nil):eq("bad argument #1 (expected table, string, number or boolean, got nil)") + expect.error(textutils.serialiseJSON, "", 1):eq("bad argument #2 (expected boolean, got number)") + end) + end) + + describe("textutils.urlEncode", function() + it("validates arguments", function() + textutils.urlEncode("") + expect.error(textutils.urlEncode, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("textutils.complete", function() + it("validates arguments", function() + textutils.complete("pri") + textutils.complete("pri", _G) + expect.error(textutils.complete, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(textutils.complete, "", false):eq("bad argument #2 (expected table, got boolean)") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/window_spec.lua b/src/test/resources/test-rom/spec/apis/window_spec.lua new file mode 100644 index 000000000..16fe229e1 --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/window_spec.lua @@ -0,0 +1,123 @@ +describe("The window library", function() + local function mk() + return window.create(term.current(), 1, 1, 5, 5, false) + end + + describe("window.create", function() + it("validates arguments", function() + local r = mk() + window.create(r, 1, 1, 5, 5) + window.create(r, 1, 1, 5, 5, false) + + expect.error(window.create, nil):eq("bad argument #1 (expected table, got nil)") + expect.error(window.create, r, nil):eq("bad argument #2 (expected number, got nil)") + expect.error(window.create, r, 1, nil):eq("bad argument #3 (expected number, got nil)") + expect.error(window.create, r, 1, 1, nil):eq("bad argument #4 (expected number, got nil)") + expect.error(window.create, r, 1, 1, 1, nil):eq("bad argument #5 (expected number, got nil)") + expect.error(window.create, r, 1, 1, 1, 1, ""):eq("bad argument #6 (expected boolean, got string)") + end) + end) + + describe("Window.blit", function() + it("validates arguments", function() + local w = mk() + w.blit("a", "a", "a") + + expect.error(w.blit, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(w.blit, "", nil):eq("bad argument #2 (expected string, got nil)") + expect.error(w.blit, "", "", nil):eq("bad argument #3 (expected string, got nil)") + expect.error(w.blit, "", "", "a"):eq("Arguments must be the same length") + end) + end) + + describe("Window.setCursorPos", function() + it("validates arguments", function() + local w = mk() + w.setCursorPos(1, 1) + + expect.error(w.setCursorPos, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(w.setCursorPos, 1, nil):eq("bad argument #2 (expected number, got nil)") + end) + end) + + describe("Window.setCursorBlink", function() + it("validates arguments", function() + local w = mk() + w.setCursorBlink(false) + expect.error(w.setCursorBlink, nil):eq("bad argument #1 (expected boolean, got nil)") + end) + end) + + describe("Window.setTextColour", function() + it("validates arguments", function() + local w = mk() + w.setTextColour(colors.white) + + expect.error(w.setTextColour, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(w.setTextColour, -5):eq("Invalid color (got -5)") + end) + end) + + describe("Window.setPaletteColour", function() + it("validates arguments", function() + local w = mk() + w.setPaletteColour(colors.white, 0, 0, 0) + w.setPaletteColour(colors.white, 0x000000) + + expect.error(w.setPaletteColour, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(w.setPaletteColour, -5):eq("Invalid color (got -5)") + expect.error(w.setPaletteColour, colors.white):eq("bad argument #2 (expected number, got nil)") + expect.error(w.setPaletteColour, colors.white, 1, false):eq("bad argument #3 (expected number, got boolean)") + expect.error(w.setPaletteColour, colors.white, 1, nil, 1):eq("bad argument #3 (expected number, got nil)") + expect.error(w.setPaletteColour, colors.white, 1, 1, nil):eq("bad argument #4 (expected number, got nil)") + end) + end) + + describe("Window.getPaletteColour", function() + it("validates arguments", function() + local w = mk() + w.getPaletteColour(colors.white) + expect.error(w.getPaletteColour, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(w.getPaletteColour, -5):eq("Invalid color (got -5)") + end) + end) + + describe("Window.setBackgroundColour", function() + it("validates arguments", function() + local w = mk() + w.setBackgroundColour(colors.white) + + expect.error(w.setBackgroundColour, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(w.setBackgroundColour, -5):eq("Invalid color (got -5)") + end) + end) + + describe("Window.scroll", function() + it("validates arguments", function() + local w = mk() + w.scroll(0) + expect.error(w.scroll, nil):eq("bad argument #1 (expected number, got nil)") + end) + end) + + describe("Window.setVisible", function() + it("validates arguments", function() + local w = mk() + w.setVisible(false) + expect.error(w.setVisible, nil):eq("bad argument #1 (expected boolean, got nil)") + end) + end) + + describe("Window.reposition", function() + it("validates arguments", function() + local w = mk() + w.reposition(1, 1) + w.reposition(1, 1, 5, 5) + expect.error(w.reposition, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(w.reposition, 1, nil):eq("bad argument #2 (expected number, got nil)") + expect.error(w.reposition, 1, 1, false, 1):eq("bad argument #3 (expected number, got boolean)") + expect.error(w.reposition, 1, 1, nil, 1):eq("bad argument #3 (expected number, got nil)") + expect.error(w.reposition, 1, 1, 1, nil):eq("bad argument #4 (expected number, got nil)") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/base_spec.lua b/src/test/resources/test-rom/spec/base_spec.lua index 11aabb396..191d87eab 100644 --- a/src/test/resources/test-rom/spec/base_spec.lua +++ b/src/test/resources/test-rom/spec/base_spec.lua @@ -1,11 +1,74 @@ describe("The Lua base library", function() + describe("expect", function() + local e = _G["~expect"] + + it("checks a single type", function() + expect(e(1, "test", "string")):eq(true) + expect(e(1, 2, "number")):eq(true) + + expect.error(e, 1, nil, "string"):eq("bad argument #1 (expected string, got nil)") + expect.error(e, 2, 1, "nil"):eq("bad argument #2 (expected nil, got number)") + end) + + it("checks multiple types", function() + expect(e(1, "test", "string", "number")):eq(true) + expect(e(1, 2, "string", "number")):eq(true) + + expect.error(e, 1, nil, "string", "number"):eq("bad argument #1 (expected string or number, got nil)") + expect.error(e, 2, false, "string", "table", "number", "nil") + :eq("bad argument #2 (expected string, table or number, got boolean)") + end) + + it("includes the function name", function() + local function worker() + expect(e(1, nil, "string")):eq(true) + end + local function trampoline() + worker() + end + + expect.error(trampoline):eq("base_spec.lua:27: bad argument #1 to 'worker' (expected string, got nil)") + end) + end) + + describe("sleep", function() + it("validates arguments", function() + sleep(0) + sleep(nil) + + expect.error(sleep, false):eq("bad argument #1 (expected number, got boolean)") + end) + end) + + describe("write", function() + it("validates arguments", function() + write("") + expect.error(write, nil):eq("bad argument #1 (expected string or number, got nil)") + end) + end) + describe("loadfile", function() + it("validates arguments", function() + loadfile("") + loadfile("", {}) + + expect.error(loadfile, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(loadfile, "", false):eq("bad argument #2 (expected table, got boolean)") + end) + it("prefixes the filename with @", function() local info = debug.getinfo(loadfile("/rom/startup.lua"), "S") expect(info):matches { short_src = "startup.lua", source = "@startup.lua" } end) end) + describe("dofile", function() + it("validates arguments", function() + expect.error(dofile, ""):eq("File not found") + expect.error(dofile, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + describe("loadstring", function() it("prefixes the chunk name with '='", function() local info = debug.getinfo(loadstring("return 1", "name"), "S") @@ -27,9 +90,25 @@ describe("The Lua base library", function() end) describe("load", function() + it("validates arguments", function() + load("") + load(function() + end) + load("", "") + load("", "", "") + load("", "", "", _ENV) + + expect.error(load, nil):eq("bad argument #1 (expected function or string, got nil)") + expect.error(load, "", false):eq("bad argument #2 (expected string, got boolean)") + expect.error(load, "", "", false):eq("bad argument #3 (expected string, got boolean)") + expect.error(load, "", "", "", false):eq("bad argument #4 (expected table, got boolean)") + end) + local function generator(parts) return coroutine.wrap(function() - for i = 1, #parts do coroutine.yield(parts[i]) end + for i = 1, #parts do + coroutine.yield(parts[i]) + end end) end diff --git a/src/test/resources/test-rom/spec/programs/advanced/multishell_spec.lua b/src/test/resources/test-rom/spec/programs/advanced/multishell_spec.lua new file mode 100644 index 000000000..d0917c296 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/advanced/multishell_spec.lua @@ -0,0 +1,30 @@ +describe("The multishell program", function() + describe("multishell.setFocus", function() + it("validates arguments", function() + multishell.setFocus(multishell.getFocus()) + expect.error(multishell.setFocus, nil):eq("bad argument #1 (expected number, got nil)") + end) + end) + + describe("multishell.getTitle", function() + it("validates arguments", function() + multishell.getTitle(1) + expect.error(multishell.getTitle, nil):eq("bad argument #1 (expected number, got nil)") + end) + end) + + describe("multishell.setTitle", function() + it("validates arguments", function() + multishell.setTitle(1, multishell.getTitle(1)) + expect.error(multishell.setTitle, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(multishell.setTitle, 1, nil):eq("bad argument #2 (expected string, got nil)") + end) + end) + + describe("multishell.launch", function() + it("validates arguments", function() + expect.error(multishell.launch, nil):eq("bad argument #1 (expected table, got nil)") + expect.error(multishell.launch, _ENV, nil):eq("bad argument #2 (expected string, got nil)") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/shell_spec.lua b/src/test/resources/test-rom/spec/programs/shell_spec.lua index 9d0a7d237..9b9dc7188 100644 --- a/src/test/resources/test-rom/spec/programs/shell_spec.lua +++ b/src/test/resources/test-rom/spec/programs/shell_spec.lua @@ -1,4 +1,11 @@ describe("The shell", function() + describe("require", function() + it("validates arguments", function() + require("math") + expect.error(require, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + describe("shell.run", function() it("sets the arguments", function() local handle = fs.open("test-files/out.txt", "w") @@ -14,4 +21,74 @@ describe("The shell", function() expect(args):same { [0] = "/test-files/out.txt", "arg1", "arg2" } end) end) + + describe("shell.setDir", function() + it("validates arguments", function() + shell.setDir(shell.dir()) + expect.error(shell.setDir, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("shell.setPath", function() + it("validates arguments", function() + shell.setPath(shell.path()) + expect.error(shell.setPath, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("shell.resolve", function() + it("validates arguments", function() + shell.resolve("") + expect.error(shell.resolve, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("shell.resolveProgram", function() + it("validates arguments", function() + shell.resolveProgram("ls") + expect.error(shell.resolveProgram, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("shell.complete", function() + it("validates arguments", function() + shell.complete("ls") + expect.error(shell.complete, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("shell.setCompletionFunction", function() + it("validates arguments", function() + expect.error(shell.setCompletionFunction, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(shell.setCompletionFunction, "", nil):eq("bad argument #2 (expected function, got nil)") + end) + end) + + describe("shell.setCompletionFunction", function() + it("validates arguments", function() + expect.error(shell.setCompletionFunction, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(shell.setCompletionFunction, "", nil):eq("bad argument #2 (expected function, got nil)") + end) + end) + + describe("shell.setAlias", function() + it("validates arguments", function() + shell.setAlias("sl", "ls") + expect.error(shell.setAlias, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(shell.setAlias, "", nil):eq("bad argument #2 (expected string, got nil)") + end) + end) + + describe("shell.clearAlias", function() + it("validates arguments", function() + shell.clearAlias("sl") + expect.error(shell.clearAlias, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("shell.switchTab", function() + it("validates arguments", function() + expect.error(shell.switchTab, nil):eq("bad argument #1 (expected number, got nil)") + end) + end) end)