From 990259edf95eabde334628181cd25bd0ef252c6b Mon Sep 17 00:00:00 2001 From: ell <77150506+ellraiser@users.noreply.github.com> Date: Wed, 28 Feb 2024 17:49:51 +0000 Subject: [PATCH 1/6] more tests - added custom error handler so that love is closed if a crash occurs rather than hang on the graphic screen (for runner crashes mainly) - updated missing functions left todo in todo.md and removed list from readme.md to make it easier to keep track of - added love.audio.getPlaybackDevice(), love.audio.getPlaybackDevices(), love.audio.setPlaybackDevice() - added love.data.ByteData:setString() - added love.filesystem.getFullCommonPath(), love.filesystem.mountFullPath(), love.filesystem.unmountFullPath(), love.filesystem.moundCommonPath(), plus optional b/t/bt params to love.filesystem.load() - added love.keyboard.isModifierActive() - added love.sound.SoundData:copy() and love.sound.SoundData:slice() - added love.graphics.Texture:isCanvas() and love.graphics.Texture:isComputeWritable() - added love.image.ImageData:isLinear(), love.image.ImageData:setLinear(), and love.image.ImageData:encode("*.exr") - added love.image.CompressedImageData:isLinear() and love.image.CompressedImageData:setLinear() - added love.system.getPreferredLocales() - added love.window.focus() and removed love.window.close() (now deprecated) --- testing/classes/TestMethod.lua | 10 ++- testing/conf.lua | 14 ++++ testing/main.lua | 2 + testing/readme.md | 9 +-- testing/resources/pop.ogg | Bin 0 -> 16438 bytes testing/resources/tone.ogg | Bin 0 -> 28105 bytes testing/tests/audio.lua | 60 +++++++++++++++++ testing/tests/data.lua | 4 ++ testing/tests/filesystem.lua | 120 +++++++++++++++++++++++++++++++-- testing/tests/graphics.lua | 14 ++++ testing/tests/image.lua | 22 +++++- testing/tests/keyboard.lua | 13 ++++ testing/tests/sound.lua | 12 ++++ testing/tests/system.lua | 8 +++ testing/tests/window.lua | 22 ++---- testing/todo.md | 40 +++++++++++ 16 files changed, 317 insertions(+), 33 deletions(-) create mode 100644 testing/resources/pop.ogg create mode 100644 testing/resources/tone.ogg create mode 100644 testing/todo.md diff --git a/testing/classes/TestMethod.lua b/testing/classes/TestMethod.lua index f4f8688d6..2061a8187 100644 --- a/testing/classes/TestMethod.lua +++ b/testing/classes/TestMethod.lua @@ -367,11 +367,19 @@ TestMethod = { end, + -- @method - TestMethod:waitFrames() + -- @desc - yields the method for x amount of frames + -- @param {number} frames - no. frames to wait + -- @return {nil} waitFrames = function(self, frames) - for i=1,frames do coroutine.yield() end + for _=1,frames do coroutine.yield() end end, + -- @method - TestMethod:waitSeconds() + -- @desc - yields the method for x amount of seconds + -- @param {number} seconds - no. seconds to wait + -- @return {nil} waitSeconds = function(self, seconds) local start = love.timer.getTime() while love.timer.getTime() < start + seconds do diff --git a/testing/conf.lua b/testing/conf.lua index 787650a49..79e5f16d8 100644 --- a/testing/conf.lua +++ b/testing/conf.lua @@ -1,4 +1,7 @@ +print("conf.lua") + function love.conf(t) + print("love.conf") t.console = true t.window.name = 'love.test' t.window.width = 360 @@ -8,3 +11,14 @@ function love.conf(t) t.window.stencil = true t.renderers = {"opengl"} end + +-- custom crash message here to catch anything that might occur with modules +-- loading before we hit main.lua +local function error_printer(msg, layer) + print((debug.traceback("Error: " .. tostring(msg), 1+(layer or 1)):gsub("\n[^\n]+$", ""))) +end +function love.errorhandler(msg) + msg = tostring(msg) + error_printer(msg, 2) + os.exit(1) +end diff --git a/testing/main.lua b/testing/main.lua index 6c7b26165..ca2d71608 100644 --- a/testing/main.lua +++ b/testing/main.lua @@ -1,3 +1,5 @@ +print('main.lua') + -- load test objs require('classes.TestSuite') require('classes.TestModule') diff --git a/testing/readme.md b/testing/readme.md index dab1cd7cb..9b328023d 100644 --- a/testing/readme.md +++ b/testing/readme.md @@ -114,14 +114,7 @@ For sanity-checking, if it's currently not covered or it's not possible to test ## Todo If you would like to contribute to the test suite please raise a PR with the main [love-test](https://github.com/ellraiser/love-test) repo. -The following items are all the things still outstanding, expanding on any existing tests is also very welcome! -- [ ] check for any 12.0 methods in the changelog not yet covered in the test suite -- [ ] add BMfont alt. tests for font class tests (Rasterizer + GlyphData) -- [ ] graphics.isCompressed() should have an example of all compressed files -- [ ] graphics.Mesh should have some graphical tests ideally to check vertex settings w/ shaders -- [ ] ability to test loading different combinations of modules if needed -- [ ] more scenario based tests similar to some of the obj class tests -- [ ] performance tests? need to discuss what + how +There is a list of outstanding methods that require test coverage in `todo.md`, expanding on any existing tests is also very welcome! --- diff --git a/testing/resources/pop.ogg b/testing/resources/pop.ogg new file mode 100644 index 0000000000000000000000000000000000000000..fb0a82a7b44207780cf5fa2500e3c8ca7312dcb8 GIT binary patch literal 16438 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 DK%0s{ literal 0 HcmV?d00001 diff --git a/testing/resources/tone.ogg b/testing/resources/tone.ogg new file mode 100644 index 0000000000000000000000000000000000000000..1e7156e479d6bef7e196b6c22e098ea043c9620e GIT binary patch literal 28105 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

?E6D zAgUz@t)wuW^{og)fIRfO$Vy0N^v0YW0aw&OQPRM+oFf@~>tMRy%AImv?6b&y^&IcEGF zmQDi+Bua@G1n+U*4ubaQA0YWFzI5;!3`7B8{;{A0qVPJIITrDOs|I~E9o)SihT`Qw z{j*FQ@MYMZ(`DjZZmOb)Fl3d`W4(GgQv@tr`nbY5K%k3hq>L&!o>KtH{BT3Tr8?V; zy*zZj8}7RtMb+s3@p&(rcf7khezu@iy&{EXLgpNQZrz%gs-weJoHTeGz2vV=qi@-- zX9}*+c4llJ0}pMZ!-}df`_uJLI9P{m{IjO~?d7;HbvLqP5yfXcQmuqNL~r9A(A(e+ zfnUa-b}x*yDVr3OBit%|vK#{Ije(jTl{wuBeHR|kEg;K!HRaR*4*iHTdbLtz8%(p| zWQ2z;HzI7%l`w&!G{BA{qv0-%K8P29(@wri9wS4x6rxN+1an0%Y2}zeGO+}_bZi&h zC=E|8PF*~xDcFh1h3pT_(z<(}{#nlZ{_cJ^4a?VMYvh}@M4wnYNp$tYWO=7D+xENb z&{t?=&`<;quGr3nz2nVNrKnk?_QsmOb0dDOb8Zr9{FfDB!1=a?CGPm(>ZoCSKp1A8 z0=uRZVhyB#<6sj`kin3C_#jQLFb{1fN|kc|P;blyJS=Q2iPp}TDWyjdBkaZpl7J+< z?nWnP9?`*ZiH;$|x=64EA)^6D?v)RVj8VXC#QAACr=fl{vh@kClQFT2FS}_h4=@y& z)!^@vb^D8F!Toecrhi%)GDxc`vAhcx0u+(P(MmF734$}nSiIoyFWH$l~ zfvD-CjoW+xJ$B{eh&MhEF_SBSM1bW~f8>OG*fF`MTV9ZUgAd16rSkSqB1psiw z640A-QD1ta`nW zz2_d(Kl3grjSQ9!9ERAH+!sns>ymMAawjQb(9f{X6%TMhU>8)sZG zj=re{ef&m+OXu^N9Fb0x4ElCa0xRb;RpO~hFOpgZqni3pf*PA)946m%U{ zar{`^-lKrd1f9k)NFqfJwCT}B*LehSja)|+vU5n>J(Kx^G%PtpH;L^>%}mVuKAs=Fr8QpuM;LA}xTnJN>%pK+HSP7S_Z_BpAnW#qkv&pO ziu|a*-{92R>wWsOW?<2Vi}kRwbYQ> z(@j9#KdVN>1#T5$S8@;VH>!Js{4_up>%?3&dE>e`5@$Jsxf9&kUDK}KWqNR7@+pN6 zt$=pgWYcm>!*I8)sf!2xN{IJb_x#e%5=L$J!7F(`@>TU#`rmhyc;!F1=GOQk`Loy@ z`Qh>^qJXk(*2XiZIWJ=fum8LGk3w>k$aM%z%JYznJlayj5&;}LSU`g5B3wKyp`3|V zm)AxB4^Fs1ym;r^nUJu}Pz9N{|P+o3?&~@sDd5N}lKO)yPt{i+ zJ{fUB61!?yvAu)ME}h`M;*&`?x1YLw_1?uNVb7jFYxAn#_waSxu_r6|svpY8HL7ya zPHI2=igq2_?*o&+x-Zgt9-mwI)mp7;r`dkTJF@wyQm6)*)-EQw%Miy?qRW%mhIpL} zby^ZbOG>mR01Sc^&1(oa2?>TgIF1uAJ{z6~LU15&>;9|L1i>&^?Y?*QFAh(R%+%Gr z*OQ_HChu&a7UE(Kd{Cnz9jb2m1qlei>U}*4|eY zA`?|w`l<2E0_;LoQcB13tR$Ht7x+P%Nq3oAtYC>@bAf%8S#Ds5&c8}5>dhhH{l0~r ze!BQ4Bo|HsSpS;|29@l_RDg3hzZ#B8$#=l0_)x!th@ww z=}f+uyB_p2W{ZkvR`%0U5Exw87=}~0O!FZDooY;MEwxU%GI!Gw`-}IkMR}EcpL)7A zxonf*@CvK1Yib^D?0XmI_^mnkO7GnZKl4J;R2W6E;U2q4A(KBl^tRsj&&1X0OqlxB z-qbHWE%2L@mvI*c5W9;^pFY)5`oeiE`Ok(_MPW2v=Yk>iQDfQ3H-19*mJApa;D!Tr z*k_u{1mPPP4JHEa-eadu&6KjOwc17Uo+$Fegpa!`Z`q{7?aapuaQ<6CF#%_p!7E+d zuc2ckr|@yM+vM@v&sD^nM6b}Ih0V&vDXKT;4%M2pv9p;~E1VQJpEYkO*HIZi;rHL9I)Hb!(6o7UQAV7OK zb8L*B&GOjGb##BTLnIj!=v0aX!Byu}$M zvrZzC6wZeJa3w`UoU^LKSp3SFFbm+S%i7n{&GP^$s$UdS8j}y5r>Mb1vP7nA8AkZ) zh*foIhi1P;NWJAWlWGlaKR!s?&4pj6?9TTYzSiRGrnb~A&pqx#cWI0LZKvQCR&bjX zd%&JBQ-R`^JR6^tOpP*WVRkx28NoE#P)r8l1s>T*!c>4b#y={30k9;!1gi%hH~2d` zAj>|cVb*k8i{zgB`VNjcPMq<;N*Z^L zSh*o%z-yHXJ%&;^jXT8z_Ud5Q9NxmrA%FRfndE}DiU3DTcf;0{{oHW|yFz_gN~Y7f zf^*IEozMI;qAb7_7mrw5=S?$Y`Ipso6plSn&P^TsScl%(ub}u?S|tHN1pM5=QQ+mM z_XSc2L14%LSme`y8}gEY0|)akP16ixl&~x(A}OMct1AVVW%R?9Nw!|$&N#Q*hPl}fXin$AzEl_LZsp6TUKjLZ7p_*!0EsmTNMra%=;=B@(zQ4Y*G8F>{^JNVL_nke7Y2l zGY~SLkg>Xe#a@tk>4G?r5|5qT)FHqjqgdHsGrOD$P*nuG$Z5~3vF6dY4NQ^JAQ(sLu1esdb?hc0^Ui>#x3ohnc4|GW;Q~fYmYS%PwIWFmNva;@WM`_Ub5|7W6Lp$>xzqh zKwrdv?V}A%)L$D7(}1I=b|~jIBiTb&d-$Y zR>YLyem;=(W43Fl_}9@xax#WZLt3k6Zw+1-w!Hr<;+fF;xXB8QjJuomeP8EZe*bL3 zo$4|E#6#z9-F+X{R7cXCm8@q6+oc~?u#)uOTHPMSe@|I@5)QaM9#?#QFqT-(Es0K> z94$VoR@u*cT(smLn*h&nAM8T9++g7g=%Iobg{(rcVutw&lvIJ3Mg^pG%HTA~#|fgS zki0_foV5^xpBY{9aNBDPHv>wjrYLQjtpx2vSkT+!qBJq!YbVW)Jjq068@NlxIEPg* z8wE8Tz6;7O(+MK)RJpqkBK-bl1$NJ7ZEu=i>t1;reK(_X=V!moMFV1~sZ5E_7j`Wv z-sn8TJ|Ai_*?&)`{B=dTA?a{g*HOr2kSq<=#CQ;c`Im8NY`( zJV@qux0{V&UhQU1NiCH;gLhx3s=JGY3;e5ciNksPUHI|kgr^rh^<*9cPQvoci+~Nk z#b^xhl!l_Q7ObTZSdw__hTjAkf}o_g?R5<-v|^z_TUdd9ll2r$ht7{pR^Na>>k_n{ z0zrEI`-eUf8*t`=a!e^LK5DK8D*6o%$Cq(NS2BS^RZGyvhsjow`}r3yzCZHBFNApf z)5wI{3AF9OTTwjQjmtH9<-19N$7QtlZdB1MwA^5>x;NOA*E|k97C!lrEkly>AcmMr zhJDXWjHqYZi*VMDrsS7;%3DaZ52H6 z@!2yC=$Zym^5%Yptk4bLSSBC0Uei23^x-Ct=)Uywtyea_WL6xaJp3<*0O`ZEzcu*) z_8;JJ$!;JxGTA%)dhpe&r!Qv42L_)FJ$*i2K&-ZZdN;Q-!fH}#ZePvfjstN)gOQ=r zweJ1Vr;mxM?s)p|z;s3)rC=0#KCxTEIG3FF2gMN})?vBlA-A-jA6cBx0bD3#Rt^My z0Zsg&wR}Ksm3buZ^e<*I}rjD;!YyGI+sAxg?-oqqBf+6dN%6L?$=URIaS( zONBGAY!CxA40s+~Q1{6B$Ed61tGO)!(vFVYVEho8z!npF}tm`Mx zeX-g~Y*`cQx-y~Hc+MQ^2T$^z93#yhNsv@QazFjnN8{kqp4P_c%|d)hKkLstw2iy^ z{P2lkz65^UC)&|%6C*!P$d=FUI_xufGwa>7+J>Y&bGVG5I$ST+a!ciuK!g{{I%h&6 z=W6oTI%{beQ4!A6+KmYHALKd~!cMky7X>G0&S&wju%0APB+yiNUK-{&1eu4b0#t0d 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 I{nY~g2eFQKo&W#< literal 0 HcmV?d00001 diff --git a/testing/tests/audio.lua b/testing/tests/audio.lua index 39133ab91..24eb7ea0a 100644 --- a/testing/tests/audio.lua +++ b/testing/tests/audio.lua @@ -299,6 +299,20 @@ love.test.audio.getOrientation = function(test) end +-- love.audio.getPlaybackDevice +love.test.audio.getPlaybackDevice = function(test) + test:assertNotNil(love.audio.getPlaybackDevice) + test:assertNotNil(love.audio.getPlaybackDevice()) +end + + +-- love.audio.getPlaybackDevices +love.test.audio.getPlaybackDevices = function(test) + test:assertNotNil(love.audio.getPlaybackDevices) + test:assertGreaterEqual(0, #love.audio.getPlaybackDevices(), 'check table') +end + + -- love.audio.getPosition -- @NOTE is there an expected default listener pos? love.test.audio.getPosition = function(test) @@ -442,6 +456,52 @@ love.test.audio.setOrientation = function(test) end +-- love.audio.setPlaybackDevice +love.test.audio.setPlaybackDevice = function(test) + -- check method + test:assertNotNil(love.audio.setPlaybackDevice) + -- check blank string name + local success1, msg1 = love.audio.setPlaybackDevice('') + -- check invalid name + local success2, msg2 = love.audio.setPlaybackDevice('loveFM') + -- check setting already set + local success3, msg3 = love.audio.setPlaybackDevice(love.audio.getPlaybackDevice()) -- current name + -- rn on macos all 3 return false + -- whereas linux/windows return true for blank/current, which is expected + -- as openalsoft treats blank as current + if love.system.getOS() == 'OS X' then + test:assertFalse(success1, 'check blank device fails') + test:assertFalse(success2, 'check invalid device fails') + test:assertFalse(success3, 'check existing device fails') + else + test:assertTrue(success1, 'check blank device is fine') + test:assertFalse(success2, 'check invalid device fails') + test:assertTrue(success3, 'check existing device is fine') + end + -- if other devices to play with lets set a different one + local devices = love.audio.getPlaybackDevices() + if #devices > 1 then + local another = '' + local current = love.audio.getPlaybackDevice() + for a=1,#devices do + if devices[a] ~= current then + another = devices[a] + break + end + end + if another ~= '' then + -- check setting new device + local success4, msg4 = love.audio.setPlaybackDevice(another) + test:assertTrue(success4, 'check setting different device') + -- check resetting to default + local success5, msg5 = love.audio.setPlaybackDevice() + test:assertTrue(success5, 'check resetting') + test:assertEquals(current, love.audio.getPlaybackDevice()) + end + end +end + + -- love.audio.setPosition love.test.audio.setPosition = function(test) -- check setting position vals are returned diff --git a/testing/tests/data.lua b/testing/tests/data.lua index 21b66b609..725d25f99 100644 --- a/testing/tests/data.lua +++ b/testing/tests/data.lua @@ -33,6 +33,10 @@ love.test.data.ByteData = function(test) test:assertEquals('o', byte5) end + -- check overwriting the byte data string + data:setString('love!', 5) + test:assertEquals('hellolove!', data:getString(), 'check change string') + end diff --git a/testing/tests/filesystem.lua b/testing/tests/filesystem.lua index 55e112553..c7d76e6f6 100644 --- a/testing/tests/filesystem.lua +++ b/testing/tests/filesystem.lua @@ -187,6 +187,27 @@ love.test.filesystem.getDirectoryItems = function(test) end +-- love.filesystem.getFullCommonPath +love.test.filesystem.getFullCommonPath = function(test) + -- check standard paths + local appsavedir = love.filesystem.getFullCommonPath('appsavedir') + local appdocuments = love.filesystem.getFullCommonPath('appdocuments') + local userhome = love.filesystem.getFullCommonPath('userhome') + local userappdata = love.filesystem.getFullCommonPath('userappdata') + local userdesktop = love.filesystem.getFullCommonPath('userdesktop') + local userdocuments = love.filesystem.getFullCommonPath('userdocuments') + test:assertNotNil(appsavedir) + test:assertNotNil(appdocuments) + test:assertNotNil(userhome) + test:assertNotNil(userappdata) + test:assertNotNil(userdesktop) + test:assertNotNil(userdocuments) + -- check invalid path + local ok = pcall(love.filesystem.getFullCommonPath, 'fakepath') + test:assertFalse(ok, 'check invalid common path') +end + + -- love.filesystem.getIdentity love.test.filesystem.getIdentity = function(test) -- check setting identity matches @@ -263,6 +284,7 @@ love.test.filesystem.getInfo = function(test) test:assertEquals(nil, love.filesystem.getInfo('foo/bar/file2.txt', 'directory'), 'check not directory') test:assertNotEquals(nil, love.filesystem.getInfo('foo/bar/file2.txt'), 'check info not nil') test:assertEquals(love.filesystem.getInfo('foo/bar/file2.txt').size, 5, 'check info size match') + test:assertFalse(love.filesystem.getInfo('foo/bar/file2.txt').readonly, 'check readonly') -- @TODO test modified timestamp from info.modtime? -- cleanup love.filesystem.remove('foo/bar/file2.txt') @@ -300,12 +322,16 @@ love.test.filesystem.load = function(test) love.filesystem.write('test1.lua', 'function test()\nreturn 1\nend\nreturn test()') love.filesystem.write('test2.lua', 'function test()\nreturn 1') -- check file that doesn't exist - local chunk, errormsg = love.filesystem.load('faker.lua') - test:assertEquals(nil, chunk, 'check file doesnt exist') - -- check valid lua file - chunk, errormsg = love.filesystem.load('test1.lua') - test:assertEquals(nil, errormsg, 'check no error message') - test:assertEquals(1, chunk(), 'check lua file runs') + local chunk1, errormsg1 = love.filesystem.load('faker.lua', 'b') + test:assertEquals(nil, chunk1, 'check file doesnt exist') + -- check valid lua file (text load) + local chunk2, errormsg2 = love.filesystem.load('test1.lua', 't') + test:assertEquals(nil, errormsg2, 'check no error message') + test:assertEquals(1, chunk2(), 'check lua file runs') + -- check valid lua file (any load) + local chunk4, errormsg4 = love.filesystem.load('test1.lua', 'bt') + test:assertEquals(nil, errormsg2, 'check no error message') + test:assertEquals(1, chunk4(), 'check lua file runs') -- check invalid lua file local ok, chunk, err = pcall(love.filesystem.load, 'test2.lua') test:assertFalse(ok, 'check invalid lua file') @@ -334,6 +360,88 @@ love.test.filesystem.mount = function(test) end +-- love.filesystem.mountFullPath +love.test.filesystem.mountFullPath = function(test) + -- mount something in the working directory + local mount = love.filesystem.mountFullPath(love.filesystem.getSource() .. '/tests', 'tests', 'read') + test:assertTrue(mount, 'check can mount') + -- check reading file through mounted path label + local contents, _ = love.filesystem.read('tests/audio.lua') + test:assertNotEquals(nil, contents) + local unmount = love.filesystem.unmountFullPath(love.filesystem.getSource() .. '/tests') + test:assertTrue(unmount, 'reset mount') +end + + +-- love.filesystem.unmountFullPath +love.test.filesystem.unmountFullPath = function(test) + -- try unmounting something we never mounted + local unmount1 = love.filesystem.unmountFullPath(love.filesystem.getSource() .. '/faker') + test:assertFalse(unmount1, 'check not mounted to start with') + -- mount something to unmount after + love.filesystem.mountFullPath(love.filesystem.getSource() .. '/tests', 'tests', 'read') + local unmount2 = love.filesystem.unmountFullPath(love.filesystem.getSource() .. '/tests') + test:assertTrue(unmount2, 'check unmounted') +end + + +-- love.filesystem.mountCommonPath +love.test.filesystem.mountCommonPath = function(test) + -- check if we can mount all the expected paths + local mount1 = love.filesystem.mountCommonPath('appsavedir', 'appsavedir', 'readwrite') + local mount2 = love.filesystem.mountCommonPath('appdocuments', 'appdocuments', 'readwrite') + local mount3 = love.filesystem.mountCommonPath('userhome', 'userhome', 'readwrite') + local mount4 = love.filesystem.mountCommonPath('userappdata', 'userappdata', 'readwrite') + -- userdesktop isnt valid on linux + if love.system.getOS() ~= 'Linux' then + local mount5 = love.filesystem.mountCommonPath('userdesktop', 'userdesktop', 'readwrite') + test:assertTrue(mount5, 'check mount userdesktop') + end + local mount6 = love.filesystem.mountCommonPath('userdocuments', 'userdocuments', 'readwrite') + local ok = pcall(love.filesystem.mountCommonPath, 'fakepath', 'fake', 'readwrite') + test:assertTrue(mount1, 'check mount appsavedir') + test:assertTrue(mount2, 'check mount appdocuments') + test:assertTrue(mount3, 'check mount userhome') + test:assertTrue(mount4, 'check mount userappdata') + test:assertTrue(mount6, 'check mount userdocuments') + test:assertFalse(ok, 'check mount invalid common path fails') +end + + +-- love.filesystem.unmountCommonPath +--love.test.filesystem.unmountCommonPath = function(test) +-- -- check unmounting invalid +-- local ok = pcall(love.filesystem.unmountCommonPath, 'fakepath') +-- test:assertFalse(ok, 'check unmount invalid common path') +-- -- check mounting valid paths +-- love.filesystem.mountCommonPath('appsavedir', 'appsavedir', 'read') +-- love.filesystem.mountCommonPath('appdocuments', 'appdocuments', 'read') +-- love.filesystem.mountCommonPath('userhome', 'userhome', 'read') +-- love.filesystem.mountCommonPath('userappdata', 'userappdata', 'read') +-- love.filesystem.mountCommonPath('userdesktop', 'userdesktop', 'read') +-- love.filesystem.mountCommonPath('userdocuments', 'userdocuments', 'read') +-- local unmount1 = love.filesystem.unmountCommonPath('appsavedir') +-- local unmount2 = love.filesystem.unmountCommonPath('appdocuments') +-- local unmount3 = love.filesystem.unmountCommonPath('userhome') +-- local unmount4 = love.filesystem.unmountCommonPath('userappdata') +-- local unmount5 = love.filesystem.unmountCommonPath('userdesktop') +-- local unmount6 = love.filesystem.unmountCommonPath('userdocuments') +-- test:assertTrue(unmount1, 'check unmount appsavedir') +-- test:assertTrue(unmount2, 'check unmount appdocuments') +-- test:assertTrue(unmount3, 'check unmount userhome') +-- test:assertTrue(unmount4, 'check unmount userappdata') +-- test:assertTrue(unmount5, 'check unmount userdesktop') +-- test:assertTrue(unmount6, 'check unmount userdocuments') +-- -- remount or future tests fail +-- love.filesystem.mountCommonPath('appsavedir', 'appsavedir', 'readwrite') +-- love.filesystem.mountCommonPath('appdocuments', 'appdocuments', 'readwrite') +-- love.filesystem.mountCommonPath('userhome', 'userhome', 'readwrite') +-- love.filesystem.mountCommonPath('userappdata', 'userappdata', 'readwrite') +-- love.filesystem.mountCommonPath('userdesktop', 'userdesktop', 'readwrite') +-- love.filesystem.mountCommonPath('userdocuments', 'userdocuments', 'readwrite') +--end + + -- love.filesystem.openFile -- @NOTE this is just basic nil checking, objs have their own test method love.test.filesystem.openFile = function(test) diff --git a/testing/tests/graphics.lua b/testing/tests/graphics.lua index da473da87..ae4079382 100644 --- a/testing/tests/graphics.lua +++ b/testing/tests/graphics.lua @@ -113,6 +113,8 @@ love.test.graphics.Canvas = function(test) debugname = 'testcanvas' }) test:assertObject(canvas) + test:assertTrue(canvas:isCanvas(), 'check is canvas') + test:assertFalse(canvas:isComputeWritable(), 'check not compute writable') -- check dpi test:assertEquals(love.graphics.getDPIScale(), canvas:getDPIScale(), 'check dpi scale') @@ -216,6 +218,16 @@ love.test.graphics.Canvas = function(test) dcanvas:setDepthSampleMode('equal') test:assertEquals('equal', dcanvas:getDepthSampleMode(), 'check depth sample mode set') + -- check compute writeable (wont work on opengl mac) + if love.graphics.getSupported().glsl4 then + local ccanvas = love.graphics.newCanvas(100, 100, { + type = '2d', + format = 'rgba8', + computewrite = true + }) + test:assertTrue(ccanvas:isComputeWritable()) + end + end @@ -303,6 +315,8 @@ love.test.graphics.Image = function(test) mipmaps = true }) test:assertObject(image) + test:assertFalse(image:isCanvas(), 'check not canvas') + test:assertFalse(image:isComputeWritable(), 'check not compute writable') -- check dpi test:assertEquals(love.graphics.getDPIScale(), image:getDPIScale(), 'check dpi scale') diff --git a/testing/tests/image.lua b/testing/tests/image.lua index fa9f4cbd2..7cdcc878b 100644 --- a/testing/tests/image.lua +++ b/testing/tests/image.lua @@ -32,6 +32,11 @@ love.test.image.CompressedImageData = function(test) -- check mipmap count test:assertEquals(7, idata:getMipmapCount(), 'check mipmap count') + -- check linear + test:assertFalse(idata:isLinear(), 'check not linear') + idata:setLinear(true) + test:assertTrue(idata:isLinear(), 'check now linear') + end @@ -78,12 +83,23 @@ love.test.image.ImageData = function(test) local r2, g2, b2 = idata:getPixel(25, 25) test:assertEquals(1, r2+g2+b2, 'check set to red') - -- check encoding to an image + -- check encoding to an image (png) idata:encode('png', 'test-encode.png') - local read = love.filesystem.openFile('test-encode.png', 'r') - test:assertNotNil(read) + local read1 = love.filesystem.openFile('test-encode.png', 'r') + test:assertNotNil(read1) love.filesystem.remove('test-encode.png') + -- check encoding to an image (exr) + idata:encode('png', 'test-encode.exr') + local read2 = love.filesystem.openFile('test-encode.exr', 'r') + test:assertNotNil(read2) + love.filesystem.remove('test-encode.exr') + + -- check linear + test:assertFalse(idata:isLinear(), 'check not linear') + idata:setLinear(true) + test:assertTrue(idata:isLinear(), 'check now linear') + end diff --git a/testing/tests/keyboard.lua b/testing/tests/keyboard.lua index e7a4f5630..c8f9748c9 100644 --- a/testing/tests/keyboard.lua +++ b/testing/tests/keyboard.lua @@ -64,6 +64,19 @@ love.test.keyboard.setKeyRepeat = function(test) end +-- love.keyboard.isModifierActive +love.test.keyboard.isModifierActive = function(test) + local active1 = love.keyboard.isModifierActive('numlock') + local active2 = love.keyboard.isModifierActive('capslock') + local active3 = love.keyboard.isModifierActive('scrolllock') + local active4 = love.keyboard.isModifierActive('mode') + test:assertNotNil(active1) + test:assertNotNil(active2) + test:assertNotNil(active3) + test:assertNotNil(active4) +end + + -- love.keyboard.setTextInput love.test.keyboard.setTextInput = function(test) love.keyboard.setTextInput(false) diff --git a/testing/tests/sound.lua b/testing/tests/sound.lua index 0304d0562..d5032cb30 100644 --- a/testing/tests/sound.lua +++ b/testing/tests/sound.lua @@ -80,6 +80,18 @@ love.test.sound.SoundData = function(test) sdata:setSample(0.002, 1) test:assertEquals(1, sdata:getSample(0.002), 'check setting sample manually') + -- check copying from another sound + local copy1 = love.sound.newSoundData('resources/tone.ogg') + local copy2 = love.sound.newSoundData('resources/pop.ogg') + local before = copy2:getSample(0.02) + copy2:copyFrom(copy1, 0.01, 1, 0.02) + test:assertNotEquals(before, copy2:getSample(0.02), 'check changed') + + -- check slicing + local count = math.floor(copy1:getSampleCount()/2) + local slice = copy1:slice(0, count) + test:assertEquals(count, slice:getSampleCount(), 'check slice length') + end diff --git a/testing/tests/system.lua b/testing/tests/system.lua index e8ef4229c..88912d525 100644 --- a/testing/tests/system.lua +++ b/testing/tests/system.lua @@ -29,6 +29,14 @@ love.test.system.getOS = function(test) end +-- love.system.getPreferredLocales +love.test.system.getPreferredLocales = function(test) + local locale = love.system.getPreferredLocales() + test:assertNotNil(locale) + test:assertEquals('table', type(locale), 'check returns table') +end + + -- love.system.getPowerInfo love.test.system.getPowerInfo = function(test) -- check battery state is one of the documented states diff --git a/testing/tests/window.lua b/testing/tests/window.lua index b1c993776..98cfc2f43 100644 --- a/testing/tests/window.lua +++ b/testing/tests/window.lua @@ -8,6 +8,13 @@ -------------------------------------------------------------------------------- +-- love.window.focus +love.test.window.focus = function(test) + -- cant test as doesnt return anything + test:assertEquals('function', type(love.window.focus), 'check method exists') +end + + -- love.window.fromPixels love.test.window.fromPixels = function(test) -- check dpi/pixel ratio as expected @@ -352,18 +359,3 @@ love.test.window.updateMode = function(test) resizable = true }) end - --- love.window.close --- calling love.window.close() last as it will stop the main test image drawing -love.test.window.z_close = function(test) - -- closing window should cause graphics to not be active - love.window.close() - local active = love.graphics.isActive() - test:assertFalse(active, 'check window not active') - -- should also mark the window as not open and not visible - test:assertFalse(love.window.isOpen(), 'check window closed') - test:assertFalse(love.window.isVisible(), 'check window not visible') - love.window.updateMode(360, 240) -- reset - active = love.graphics.isActive() - test:assertTrue(active, 'check window active again') -end diff --git a/testing/todo.md b/testing/todo.md new file mode 100644 index 000000000..026148b81 --- /dev/null +++ b/testing/todo.md @@ -0,0 +1,40 @@ +# TODO +These are all the outstanding methods that require test coverage, along with a few bits that still need doing / discussion. + +## General +- ability to test loading different combinations of modules if needed? +- performance tests? need to discuss what + how, might be better as a seperate thing +- check expected behaviour of mount + unmount with common path + try uncommenting love.filesystem.unmountCommonPath and you'll see the issues +- revisit love.audio.setPlaybackDevice when we update openal soft for MacOS + +## Physics +- love.physics.World:rayCastAny +- love.physics.World:rayCastClosest +- love.physics.World:getShapesInArea +- love.physics.Body:getShapes +- love.physics.Body:getShape +- love.physics.Body:hasCustomMassData + +## Graphics +- love.graphics.copyBuffer +- love.graphics.copyBufferToTexture +- love.graphics.copyTextureToBuffer +- love.graphics.readbackTexture +- love.graphics.readbackTextureAsync +- love.graphics.readbackBuffer +- love.graphics.readbackBufferAsync +- love.graphics.newComputeShader +- love.graphics.dispatchThreadgroupos +- love.graphics.dispatchIndirect +- love.graphics.newTexture +- love.graphics.drawFromShader +- love.graphics.drawFromShaderIndirect +- love.graphics.drawIndirect +- love.graphics.getQuadIndexBuffer +- love.graphics.setBlendState +- love.graphics.setOrthoProjection +- love.graphics.setPerspectiveProjection +- love.graphics.resetProjection +- Mesh:getAttachedAttributes +- Shader:hasStage From 7cc3816bec4e2d0a131f849df9d5a926cd621850 Mon Sep 17 00:00:00 2001 From: ell <77150506+ellraiser@users.noreply.github.com> Date: Wed, 28 Feb 2024 18:38:43 +0000 Subject: [PATCH 2/6] finish physics module coverage - love.physics.World:rayCastAny() - love.physics.World:rayCastClosest() - love.physics.World:getShapesInArea() - love.physics.Body:getShapes() - love.physics.Body:getShape() - love.physics.Body:hasCustomMassData() --- testing/tests/physics.lua | 13 +++++++++++++ testing/todo.md | 12 ++---------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/testing/tests/physics.lua b/testing/tests/physics.lua index 974c89a84..5e4662526 100644 --- a/testing/tests/physics.lua +++ b/testing/tests/physics.lua @@ -19,6 +19,12 @@ love.test.physics.Body = function(test) love.physics.newRectangleShape(body2, 5, 5, 10, 10) test:assertObject(body1) + -- check shapes + test:assertEquals(1, #body1:getShapes(), 'check shapes total 1') + test:assertEquals(1, #body2:getShapes(), 'check shapes total 2') + test:assertNotEquals(nil, body1:getShape(), 'check shape 1') + test:assertNotEquals(nil, body2:getShape(), 'check shape 2') + -- check body active test:assertTrue(body1:isActive(), 'check active by def') @@ -135,6 +141,7 @@ love.test.physics.Body = function(test) test:assertRange(y5, 5, 6, 'check mass data reset y') test:assertRange(mass5, 0.1, 0.2, 'check mass data reset mass') test:assertRange(inertia5, 5, 6, 'check mass data reset inertia') + test:assertFalse(body1:hasCustomMassData()) -- check position local x6, y6 = body1:getPosition() @@ -515,6 +522,10 @@ love.test.physics.World = function(test) test:assertRange(world:getBodies()[1]:getY(), 9, 11, 'check body prop change y') test:assertEquals(1, world:getBodyCount(), 'check 1 body count') + -- check shapes in world + test:assertEquals(1, #world:getShapesInArea(0, 0, 10, 10), 'check shapes in area #1') + test:assertEquals(0, #world:getShapesInArea(20, 20, 30, 30), 'check shapes in area #1') + -- check world status test:assertFalse(world:isLocked(), 'check not updating') test:assertFalse(world:isSleepingAllowed(), 'check no sleep (till brooklyn)') @@ -571,6 +582,8 @@ love.test.physics.World = function(test) return 1 end) test:assertEquals(3, shapes, 'check shapes in raycast') + test:assertEquals(world:rayCastClosest(0, 0, 200, 200), rectangle1, 'check closest raycast') + test:assertNotEquals(nil, world:rayCastAny(0, 0, 200, 200), 'check any raycast') -- change collision logic test:assertEquals(nil, world:getContactFilter(), 'check def filter') diff --git a/testing/todo.md b/testing/todo.md index 026148b81..7339d96e5 100644 --- a/testing/todo.md +++ b/testing/todo.md @@ -8,14 +8,6 @@ These are all the outstanding methods that require test coverage, along with a f try uncommenting love.filesystem.unmountCommonPath and you'll see the issues - revisit love.audio.setPlaybackDevice when we update openal soft for MacOS -## Physics -- love.physics.World:rayCastAny -- love.physics.World:rayCastClosest -- love.physics.World:getShapesInArea -- love.physics.Body:getShapes -- love.physics.Body:getShape -- love.physics.Body:hasCustomMassData - ## Graphics - love.graphics.copyBuffer - love.graphics.copyBufferToTexture @@ -36,5 +28,5 @@ These are all the outstanding methods that require test coverage, along with a f - love.graphics.setOrthoProjection - love.graphics.setPerspectiveProjection - love.graphics.resetProjection -- Mesh:getAttachedAttributes -- Shader:hasStage +- love.graphics.Mesh:getAttachedAttributes +- love.graphics.Shader:hasStage From 3dfa13e60c27a4eab3c139e7c0a609f13be5331a Mon Sep 17 00:00:00 2001 From: ell <77150506+ellraiser@users.noreply.github.com> Date: Thu, 29 Feb 2024 09:20:18 +0000 Subject: [PATCH 3/6] requested changes --- testing/conf.lua | 4 +--- testing/main.lua | 2 -- testing/tests/image.lua | 3 ++- testing/todo.md | 42 ++++++++++++++++++++--------------------- 4 files changed, 24 insertions(+), 27 deletions(-) diff --git a/testing/conf.lua b/testing/conf.lua index 79e5f16d8..3a9532780 100644 --- a/testing/conf.lua +++ b/testing/conf.lua @@ -1,5 +1,3 @@ -print("conf.lua") - function love.conf(t) print("love.conf") t.console = true @@ -20,5 +18,5 @@ end function love.errorhandler(msg) msg = tostring(msg) error_printer(msg, 2) - os.exit(1) + return nil end diff --git a/testing/main.lua b/testing/main.lua index ca2d71608..6c7b26165 100644 --- a/testing/main.lua +++ b/testing/main.lua @@ -1,5 +1,3 @@ -print('main.lua') - -- load test objs require('classes.TestSuite') require('classes.TestModule') diff --git a/testing/tests/image.lua b/testing/tests/image.lua index 7cdcc878b..db98882d4 100644 --- a/testing/tests/image.lua +++ b/testing/tests/image.lua @@ -90,7 +90,8 @@ love.test.image.ImageData = function(test) love.filesystem.remove('test-encode.png') -- check encoding to an image (exr) - idata:encode('png', 'test-encode.exr') + local edata = love.image.newImageData(100, 100, 'r16f') + edata:encode('exr', 'test-encode.exr') local read2 = love.filesystem.openFile('test-encode.exr', 'r') test:assertNotNil(read2) love.filesystem.remove('test-encode.exr') diff --git a/testing/todo.md b/testing/todo.md index 7339d96e5..e5f5789ae 100644 --- a/testing/todo.md +++ b/testing/todo.md @@ -9,24 +9,24 @@ These are all the outstanding methods that require test coverage, along with a f - revisit love.audio.setPlaybackDevice when we update openal soft for MacOS ## Graphics -- love.graphics.copyBuffer -- love.graphics.copyBufferToTexture -- love.graphics.copyTextureToBuffer -- love.graphics.readbackTexture -- love.graphics.readbackTextureAsync -- love.graphics.readbackBuffer -- love.graphics.readbackBufferAsync -- love.graphics.newComputeShader -- love.graphics.dispatchThreadgroupos -- love.graphics.dispatchIndirect -- love.graphics.newTexture -- love.graphics.drawFromShader -- love.graphics.drawFromShaderIndirect -- love.graphics.drawIndirect -- love.graphics.getQuadIndexBuffer -- love.graphics.setBlendState -- love.graphics.setOrthoProjection -- love.graphics.setPerspectiveProjection -- love.graphics.resetProjection -- love.graphics.Mesh:getAttachedAttributes -- love.graphics.Shader:hasStage +- love.graphics.copyBuffer() +- love.graphics.copyBufferToTexture() +- love.graphics.copyTextureToBuffer() +- love.graphics.readbackTexture() +- love.graphics.readbackTextureAsync() +- love.graphics.readbackBuffer() +- love.graphics.readbackBufferAsync() +- love.graphics.newComputeShader() +- love.graphics.dispatchThreadgroups() +- love.graphics.dispatchIndirect() +- love.graphics.newTexture() +- love.graphics.drawFromShader() +- love.graphics.drawFromShaderIndirect() +- love.graphics.drawIndirect() +- love.graphics.getQuadIndexBuffer() +- love.graphics.setBlendState() +- love.graphics.setOrthoProjection() +- love.graphics.setPerspectiveProjection() +- love.graphics.resetProjection() +- love.graphics.Mesh:getAttachedAttributes() +- love.graphics.Shader:hasStage() From 23bd9110ddd2af5f5ef83314022c019928a639d3 Mon Sep 17 00:00:00 2001 From: ell <77150506+ellraiser@users.noreply.github.com> Date: Thu, 29 Feb 2024 09:54:49 +0000 Subject: [PATCH 4/6] add callback variant for love.graphics.captureScreenshot --- testing/tests/graphics.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/testing/tests/graphics.lua b/testing/tests/graphics.lua index ae4079382..bc338b94d 100644 --- a/testing/tests/graphics.lua +++ b/testing/tests/graphics.lua @@ -1550,6 +1550,11 @@ love.test.graphics.captureScreenshot = function(test) -- need to wait until end of the frame for the screenshot test:assertNotNil(love.filesystem.openFile('example-screenshot.png', 'r')) love.filesystem.remove('example-screenshot.png') + -- test callback version + love.graphics.captureScreenshot(function (idata) + test:assertNotEquals(nil, idata, 'check we have image data') + end) + test:waitFrames(10) end From ced6448011ad19b8646099edadb9facf3644a007 Mon Sep 17 00:00:00 2001 From: ell <77150506+ellraiser@users.noreply.github.com> Date: Thu, 29 Feb 2024 10:17:14 +0000 Subject: [PATCH 5/6] attempt to fix opengl ES not running as ES on windows runner --- .github/workflows/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 42eadf0b2..7298d16e5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -344,8 +344,9 @@ jobs: # windows opengles tests - name: Run Tests (opengles) if: steps.vars.outputs.arch != 'ARM64' && steps.vars.outputs.compatname != '-compat' + env: + LOVE_GRAPHICS_USE_OPENGLES: 1 run: | - $ENV:LOVE_GRAPHICS_USE_OPENGLES=1 powershell.exe ./install/lovec.exe ./megasource/libs/love/testing/main.lua --runAllTests --isRunner - name: Love Test Report (opengles) id: report2 From c7e7565a3cd67b5fcd8dc8cd4c01be7cf3f061f8 Mon Sep 17 00:00:00 2001 From: ell <77150506+ellraiser@users.noreply.github.com> Date: Thu, 29 Feb 2024 17:49:24 +0000 Subject: [PATCH 6/6] indentation --- testing/conf.lua | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/testing/conf.lua b/testing/conf.lua index 3a9532780..a954b3119 100644 --- a/testing/conf.lua +++ b/testing/conf.lua @@ -13,10 +13,9 @@ end -- custom crash message here to catch anything that might occur with modules -- loading before we hit main.lua local function error_printer(msg, layer) - print((debug.traceback("Error: " .. tostring(msg), 1+(layer or 1)):gsub("\n[^\n]+$", ""))) + print((debug.traceback("Error: " .. tostring(msg), 1+(layer or 1)):gsub("\n[^\n]+$", ""))) end function love.errorhandler(msg) - msg = tostring(msg) - error_printer(msg, 2) - return nil + msg = tostring(msg) + error_printer(msg, 2) end