From e03b2db08bce57f276ce61fb4169e3cc84984348 Mon Sep 17 00:00:00 2001 From: ell <77150506+ellraiser@users.noreply.github.com> Date: Thu, 5 Oct 2023 23:03:32 +0100 Subject: [PATCH] 0.2 - Added tests for all obj creation, transformation, window + system info graphics methods - Added half the state methods for graphics + added placeholders for missing drawing methods - Added TestMethod:assertNotNil() for quick nil checking - Added time total to the end of each module summary in console log to match file output - Removed a bunch of unessecary nil checks - Removed :release() from test methods, collectgarbage("collect") is called between methods instead - Renamed /output to /examples to avoid confusion - Replaced love.filesystem.newFile with love.filesystem.openFile - Replaced love.math.noise with love.math.perlinNoise / love.math.simplexNoise - Fixed newGearJoint throwing an error in 12 as body needs to be dynamic not static now - Some general cleanup, incl. better comments and time format in file output --- testing/classes/TestMethod.lua | 26 +- testing/classes/TestModule.lua | 11 +- testing/classes/TestSuite.lua | 18 +- testing/conf.lua | 2 +- testing/examples/lovetest_runAllTests.html | 1 + testing/examples/lovetest_runAllTests.xml | 578 +++++++++++ testing/main.lua | 8 +- testing/output/lovetest_runAllTests.html | 1 - testing/output/lovetest_runAllTests.xml | 385 -------- testing/readme.md | 32 +- testing/resources/cubemap.png | Bin 0 -> 27634 bytes testing/resources/love2.png | Bin 0 -> 680 bytes testing/resources/love3.png | Bin 0 -> 680 bytes testing/tests/audio.lua | 109 +-- testing/tests/data.lua | 48 +- testing/tests/event.lua | 22 +- testing/tests/filesystem.lua | 121 ++- testing/tests/font.lua | 19 +- testing/tests/graphics.lua | 1022 +++++++++++++++++++- testing/tests/image.lua | 19 +- testing/tests/math.lua | 75 +- testing/tests/objects.lua | 26 +- testing/tests/physics.lua | 103 +- testing/tests/sound.lua | 11 +- testing/tests/system.lua | 32 +- testing/tests/thread.lua | 14 +- testing/tests/timer.lua | 10 +- testing/tests/video.lua | 6 +- testing/tests/window.lua | 111 ++- testing/todo.md | 26 + 30 files changed, 1976 insertions(+), 860 deletions(-) create mode 100644 testing/examples/lovetest_runAllTests.html create mode 100644 testing/examples/lovetest_runAllTests.xml delete mode 100644 testing/output/lovetest_runAllTests.html delete mode 100644 testing/output/lovetest_runAllTests.xml create mode 100644 testing/resources/cubemap.png create mode 100644 testing/resources/love2.png create mode 100644 testing/resources/love3.png create mode 100644 testing/todo.md diff --git a/testing/classes/TestMethod.lua b/testing/classes/TestMethod.lua index b0c763082..8fa55080f 100644 --- a/testing/classes/TestMethod.lua +++ b/testing/classes/TestMethod.lua @@ -189,14 +189,23 @@ TestMethod = { -- @param {table} obj - table to check is a valid love object -- @return {nil} assertObject = function(self, obj) - self:assertNotEquals(nil, obj, 'check not nill') + self:assertNotNil(obj) self:assertEquals('userdata', type(obj), 'check is userdata') - if obj ~= nil then + if obj ~= nil then self:assertNotEquals(nil, obj:type(), 'check has :type()') end end, + -- @method - TestMethod:assertNotNil() + -- @desc - quick assert for value not nil + -- @param {any} value - value to check not nil + -- @return {nil} + assertNotNil = function (self, value) + self:assertNotEquals(nil, value, 'check not nil') + end, + + -- @method - TestMethod:skipTest() -- @desc - used to mark this test as skipped for a specific reason @@ -289,10 +298,7 @@ TestMethod = { self.finish = love.timer.getTime() - self.start love.test.time = love.test.time + self.finish self.testmodule.time = self.testmodule.time + self.finish - local endtime = tostring(math.floor((love.timer.getTime() - self.start)*1000)) - if string.len(endtime) == 1 then endtime = ' ' .. endtime end - if string.len(endtime) == 2 then endtime = ' ' .. endtime end - if string.len(endtime) == 3 then endtime = ' ' .. endtime end + local endtime = UtilTimeFormat(love.timer.getTime() - self.start) -- get failure/skip message for output (if any) local failure = '' @@ -309,7 +315,7 @@ TestMethod = { -- append XML for the test class result self.testmodule.xml = self.testmodule.xml .. '\t\t\n' .. + '" time="' .. endtime .. '">\n' .. failure .. '\t\t\n' -- unused currently, adds a preview image for certain graphics methods to the output @@ -329,7 +335,7 @@ TestMethod = { '' .. '' .. status .. '' .. '' .. self.method .. '' .. - '' .. tostring(self.finish*1000) .. 'ms' .. + '' .. endtime .. 's' .. '' .. output .. preview .. '' .. '' @@ -350,10 +356,10 @@ TestMethod = { self.testmodule:log( self.testmodule.colors[self.result.result], ' ' .. tested .. matching, - ' ==> ' .. self.result.result .. ' - ' .. endtime .. 'ms ' .. + ' ==> ' .. self.result.result .. ' - ' .. endtime .. 's ' .. self.result.total .. msg ) end -} \ No newline at end of file +} diff --git a/testing/classes/TestModule.lua b/testing/classes/TestModule.lua index 379aac360..9ee6cd62e 100644 --- a/testing/classes/TestModule.lua +++ b/testing/classes/TestModule.lua @@ -83,12 +83,13 @@ TestModule = { -- the XML + HTML for the test to the testsuite output -- @return {nil} printResult = function(self) + local finaltime = UtilTimeFormat(self.time) -- add xml to main output love.test.xml = love.test.xml .. '\t\n' .. self.xml .. '\t\n' + '" time="' .. finaltime .. '">\n' .. self.xml .. '\t\n' -- add html to main output local status = '🔴' if self.failed == 0 then status = '🟢' end @@ -96,8 +97,8 @@ TestModule = { '
  • 🟢 ' .. tostring(self.passed) .. ' Tests
  • ' .. '
  • 🔴 ' .. tostring(self.failed) .. ' Failures
  • ' .. '
  • 🟡 ' .. tostring(self.skipped) .. ' Skipped
  • ' .. - '
  • ' .. tostring(self.time*1000) .. 'ms
  • ' .. '

    ' + '
  • ' .. finaltime .. 's


  • ' -- @TODO use mountFullPath to write output to src? love.filesystem.createDirectory('output') love.filesystem.write('output/' .. self.output .. '.xml', xml .. self.xml .. '') love.filesystem.write('output/' .. self.output .. '.html', html .. self.html .. '') - self.module:log('grey', '\nFINISHED - ' .. finaltime .. 'ms\n') + self.module:log('grey', '\nFINISHED - ' .. finaltime .. 's\n') local failedcol = '\27[31m' if self.totals[2] == 0 then failedcol = '\27[37m' end self.module:log('green', tostring(self.totals[1]) .. ' PASSED' .. ' || ' .. failedcol .. tostring(self.totals[2]) .. ' FAILED || \27[37m' .. tostring(self.totals[3]) .. ' SKIPPED') @@ -156,4 +156,4 @@ TestSuite = { end -} \ No newline at end of file +} diff --git a/testing/conf.lua b/testing/conf.lua index 9f1ba5789..f04c2d90a 100644 --- a/testing/conf.lua +++ b/testing/conf.lua @@ -21,4 +21,4 @@ function love.conf(t) t.modules.timer = true t.modules.video = true t.modules.window = true -end \ No newline at end of file +end diff --git a/testing/examples/lovetest_runAllTests.html b/testing/examples/lovetest_runAllTests.html new file mode 100644 index 000000000..ac9b12d58 --- /dev/null +++ b/testing/examples/lovetest_runAllTests.html @@ -0,0 +1 @@ +

    🔴 love.test



    🟢 love.audio

    \ No newline at end of file diff --git a/testing/examples/lovetest_runAllTests.xml b/testing/examples/lovetest_runAllTests.xml new file mode 100644 index 000000000..9c69661ed --- /dev/null +++ b/testing/examples/lovetest_runAllTests.xml @@ -0,0 +1,578 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testing/main.lua b/testing/main.lua index 205f0b786..c90040818 100644 --- a/testing/main.lua +++ b/testing/main.lua @@ -169,4 +169,10 @@ function UtilStringSplit(str, splitter) table.insert(splits, word) end return splits -end \ No newline at end of file +end + + +-- string time formatter +function UtilTimeFormat(seconds) + return string.format("%.3f", tostring(seconds)) +end diff --git a/testing/output/lovetest_runAllTests.html b/testing/output/lovetest_runAllTests.html deleted file mode 100644 index 164ade985..000000000 --- a/testing/output/lovetest_runAllTests.html +++ /dev/null @@ -1 +0,0 @@ -

    🔴 love.test



    🟢 love.audio

    \ No newline at end of file diff --git a/testing/output/lovetest_runAllTests.xml b/testing/output/lovetest_runAllTests.xml deleted file mode 100644 index a30afbbc2..000000000 --- a/testing/output/lovetest_runAllTests.xml +++ /dev/null @@ -1,385 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/testing/readme.md b/testing/readme.md index 5740a6b4e..4269e4447 100644 --- a/testing/readme.md +++ b/testing/readme.md @@ -84,19 +84,22 @@ This is the status of all module tests currently. -- [x] audio 26 PASSED | 0 FAILED | 0 SKIPPED -- [x] data 7 PASSED | 0 FAILED | 3 SKIPPED [SEE BELOW] -- [x] event 4 PASSED | 0 FAILED | 2 SKIPPED [SEE BELOW] --- [x] filesystem 26 PASSED | 1 FAILED | 2 SKIPPED [SEE BELOW] +-- [x] filesystem 27 PASSED | 0 FAILED | 2 SKIPPED -- [x] font 4 PASSED | 0 FAILED | 1 SKIPPED [SEE BELOW] --- [ ] graphics STILL TO BE DONE +-- [ ] graphics 65 PASSED | 0 FAILED | 31 SKIPPED [SEE BELOW] -- [x] image 3 PASSED | 0 FAILED | 0 SKIPPED --- [x] math 16 PASSED | 0 FAILED | 0 SKIPPED [SEE BELOW] --- [x] physics 21 PASSED | 1 FAILED | 0 SKIPPED [SEE BELOW] +-- [x] math 17 PASSED | 0 FAILED | 0 SKIPPED +-- [x] physics 22 PASSED | 0 FAILED | 0 SKIPPED -- [x] sound 2 PASSED | 0 FAILED | 0 SKIPPED --- [x] system 7 PASSED | 0 FAILED | 1 SKIPPED --- [ ] thread 3 PASSED | 0 FAILED | 0 SKIPPED --- [x] timer 6 PASSED | 0 FAILED | 0 SKIPPED [SEE BELOW] +-- [x] system 6 PASSED | 0 FAILED | 2 SKIPPED +-- [x] thread 3 PASSED | 0 FAILED | 0 SKIPPED +-- [x] timer 6 PASSED | 0 FAILED | 0 SKIPPED -- [x] video 1 PASSED | 0 FAILED | 0 SKIPPED --- [x] window 32 PASSED | 2 FAILED | 1 SKIPPED [SEE BELOW] +-- [x] window 32 PASSED | 2 FAILED | 2 SKIPPED [SEE BELOW] + -- [ ] objects STILL TO BE DONE +-------------------------------------------------------------------------------- +-- [x] totals 226 PASSED | 4 FAILED | 43 SKIPPED ``` The following modules are not covered as we can't really emulate input nicely: @@ -108,24 +111,17 @@ The following modules are not covered as we can't really emulate input nicely: Modules with some small bits needed or needing sense checking: - **love.data** - packing methods need writing cos i dont really get what they are - **love.event** - love.event.wait or love.event.pump need writing if possible I dunno how to check -- **love.filesystem** - getSource() / setSource() dont think we can test - **love.font** - newBMFontRasterizer() wiki entry is wrong so not sure whats expected -- **love.timer** - couple methods I don't know if you could reliably test specific values +- **love.graphics** - still need to do tests for the drawing and state methods - **love.image** - ideally isCompressed should have an example of all compressed files love can take - **love.math** - linearToGamma + gammaToLinear using direct formulas don't get same value back -- **love.window** - couple stuff just nil checked as I think it's hardware dependent, needs checking - -Modules still to be completed or barely started -- **love.graphics** - done 1 as an example of how we can test the drawing but not really started -- **love.objects** - done 1 as an example of how we can test objs with mini scenarios +- **love.objects** - not started properly yet --- ## Failures - **love.window.isMaximized()** - returns false after calling love.window.maximize? - **love.window.maximize()** - same as above -- **love.physics.newGearJoint()** - something changed in 12 -- **love.objects.File()** - dont think I understand the buffering system --- @@ -136,4 +132,4 @@ Modules still to be completed or barely started - [ ] Ability to test loading different combinations of modules - [ ] Performance tests -There is some unused code in the Test.lua class to add preview vs actual images to the HTML output \ No newline at end of file +There is some unused code in the Test.lua class to add preview vs actual images to the HTML output diff --git a/testing/resources/cubemap.png b/testing/resources/cubemap.png new file mode 100644 index 0000000000000000000000000000000000000000..2b8b2ed0c6b3eb8fd82bf7804ea9789bbdd306a5 GIT binary patch literal 27634 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 literal 0 HcmV?d00001 diff --git a/testing/resources/love2.png b/testing/resources/love2.png new file mode 100644 index 0000000000000000000000000000000000000000..e2612a857c850afa83db824f1b5a30d226508df0 GIT binary patch literal 680 zcmV;Z0$2TsP)Px%Vo5|nRCt{2o7+*tFc3vAv;sfS2Mqv2C;^I~4k&>z&<^}SE%3o?#!>9(vG=YF z@%7T0>Fr z7M27`Bhl~{h6Hy5z2Gfg3CEs;d&2|3)$^z89GV5p0p8+~&{RHifq%HX*n0hTds@v? zT>*1}A4^LmR2gf5KU?2z{{C1!(T+*4{xCI_Q2fPO_#s4^DX5xb_6Y#WB@}&$32#Y( zYL3alTS_Ekzo3A(7*NeI*XysE)5%KM`=Juv6Q+d859SJQVM!Pr2IoA~wPtFF+_B;v z>LOEH1;B14Y*oO2yz*(%N^so_{fBG>9KzMN469(NfZiw2I|nadYe?|?ADH_Op<#wY z;ZgzV8-Jk+SXUnyseoQfRU$HWKR~+~vZ$+|_3BUE3{h`~Eh-6Yct9{AVqr^AzyqQw zF$+tA3LX$nidwu9l<8FF4Q!4>;Ecn1otzc3R;9!U75J^LcMP@BnFvOfLyuc!0P_ zDp~>q9w0B1i;}>C2LuZx)e@NSfM}_#N&*`m5H6NxOHjZA;^p!z2`YFXV8eu0f)XAG z+A`BBK@ATCZkno<5CIPaZ<{NX5Cso(*f^P!5D5=-+&Y_zhz4J>Px%Vo5|nRCt{2o7+*tFc3vAv;sfS2Mqv2C;^I~4k&>z&<^}SE%3o?#!>9(vG=YF z@%7T0>Fr z7M27`Bhl~{h6Hy5z2Gfg3CEs;d&2|3)$^z89GV5p0p8+~&{RHifq%HX*n0hTds@v? zT>*1}A4^LmR2gf5KU?2z{{C1!(T+*4{xCI_Q2fPO_#s4^DX5xb_6Y#WB@}&$32#Y( zYL3alTS_Ekzo3A(7*NeI*XysE)5%KM`=Juv6Q+d859SJQVM!Pr2IoA~wPtFF+_B;v z>LOEH1;B14Y*oO2yz*(%N^so_{fBG>9KzMN469(NfZiw2I|nadYe?|?ADH_Op<#wY z;ZgzV8-Jk+SXUnyseoQfRU$HWKR~+~vZ$+|_3BUE3{h`~Eh-6Yct9{AVqr^AzyqQw zF$+tA3LX$nidwu9l<8FF4Q!4>;Ecn1otzc3R;9!U75J^LcMP@BnFvOfLyuc!0P_ zDp~>q9w0B1i;}>C2LuZx)e@NSfM}_#N&*`m5H6NxOHjZA;^p!z2`YFXV8eu0f)XAG z+A`BBK@ATCZkno<5CIPaZ<{NX5Cso(*f^P!5D5=-+&Y_zhz4J>