local function rng_markup() return math.random() > 0.5 and "plain" or "imageboard" end local function generate_str(length,characters) return function() local t = {} local rnglength = math.random(2,length) for i = 1,rnglength do local rngpos = math.random(#characters) local rngchar = string.sub(characters,rngpos,rngpos) table.insert(t,rngchar) end local ret = table.concat(t) return ret end end local function characters(mask) local t = {} for i = 1,255 do if string.match(string.char(i), mask) then table.insert(t,string.char(i)) end end return table.concat(t) end local function maybe(input,chance) chance = chance or 0.5 if math.random() < chance then return input end end local rng_any = generate_str(1024,characters(".")) local rng_subdomain = generate_str(30,characters("[0-9a-z]")) local rng_storyname = generate_str(10,"[a-zA-Z0-9$+!*'(),-]") local rng_storyid = function() return tostring(math.random(1,10)) end local rng_tags = function() local tag_gen = generate_str(10,"[%w%d ]") local t = {} for i = 1,10 do table.insert(t,tag_gen()) end return table.concat(t,";") end local pages = { index = { route = "/", name = "home", methods = { GET={} } }, paste = { route = "/_paste", name = "post_story", methods = { GET={}, POST={ title = rng_any, text = rng_any, pasteas = rng_subdomain, markup = rng_markup, tags = rng_any, } } }, edit = { route = "/_edit", name = "edit", methods = { GET={ story=rng_storyid }, POST={ story=rng_storyid, title = rng_any, text = rng_any, pasteas = rng_subdomain, markup = rng_markup, tags = rng_any }, } }, bio = { route = "/_bio", name = "edit_bio", methods = { GET={}, POST={ user = rng_subdomain, pass = rng_any }, } }, login = { route = "/_login", name = "login", methods = { GET={}, POST={ user = rng_subdomain, pass = rng_any }, } }, claim = { route = "/_claim", name = "claim", methods = { GET = {}, POST = { user = rng_subdomain } } }, download = { route = "/_download", name = "download", methods = { GET = { story = rng_storyid }, } }, preview = { route = "/_preview", name = "preview", methods = { POST = { title = rng_any, text = rng_any, markup = rng_markup, tags = maybe(rng_tags) }, } }, search = { route = "/_search", name = "search", methods = { GET = {}, } } } local request_stub_m = {} function http_response(req,errcode,str) req.responded = true req.errcode = errcode req.message = str end function http_request_get_host(reqstub) return "localhost:8888" end function http_request_populate_post(reqstub) reqstub.post_populated = true end local function fuzz_endpoint(endpoint, parameters) for i = 1,100 do local req = {} for paramtype, params in pairs(parameters) do end end return true end local function generate_req(tbl) assert(({GET=true,POST=true})[tbl.method]) return tbl end local env = {} local smr_mock_env = { --An empty function that gets called to set up databases and do other --startup-time stuff, runs once for each worker process. configure = spy.new(function(...) end), http_request_get_host = spy.new(function(req) return env.host or "test.host" end), http_request_get_path = spy.new(function(req) return env.path or "/" end), http_request_populate_qs = spy.new(function(req) req.qs_populated = true end), http_request_populate_post = spy.new(function(req) req.post_populated = true end), http_populate_multipart_form = spy.new(function(req) req.post_populated = true end), http_argument_get_string = spy.new(function(req,str) assert( req.method == "GET" and req.qs_populated or req.method == "POST" and req.post_populated,[[ http_argument_get_string() can only be called after the appropriate populate method has been called, either http_request_populate_qs(req) or http_request_populate_post(req)]] ) return req.args[str] end), http_file_get = spy.new(function(req,filename) return "file data" end), http_response = spy.new(function(req,errcode,html) end), http_response_header = spy.new(function(req,name,value) end), http_method_text = spy.new(function(req) return req.method end), http_populate_cookies = spy.new(function(req) req.cookies_populated = true end), http_request_cookie = spy.new(function(req,cookie_name) end), http_response_cookie = spy.new(function(req,name,value) req.cookies = {[name] = value} end), log = spy.new(function(priority, message) end), sha3 = spy.new(function(message) return "digest" end), } local sfmt = string.format local string_fmt_override = { --[[ format = spy.new(function(fmt,...) local args = {...} for i = 1,#args do if args[i] == nil then args[i] = "nil" end end table.insert(args,1,fmt) return sfmt(unpack(args)) end) ]] } setmetatable(string_fmt_override,{__index = string}) local smr_override_env = { --Detour assert so we don't actually perform any checks --assert = spy.new(function(bool,msg,level) return bool end), --Allow string.format to accept nil as arguments --string = string_fmt_override } local smr_mock_env_m = { __index = smr_mock_env, __newindex = function(self,key,value) local setter = debug.getinfo(2) if setter.source ~= "=[C]" and setter.source ~= "@./global.lua" and key ~= "configure" then error(string.format( "Tried to create a global %q with value %s\n%s", key, tostring(value), debug.traceback() ),2) else rawset(self,key,value) end end } describe("smr",function() for name, obj in pairs(pages) do describe("endpoint " .. name,function() for method,parameters in pairs(obj.methods) do describe("method " .. method,function() local fname = string.format("%s_%s",name,string.lower(method)) local olds = {} setup(function() setmetatable(_G,smr_mock_env_m) for k,v in pairs(smr_override_env) do olds[k] = _G[k] _G[k] = v end end) teardown(function() setmetatable(_G,{}) for k,v in pairs(olds) do _G[k] = v end end) it("should be named appropriately",function() local f = assert(io.open("endpoints/"..fname .. ".lua","r")) f:close() end) it("should run without errors",function() require("endpoints." .. fname) end) it("should configure without errors",function() require("endpoints." .. fname) configure() end) it("should return a function",function() local pagefunc = assert(require("endpoints." .. fname)) assert(type(pagefunc) == "function") end) it("should call http_response() at some point #slow",function() local pagefunc = require("endpoints." .. fname) for i = 1,10 do local req = {} req.method = method req.path = obj.route req.args = {} for param_name,param_rng_func in pairs(parameters) do local param = param_rng_func() req.args[param_name] = param end pagefunc(req) assert.spy(smr_mock_env.http_response).was_called() end end) end) end end) end end)