finished obj tests

- added physics.Contact, physics.Body, and physics.Shape obj tests
- added graphics.Mesh and graphics.ParticleSystem obj tests
- fixed some rgba tolerance needed on a couple methods
- added test conclusion to zip artifact name for quick checking on PRs
- ignored testsuite on compat mode windows builds
This commit is contained in:
ell
2023-11-20 20:05:30 +00:00
parent 1ef183c3c7
commit 825e46621e
7 changed files with 668 additions and 52 deletions
+22 -16
View File
@@ -63,6 +63,7 @@ jobs:
chmod a+x love-${{ github.sha }}.AppImage
./love-${{ github.sha }}.AppImage love2d-${{ github.sha }}/testing/main.lua --runAllTests --isRunner
- name: Love Test Report (opengl)
id: report1
uses: ellraiser/love-test-report@main
with:
name: Love Testsuite Linux
@@ -75,7 +76,7 @@ jobs:
- name: Artifact Test Output (opengl)
uses: actions/upload-artifact@v3
with:
name: test-output-linux-opengl
name: test-output-linux-opengl-${{ steps.report1.outputs.conclusion }}
path: test-output-linux-opengl.zip
# linux opengles tests
- name: Run Test Suite (opengles)
@@ -84,6 +85,7 @@ jobs:
./love-${{ github.sha }}.AppImage love2d-${{ github.sha }}/testing/main.lua --runAllTests --isRunner
- name: Love Test Report (opengles)
uses: ellraiser/love-test-report@main
id: report2
with:
name: Love Testsuite Linux
title: test-report-linux-opengles
@@ -95,7 +97,7 @@ jobs:
- name: Artifact Test Output (opengles)
uses: actions/upload-artifact@v3
with:
name: test-output-linux-opengles
name: test-output-linux-opengles-${{ steps.report2.outputs.conclusion }}
path: test-output-linux-opengles.zip
# # linux vulkan tests
# - name: Run Test Suite (vulkan)
@@ -297,23 +299,25 @@ jobs:
path: pdb/Release/*.pdb
# install mesa for graphic tests
- name: Install Mesa
if: steps.vars.outputs.arch != 'ARM64' && steps.vars.outputs.compatname != '-compat'
run: |
curl -L --output mesa.7z --url https://github.com/pal1000/mesa-dist-win/releases/download/23.2.1/mesa3d-23.2.1-release-msvc.7z
7z x mesa.7z -o*
powershell.exe mesa\systemwidedeploy.cmd 1
# build love to use for the tests
- name: Build Test Exe
if: steps.vars.outputs.arch != 'ARM64'
if: steps.vars.outputs.arch != 'ARM64' && steps.vars.outputs.compatname != '-compat'
run: cmake --build build --config Release --target install
# windows opengl tests
- name: Run Tests (opengl)
if: steps.vars.outputs.arch != 'ARM64'
if: steps.vars.outputs.arch != 'ARM64' && steps.vars.outputs.compatname != '-compat'
run: |
echo 'check dir'
ls
powershell.exe ./install/lovec.exe ./megasource/libs/love/testing/main.lua --runAllTests --isRunner
- name: Love Test Report (opengl)
if: steps.vars.outputs.arch != 'ARM64'
id: report1
if: steps.vars.outputs.arch != 'ARM64' && steps.vars.outputs.compatname != '-compat'
uses: ellraiser/love-test-report@main
with:
name: Love Testsuite Windows ${{ steps.vars.outputs.arch }} ${{ steps.vars.outputs.compatname }} (opengl)
@@ -321,23 +325,24 @@ jobs:
path: megasource/libs/love/testing/output/lovetest_runAllTests.md
token: ${{ secrets.GITHUB_TOKEN }}
- name: Zip Test Output (opengl)
if: steps.vars.outputs.arch != 'ARM64'
if: steps.vars.outputs.arch != 'ARM64' && steps.vars.outputs.compatname != '-compat'
run: |
7z a -tzip test-output-windows-${{ steps.vars.outputs.arch }}${{ steps.vars.outputs.compatname }}-opengl.zip megasource/libs/love/testing/output/
- name: Artifact Test Output (opengl)
if: steps.vars.outputs.arch != 'ARM64'
if: steps.vars.outputs.arch != 'ARM64' && steps.vars.outputs.compatname != '-compat'
uses: actions/upload-artifact@v3
with:
name: test-output-windows-${{ steps.vars.outputs.arch }}${{ steps.vars.outputs.compatname }}-opengl
path: test-output-windows-${{ steps.vars.outputs.arch }}${{ steps.vars.outputs.compatname }}-opengl.zip
name: test-output-windows-${{ steps.vars.outputs.arch }}-opengl-${{ steps.report1.outputs.conclusion }}
path: test-output-windows-${{ steps.vars.outputs.arch }}-opengl.zip
# windows opengles tests
- name: Run Tests (opengles)
if: steps.vars.outputs.arch != 'ARM64'
if: steps.vars.outputs.arch != 'ARM64' && steps.vars.outputs.compatname != '-compat'
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)
if: steps.vars.outputs.arch != 'ARM64'
id: report2
if: steps.vars.outputs.arch != 'ARM64' && steps.vars.outputs.compatname != '-compat'
uses: ellraiser/love-test-report@main
with:
name: Love Testsuite Windows ${{ steps.vars.outputs.arch }} ${{ steps.vars.outputs.compatname }} (opengles)
@@ -345,15 +350,15 @@ jobs:
path: megasource/libs/love/testing/output/lovetest_runAllTests.md
token: ${{ secrets.GITHUB_TOKEN }}
- name: Zip Test Output (opengles)
if: steps.vars.outputs.arch != 'ARM64'
if: steps.vars.outputs.arch != 'ARM64' && steps.vars.outputs.compatname != '-compat'
run: |
7z a -tzip test-output-windows-${{ steps.vars.outputs.arch }}${{ steps.vars.outputs.compatname }}-opengles.zip megasource/libs/love/testing/output/
- name: Artifact Test Output (opengles)
if: steps.vars.outputs.arch != 'ARM64'
if: steps.vars.outputs.arch != 'ARM64' && steps.vars.outputs.compatname != '-compat'
uses: actions/upload-artifact@v3
with:
name: test-output-windows-${{ steps.vars.outputs.arch }}${{ steps.vars.outputs.compatname }}-opengles
path: test-output-windows-${{ steps.vars.outputs.arch }}${{ steps.vars.outputs.compatname }}-opengles.zip
name: test-output-windows-${{ steps.vars.outputs.arch }}-opengles-${{ steps.report2.outputs.conclusion }}
path: test-output-windows-${{ steps.vars.outputs.arch }}-opengles.zip
# # install vulkan
# - name: Install Vulkan
# if: steps.vars.outputs.arch != 'ARM64'
@@ -427,6 +432,7 @@ jobs:
ls
love-macos/love.app/Contents/MacOS/love ./testing/main.lua --runAllTests --isRunner
- name: Love Test Report
id: report1
uses: ellraiser/love-test-report@main
with:
name: Love Testsuite MacOS
@@ -439,7 +445,7 @@ jobs:
- name: Artifact Test Output
uses: actions/upload-artifact@v3
with:
name: test-output-macos-opengl
name: test-output-macos-opengl-${{ steps.report1.outputs.conclusion }}
path: test-output-macos-opengl.zip
iOS-Simulator:
runs-on: macos-latest
+6 -3
View File
@@ -47,13 +47,16 @@ love.load = function(args)
}
Logo.img = love.graphics.newQuad(0, 0, 64, 64, Logo.texture)
Font = love.graphics.newFont('resources/font.ttf', 8, 'normal')
TextCommand = love.graphics.newTextBatch(Font, 'Loading...')
TextRun = love.graphics.newTextBatch(Font, '')
local txtobj = love.graphics.newTextBatch or love.graphics.newText
TextCommand = txtobj(Font, 'Loading...')
TextRun = txtobj(Font, '')
end
end
-- mount for output later
love.filesystem.mountFullPath(love.filesystem.getSource() .. "/output", "tempoutput", "readwrite")
if love.filesystem.mountFullPath then
love.filesystem.mountFullPath(love.filesystem.getSource() .. "/output", "tempoutput", "readwrite")
end
-- get all args with any comma lists split out as seperate
local arglist = {}
Binary file not shown.

After

Width:  |  Height:  |  Size: 134 B

+38 -27
View File
@@ -1,12 +1,14 @@
# Lövetest
Test suite for the [Löve](https://github.com/love2d/love) APIs, based off of [this issue](https://github.com/love2d/love/issues/1745).
Currently written for [Löve 12](https://github.com/love2d/love/tree/12.0-development), which is still in development.
Currently written for [Löve 12](https://github.com/love2d/love/tree/12.0-development), which is still in development. As such the test suite may fail if you try to run it with an older version of Löve due to it trying to call methods that don't exist.
While the test suite is part of the main Löve repo, the test suite has it's own repo [here](https://github.com/ellraiser/love-test) so that it can be used with other builds like [love-potion](https://github.com/lovebrew/lovepotion). If you would like to contribute to the test suite please raise a PR on the [love-test](https://github.com/ellraiser/love-test) repo.
---
## Features
- [x] Simple pass/fail tests in Lua with minimal setup
- [x] Simple pass/fail tests written in Lua with minimal setup
- [x] Ability to run all tests with a simple command
- [x] Ability to see how many tests are passing/failing
- [x] Ability to run a subset of tests
@@ -19,8 +21,8 @@ Currently written for [Löve 12](https://github.com/love2d/love/tree/12.0-develo
---
## Coverage
This is the status of all module tests currently.
See the **Todo** section for outstanding tests that need writing.
This is the status of all module tests.
See the **Todo** section for outstanding tasks if you want to contribute!
| Module | Done | Todo | Skip |
| ----------------- | ---- | ---- | ---- |
| 🟢 audio | 28 | 0 | 0 |
@@ -28,10 +30,10 @@ See the **Todo** section for outstanding tests that need writing.
| 🟢 event | 4 | 0 | 2 |
| 🟢 filesystem | 29 | 0 | 2 |
| 🟢 font | 7 | 0 | 0 |
| 🟡 graphics | 102 | 2 | 1 |
| 🟢 graphics | 104 | 0 | 1 |
| 🟢 image | 5 | 0 | 0 |
| 🟢 math | 20 | 0 | 0 |
| 🟡 physics | 22 | 4 | 0 |
| 🟢 physics | 26 | 0 | 0 |
| 🟢 sound | 4 | 0 | 0 |
| 🟢 system | 6 | 0 | 2 |
| 🟢 thread | 5 | 0 | 0 |
@@ -48,9 +50,9 @@ See the **Todo** section for outstanding tests that need writing.
The testsuite aims to keep things as simple as possible, and just runs all the tests inside Löve to match how they'd be used by developers in-engine.
To run the tests, download the repo and then run the main.lua as you would a Löve game, i.e:
WINDOWS: `& 'c:\Program Files\LOVE\love.exe' PATH_TO_TESTING_FOLDER --console`
MACOS: `/Applications/love.app/Contents/MacOS/love PATH_TO_TESTING_FOLDER`
LINUX: `./love.AppImage PATH_TO_TESTING_FOLDER`
WINDOWS: `& 'c:\Program Files\LOVE\love.exe' PATH_TO_TESTING_FOLDER/main.lua --console`
MACOS: `/Applications/love.app/Contents/MacOS/love PATH_TO_TESTING_FOLDER/main.lua`
LINUX: `./love.AppImage PATH_TO_TESTING_FOLDER/main.lua`
By default all tests will be run for all modules.
If you want to specify a module/s you can use:
@@ -111,32 +113,41 @@ For sanity-checking, if it's currently not covered or it's not possible to test
---
## Todo
Test classes that still need to be written:
- [ ] graphics.Mesh
- [ ] graphics.ParticleSystem
- [ ] physics.Body
- [ ] physics.Contact
- [ ] physics.Shape (this will include physics.Fixture properties)
## 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
---
## Graphics Tolerance
By default all graphic tests are run with pixel precision and 0 rgba tolerance.
However there are a couple of methods that on some platforms require some slight tolerance to allow for tiny differences in rendering.
| Test | OS | Exception | Reason |
| -------------------------- | --------- | ------------------- | ------ |
| love.graphics.drawInstanced | Windows | 1rgba tolerance | On Windows there's a couple pixels a tiny bit off, most likely due to complexity of the mesh drawn |
| love.graphics.setBlendMode | Win/Lin | 1rgba tolerance | Blendmodes have some small varience on some machines |
---
## Runner Exceptions
The automated tests through Github work for the most part however there are a few exceptions that have to be accounted for due to limitations of the VMs and the graphics emulation used.
These exceptions are either skipped, or handled by using a 1px or 1/255rgba tolerance - when run locally on real hardware, these tests pass fine at the default 0 tolerance.
These exceptions are either skipped, or handled by using a 1px or 1/255rgba tolerance - when run locally on real hardware, these tests pass fine at the default 0 tolerance.
You can specify the test suite is being run on a runner by adding the `--isRunner` flag in your workflow file, i.e.:
`& 'c:\Program Files\LOVE\love.exe' PATH_TO_TESTING_FOLDER/main.lua --console --runAllTests --isRunner`
| Test | OS | Exception | Reason |
| -------------------------- | --------- | ------------------- | ------ |
| love.graphics.points | MacOS | 1px tolerance | Points are offset by 1,1 when drawn |
| love.graphics.setWireframe | MacOS | 1px tolerance | Wireframes are offset by 1,1 when drawn |
| love.graphica.arc | MacOS | Skipped | Arc curves are drawn slightly off at really low scale |
| love.graphics.setLineStyle | Linux | 1rgba tolerance | Rough lines blend differently with the background rgba |
| love.audio.RecordingDevice | All | Skipped | Recording devices can't be emulated on runners |
---
## Future
- [ ] add BMfont alts for font class tests (Rasterizer + GlyphData)
- [ ] graphics.isCompressed() should have an example of all compressed files
- [ ] ability to test loading different combinations of modules
- [ ] performance tests?
| love.graphics.setLineStyle | Linux | 1rgba tolerance | 'Rough' lines blend differently with the background rgba |
| love.audio.RecordingDevice | All | Skipped | Recording devices can't be emulated on runners |
Binary file not shown.

After

Width:  |  Height:  |  Size: 81 B

+284 -2
View File
@@ -239,13 +239,291 @@ end
-- Mesh (love.graphics.newMesh)
love.test.graphics.Mesh = function(test)
test:skipTest('test class needs writing')
-- create 2d mesh with pretty colors
local image = love.graphics.newImage('resources/love.png')
local vertices = {
{ 0, 0, 0, 0, 1, 0, 0 },
{ image:getWidth(), 0, 1, 0, 0, 1, 0 },
{ image:getWidth(), image:getHeight(), 1, 1, 0, 0, 1 },
{ 0, image:getHeight(), 0, 1, 1, 1, 0 },
}
local mesh1 = love.graphics.newMesh(vertices, 'fan')
test:assertObject(mesh1)
-- check properties
test:assertEquals('fan', mesh1:getDrawMode(), 'check draw mode')
mesh1:setDrawMode('triangles')
test:assertEquals('triangles', mesh1:getDrawMode(), 'check draw mode set')
local min, max = mesh1:getDrawRange()
test:assertEquals(nil, min, 'check draw range not set')
mesh1:setDrawRange(1, 10)
min, max = mesh1:getDrawRange()
test:assertEquals(1, min, 'check draw range set min')
test:assertEquals(10, max, 'check draw range set max')
test:assertEquals(nil, mesh1:getTexture(), 'check no texture')
mesh1:setTexture(image)
test:assertEquals(image:getHeight(), mesh1:getTexture():getHeight(), 'check texture match w')
test:assertEquals(image:getWidth(), mesh1:getTexture():getWidth(), 'check texture match h')
test:assertEquals(4, mesh1:getVertexCount(), 'check vertex count')
local format = mesh1:getVertexFormat()
test:assertEquals('floatvec2', format[2][2], 'check def vertex format 2')
test:assertEquals('VertexColor', format[3][1], 'check def vertex format 3')
-- check attributes
test:assertEquals(true, mesh1:isAttributeEnabled('VertexPosition'), 'check def attribute VertexPosition')
test:assertEquals(true, mesh1:isAttributeEnabled('VertexTexCoord'), 'check def attribute VertexTexCoord')
test:assertEquals(true, mesh1:isAttributeEnabled('VertexColor'), 'check def attribute VertexColor')
mesh1:setAttributeEnabled('VertexPosition', false)
mesh1:setAttributeEnabled('VertexTexCoord', false)
mesh1:setAttributeEnabled('VertexColor', false)
test:assertEquals(false, mesh1:isAttributeEnabled('VertexPosition'), 'check disable attribute VertexPosition')
test:assertEquals(false, mesh1:isAttributeEnabled('VertexTexCoord'), 'check disable attribute VertexTexCoord')
test:assertEquals(false, mesh1:isAttributeEnabled('VertexColor'), 'check disable attribute VertexColor')
-- check vertex
local x, y, u, v, r, g, b, a = mesh1:getVertex(1)
test:assertEquals(0, x, 'check vertex props x')
test:assertEquals(0, y, 'check vertex props y')
test:assertEquals(0, u, 'check vertex props u')
test:assertEquals(0, v, 'check vertex props v')
test:assertEquals(1, r, 'check vertex props r')
test:assertEquals(0, g, 'check vertex props g')
test:assertEquals(0, b, 'check vertex props b')
test:assertEquals(1, a, 'check vertex props a')
mesh1:setVertex(2, image:getWidth(), 0, 1, 0, 0, 1, 1, 1)
x, y, u, v, r, g, b, a = mesh1:getVertex(2)
test:assertEquals(image:getWidth(), x, 'check changed vertex props x')
test:assertEquals(0, y, 'check changed vertex props y')
test:assertEquals(1, u, 'check changed vertex props u')
test:assertEquals(0, v, 'check changed vertex props v')
test:assertEquals(0, r, 'check changed vertex props r')
test:assertEquals(1, g, 'check changed vertex props g')
test:assertEquals(1, b, 'check changed vertex props b')
test:assertEquals(1, a, 'check changed vertex props a')
r, g, b, a = mesh1:getVertexAttribute(3, 3)
test:assertEquals(1, b, 'check specific vertex color')
mesh1:setVertexAttribute(4, 3, 1, 0, 1)
r, g, b, a = mesh1:getVertexAttribute(4, 3)
test:assertEquals(0, g, 'check changed vertex color')
-- change vertices
mesh1:setVertices(vertices)
r, g, b, a = mesh1:getVertexAttribute(4, 3)
x, y, u, v, r, g, b, a = mesh1:getVertex(2)
test:assertEquals(1, g, 'check reset vertex color 1')
test:assertEquals(0, b, 'check reset vertex color 2')
local vmap = mesh1:getVertexMap()
test:assertEquals(nil, vmap, 'check no map by def')
mesh1:setVertexMap({4, 1, 2, 3})
vmap = mesh1:getVertexMap()
test:assertEquals(4, #vmap, 'check set map len')
test:assertEquals(2, vmap[3], 'check set map val')
-- custom attributes
local mesh2 = love.graphics.newMesh({
{ name = 'VertexPosition', format = 'floatvec2'},
{ name = 'VertexTexCoord', format = 'floatvec2'},
{ name = 'VertexColor', format = 'floatvec4'},
{ name = 'CustomValue1', format = 'floatvec2'},
{ name = 'CustomValue2', format = 'uint16'}
}, {
{ 0, 0, 0, 0, 1, 0, 0, 1, 2, 1, 1005 },
{ image:getWidth(), 0, 1, 0, 0, 1, 0, 0, 2, 2, 2005 },
{ image:getWidth(), image:getHeight(), 1, 1, 0, 0, 1, 0, 2, 3, 3005 },
{ 0, image:getHeight(), 0, 1, 1, 1, 0, 0, 2, 4, 4005 },
}, 'fan')
local c1, c2 = mesh2:getVertexAttribute(1, 4)
local c3 = mesh2:getVertexAttribute(1, 5)
test:assertEquals(2, c1, 'check custom attribute val 1')
test:assertEquals(1, c2, 'check custom attribute val 2')
test:assertEquals(1005, c3, 'check custom attribute val 3')
mesh1:attachAttribute('CustomValue1', mesh2)
test:assertEquals(true, mesh1:isAttributeEnabled('CustomValue1'), 'check custom attribute attached')
mesh1:detachAttribute('CustomValue1')
local obj, err = pcall(mesh1.isAttributeEnabled, mesh1, 'CustomValue1')
test:assertNotEquals(nil, err, 'check attribute detached')
mesh1:detachAttribute('VertexPosition')
test:assertEquals(true, mesh1:isAttributeEnabled('VertexPosition'), 'check cant detach def attribute')
end
-- ParticleSystem (love.graphics.newParticleSystem)
love.test.graphics.ParticleSystem = function(test)
test:skipTest('test class needs writing')
-- create new system
local image = love.graphics.newImage('resources/pixel.png')
local quad1 = love.graphics.newQuad(0, 0, 1, 1, image)
local quad2 = love.graphics.newQuad(0, 0, 1, 1, image)
local psystem = love.graphics.newParticleSystem(image, 1000)
test:assertObject(psystem)
-- check properties
psystem:start()
psystem:update(1)
test:assertEquals(true, psystem:isActive(), 'check active')
test:assertEquals(false, psystem:isPaused(), 'checked not paused by def')
test:assertEquals(false, psystem:hasRelativeRotation(), 'check rel rot def')
psystem:pause()
test:assertEquals(true, psystem:isPaused(), 'check now paused')
test:assertEquals(false, psystem:isStopped(), 'check not stopped by def')
psystem:stop()
test:assertEquals(true, psystem:isStopped(), 'check now stopped')
psystem:start()
psystem:reset()
-- need to set lifetime here or count will be 0
local min, max = psystem:getParticleLifetime()
test:assertEquals(0, min, 'check def lifetime min')
test:assertEquals(0, max, 'check def lifetime max')
psystem:setParticleLifetime(1, 2)
psystem:emit(10)
psystem:update(1)
test:assertEquals(10, psystem:getCount(), 'check added particles')
psystem:reset()
test:assertEquals(0, psystem:getCount(), 'check reset')
-- check particle get/sets
local colors = {psystem:getColors()}
test:assertEquals(1, #colors, 'check 1 color by def')
psystem:setColors(1, 1, 1, 1, 1, 0, 0, 1)
colors = {psystem:getColors()}
test:assertEquals(2, #colors, 'check set colors')
test:assertEquals(1, colors[2][1], 'check set color')
test:assertEquals(0, psystem:getDirection(), 'check def direction')
psystem:setDirection(90 * (math.pi/180))
test:assertEquals(math.floor(math.pi/2*100), math.floor(psystem:getDirection()*100), 'check set direction')
psystem:setEmissionArea('normal', 100, 50)
psystem:setEmissionArea('ellipse', 100, 50)
psystem:setEmissionArea('borderellipse', 100, 50)
psystem:setEmissionArea('borderrectangle', 100, 50)
psystem:setEmissionArea('none', 100, 50)
psystem:setEmissionArea('uniform', 100, 50)
local dist, dx, dy, angle, rel = psystem:getEmissionArea()
test:assertEquals('uniform', dist, 'check emission area dist')
test:assertEquals(100, dx, 'check emission area dx')
test:assertEquals(50, dy, 'check emission area dy')
test:assertEquals(0, angle, 'check emission area angle')
test:assertEquals(false, rel, 'check emission area rel')
test:assertEquals(0, psystem:getEmissionRate(), 'check def emission rate')
psystem:setEmissionRate(1)
test:assertEquals(1, psystem:getEmissionRate(), 'check changed emission rate')
test:assertEquals(-1, psystem:getEmitterLifetime(), 'check def emitter life')
psystem:setEmitterLifetime(10)
test:assertEquals(10, psystem:getEmitterLifetime(), 'check changed emitter life')
test:assertEquals('top', psystem:getInsertMode(), 'check def insert mode')
psystem:setInsertMode('bottom')
psystem:setInsertMode('random')
test:assertEquals('random', psystem:getInsertMode(), 'check change insert mode')
local xmin, ymin, xmax, ymax = psystem:getLinearAcceleration()
test:assertEquals(0, xmin, 'check def lin acceleration xmin')
test:assertEquals(0, ymin, 'check def lin acceleration ymin')
test:assertEquals(0, xmax, 'check def lin acceleration xmax')
test:assertEquals(0, ymax, 'check def lin acceleration ymax')
psystem:setLinearAcceleration(1, 2, 3, 4)
xmin, ymin, xmax, ymax = psystem:getLinearAcceleration()
test:assertEquals(1, xmin, 'check change lin acceleration xmin')
test:assertEquals(2, ymin, 'check change lin acceleration ymin')
test:assertEquals(3, xmax, 'check change lin acceleration xmax')
test:assertEquals(4, ymax, 'check change lin acceleration ymax')
min, max = psystem:getLinearDamping()
test:assertEquals(0, min, 'check def lin damping min')
test:assertEquals(0, max, 'check def lin damping max')
psystem:setLinearDamping(1, 2)
min, max = psystem:getLinearDamping()
test:assertEquals(1, min, 'check change lin damping min')
test:assertEquals(2, max, 'check change lin damping max')
local ox, oy = psystem:getOffset()
-- 0.5 cos middle of pixel image which is 1x1
test:assertEquals(0.5, ox, 'check def offset x')
test:assertEquals(0.5, oy, 'check def offset y')
psystem:setOffset(0, 10)
ox, oy = psystem:getOffset()
test:assertEquals(0, ox, 'check change offset x')
test:assertEquals(10, oy, 'check change offset y')
min, max = psystem:getParticleLifetime()
test:assertEquals(1, min, 'check p lifetime min')
test:assertEquals(2, max, 'check p lifetime max')
local x, y = psystem:getPosition()
test:assertEquals(0, x, 'check emitter x')
test:assertEquals(0, y, 'check emitter y')
psystem:setPosition(10, 12)
x, y = psystem:getPosition()
test:assertEquals(10, x, 'check set emitter x')
test:assertEquals(12, y, 'check set emitter y')
test:assertEquals(0, #psystem:getQuads(), 'check def quads')
psystem:setQuads({quad1})
psystem:setQuads(quad1, quad2)
test:assertEquals(2, #psystem:getQuads(), 'check set quads')
min, max = psystem:getRadialAcceleration()
test:assertEquals(0, min, 'check def rad accel min')
test:assertEquals(0, max, 'check def rad accel max')
psystem:setRadialAcceleration(1, 2)
min, max = psystem:getRadialAcceleration()
test:assertEquals(1, min, 'check change rad accel min')
test:assertEquals(2, max, 'check change rad accel max')
min, max = psystem:getRotation()
test:assertEquals(0, min, 'check def rot min')
test:assertEquals(0, max, 'check def rot max')
psystem:setRotation(90 * (math.pi/180), 180 * (math.pi/180))
min, max = psystem:getRotation()
test:assertEquals(math.floor(math.pi/2*100), math.floor(min*100), 'check set rot min')
test:assertEquals(math.floor(math.pi*100), math.floor(max*100), 'check set rot max')
test:assertEquals(0, psystem:getSizeVariation(), 'check def variation')
psystem:setSizeVariation(1)
test:assertEquals(1, psystem:getSizeVariation(), 'check change variation')
test:assertEquals(1, #{psystem:getSizes()}, 'check def size')
psystem:setSizes(1, 2, 4, 1, 3, 2)
local sizes = {psystem:getSizes()}
test:assertEquals(6, #sizes, 'check set sizes')
test:assertEquals(3, sizes[5], 'check set size')
min, max = psystem:getSpeed()
test:assertEquals(0, min, 'check def speed min')
test:assertEquals(0, max, 'check def speed max')
psystem:setSpeed(1, 10)
min, max = psystem:getSpeed()
test:assertEquals(1, min, 'check change speed min')
test:assertEquals(10, max, 'check change speed max')
local variation = psystem:getSpinVariation()
test:assertEquals(0, variation, 'check def spin variation')
psystem:setSpinVariation(1)
test:assertEquals(1, psystem:getSpinVariation(), 'check change spin variation')
psystem:setSpin(1, 2)
min, max = psystem:getSpin()
test:assertEquals(1, min, 'check change spin min')
test:assertEquals(2, max, 'check change spin max')
test:assertEquals(0, psystem:getSpread(), 'check def spread')
psystem:setSpread(90 * (math.pi/180))
test:assertEquals(math.floor(math.pi/2*100), math.floor(psystem:getSpread()*100), 'check change spread')
min, max = psystem:getTangentialAcceleration()
test:assertEquals(0, min, 'check def tan accel min')
test:assertEquals(0, max, 'check def tan accel max')
psystem:setTangentialAcceleration(1, 2)
min, max = psystem:getTangentialAcceleration()
test:assertEquals(1, min, 'check change tan accel min')
test:assertEquals(2, max, 'check change tan accel max')
test:assertNotEquals(nil, psystem:getTexture(), 'check texture obj')
test:assertObject(psystem:getTexture())
psystem:setTexture(love.graphics.newImage('resources/love.png'))
test:assertObject(psystem:getTexture())
-- try a graphics test!
-- hard to get exactly because of the variation but we can use some pixel
-- tolerance and volume to try and cover the randomness
local psystem2 = love.graphics.newParticleSystem(image, 5000)
psystem2:setEmissionArea('uniform', 2, 64)
psystem2:setColors(1, 0, 0, 1)
psystem2:setDirection(0 * math.pi/180)
psystem2:setEmitterLifetime(100)
psystem2:setEmissionRate(5000)
local psystem3 = psystem2:clone()
psystem3:setPosition(64, 0)
psystem3:setColors(0, 1, 0, 1)
psystem3:setDirection(180 * (math.pi/180))
psystem2:start()
psystem3:start()
psystem2:update(1)
psystem3:update(1)
local canvas = love.graphics.newCanvas(64, 64)
love.graphics.setCanvas(canvas)
love.graphics.clear(0, 0, 0, 1)
love.graphics.draw(psystem2, 0, 0)
love.graphics.draw(psystem3, 0, 0)
love.graphics.setCanvas()
-- this should result in a bunch of red pixels on the left 2px of the canvas
-- and a bunch of green pixels on the right 2px of the canvas
local imgdata = love.graphics.readbackTexture(canvas, {64, 0, 0, 0, 64, 64})
test.pixel_tolerance = 1
test:compareImg(imgdata)
end
@@ -744,6 +1022,8 @@ love.test.graphics.drawInstanced = function(test)
blue = {{63,63}},
yellow = {{0,63}}
}, 'draw instances')
-- need 1 tolerance here just cos of the amount of colors
test.rgba_tolerance = 1
test:compareImg(imgdata)
end
@@ -1518,6 +1798,8 @@ love.test.graphics.setBlendMode = function(test)
bluefade = {{0,15}}
}, 'blend mode')
love.graphics.setBlendMode('alpha', 'alphamultiply') -- reset
-- need 1rgba tolerance here on some machines
test.rgba_tolerance = 1
test:compareImg(imgdata)
end
+318 -4
View File
@@ -10,13 +10,206 @@
-- Body (love.physics.newBody)
love.test.physics.Body = function(test)
test:skipTest('test class needs writing')
-- create body
local world = love.physics.newWorld(1, 1, true)
local body1 = love.physics.newBody(world, 0, 0, 'static')
local body2 = love.physics.newBody(world, 30, 30, 'dynamic')
love.physics.newRectangleShape(body1, 5, 5, 10, 10)
love.physics.newRectangleShape(body2, 5, 5, 10, 10)
test:assertObject(body1)
-- check state properties
test:assertEquals(true, body1:isActive(), 'check active by def')
test:assertEquals(false, body1:isBullet(), 'check not bullet by def')
body1:setBullet(true)
test:assertEquals(true, body1:isBullet(), 'check set bullet')
test:assertEquals(false, body1:isFixedRotation(), 'check fix rot def')
body1:setFixedRotation(true)
test:assertEquals(true, body1:isFixedRotation(), 'check set fix rot')
test:assertEquals(true, body1:isSleepingAllowed(), 'check sleep def')
body1:setSleepingAllowed(false)
test:assertEquals(false, body1:isSleepingAllowed(), 'check set sleep')
body1:setSleepingAllowed(true)
world:update(1)
test:assertEquals(false, body1:isAwake(), 'check fell asleep')
body1:setSleepingAllowed(false)
body1:setType('dynamic')
test:assertEquals(true, body1:isAwake(), 'check waking up')
test:assertEquals(false, body1:isTouching(body2))
body2:setPosition(5, 5)
world:update(1)
test:assertEquals(true, body1:isTouching(body2))
-- check body properties
test:assertEquals(1, #body1:getContacts(), 'check contact list')
test:assertEquals(0, #body1:getJoints(), 'check joints list')
love.physics.newDistanceJoint(body1, body2, 5, 5, 10, 10, true)
test:assertEquals(1, #body1:getJoints(), 'check joints list')
local x, y = body1:getLocalCenter()
test:assertEquals(5, math.floor(x), 'check local center x')
test:assertEquals(5, math.floor(y), 'check local center y')
local lx, ly = body1:getLocalPoint(10, 10)
test:assertEquals(10, math.floor(lx), 'check local point x')
test:assertEquals(9, math.floor(ly), 'check local point y')
local lx1, ly1, lx2, ly2 = body1:getLocalPoints(0, 5, 5, 10)
test:assertEquals(0, math.floor(lx1), 'check local points x 1')
test:assertEquals(4, math.floor(ly1), 'check local points y 1')
test:assertEquals(5, math.floor(lx2), 'check local points x 2')
test:assertEquals(9, math.floor(ly2), 'check local points y 2')
local wx, wy = body1:getWorldPoint(10.4, 9)
test:assertEquals(10, math.floor(wx), 'check world point x')
test:assertEquals(10, math.floor(wy), 'check world point y')
local wx1, wy1, wx2, wy2 = body1:getWorldPoints(0.4, 4, 5.4, 9)
test:assertEquals(0, math.floor(wx1), 'check world points x 1')
test:assertEquals(5, math.floor(wy1), 'check world points y 1')
test:assertEquals(5, math.floor(wx2), 'check world points x 2')
test:assertEquals(10, math.floor(wy2), 'check world points y 2')
test:assertEquals(0, body1:getAngularDamping(), 'check angular damping')
test:assertEquals(0, body1:getAngularVelocity(), 'check angular velocity')
test:assertObject(body1:getWorld())
test:assertEquals(2, body1:getWorld():getBodyCount(), 'check world count')
local cx, cy = body1:getWorldCenter()
test:assertEquals(46, math.floor(cx*10), 'check world center x')
test:assertEquals(60, math.floor(cy*10), 'check world center y')
local vx, vy = body1:getWorldVector(5, 10)
test:assertEquals(5, vx, 'check vector x')
test:assertEquals(10, vy, 'check vector y')
test:assertEquals(555, math.floor(body1:getInertia()*100), 'check inertia')
-- check get/set properties
test:assertEquals(0, body1:getAngle(), 'check def angle')
body1:setAngle(90 * (math.pi/180))
test:assertEquals(math.floor(math.pi/2*100), math.floor(body1:getAngle()*100), 'check set angle')
test:assertEquals(1, body1:getGravityScale(), 'check def grav')
body1:setGravityScale(2)
test:assertEquals(2, body1:getGravityScale(), 'check change grav')
test:assertEquals(0, body1:getLinearDamping(), 'check def lin damping')
body1:setLinearDamping(0.1)
test:assertEquals(1, math.floor(body1:getLinearDamping()*10), 'check change lin damping')
x, y = body1:getLinearVelocity()
test:assertEquals(1, x, 'check def lin velocity x')
test:assertEquals(1, y, 'check def lin velocity y')
body1:setLinearVelocity(4, 5)
x, y = body1:getLinearVelocity()
test:assertEquals(4, x, 'check change lin velocity x')
test:assertEquals(5, y, 'check change lin velocity y')
test:assertEquals(1, math.floor(body1:getMass()*10), 'check def mass')
body1:setMass(10)
test:assertEquals(10, body1:getMass(), 'check change mass')
body1:setMassData(3, 5, 10, 1)
local x, y, mass, inertia = body1:getMassData()
test:assertEquals(3, x, 'check mass data change x')
test:assertEquals(5, y, 'check mass data change y')
test:assertEquals(10, mass, 'check mass data change mass')
test:assertEquals(340, math.floor(inertia), 'check mass data change inertia')
body1:resetMassData()
x, y, mass, inertia = body1:getMassData()
test:assertEquals(5, math.floor(x), 'check mass data reset x')
test:assertEquals(5, math.floor(y), 'check mass data reset y')
test:assertEquals(1, math.floor(mass*10), 'check mass data reset mass')
test:assertEquals(5, math.floor(inertia), 'check mass data reset inertia')
x, y = body1:getPosition()
test:assertEquals(-1, math.floor(x), 'check position x')
test:assertEquals(0, math.floor(y), 'check position y')
body1:setPosition(10, 4)
x, y = body1:getPosition()
test:assertEquals(10, math.floor(x), 'check set position x')
test:assertEquals(4, math.floor(y), 'check set position y')
test:assertEquals('dynamic', body1:getType(), 'check type match')
body1:setType('kinematic')
body1:setType('static')
test:assertEquals('static', body1:getType(), 'check type change')
test:assertEquals(nil, body1:getUserData(), 'check user data')
body1:setUserData({ love = 'cool' })
test:assertEquals('cool', body1:getUserData().love, 'check set user data')
test:assertEquals(10, body1:getX(), 'check get x')
test:assertEquals(4, body1:getY(), 'check get y')
body1:setX(0)
body1:setY(0)
test:assertEquals(0, body1:getX(), 'check get x')
test:assertEquals(0, body1:getY(), 'check get y')
-- apply some force
local vel = body2:getAngularVelocity()
test:assertEquals(0, math.floor(vel), 'check velocity before')
body2:applyAngularImpulse(10)
vel = body2:getAngularVelocity()
test:assertEquals(54, math.floor(vel*10), 'check velocity after 1')
local ang = body2:getAngle()
test:assertEquals(149, math.floor(ang*1000), 'check initial angle')
body2:applyForce(2, 3)
world:update(2)
vel = body2:getAngularVelocity()
ang = body2:getAngle()
test:assertEquals(-84, math.floor(ang*1000), 'check angle after')
test:assertEquals(124, math.floor(vel*100), 'check velocity after 2')
body2:applyLinearImpulse(-4, -59)
world:update(1)
ang = body2:getAngle()
vel = body2:getAngularVelocity()
test:assertEquals(-1572, math.floor(ang*1000), 'check angle after 2')
test:assertEquals(9, math.floor(vel*100000000), 'check velocity after 3')
body2:applyTorque(4)
world:update(2)
ang = body2:getAngle()
vel = body2:getAngularVelocity()
test:assertEquals(-912, math.floor(ang*1000), 'check angle after 3')
test:assertEquals(321, math.floor(vel*1000), 'check velocity after 4')
test:assertEquals(false, body1:isDestroyed(), 'check not destroyed')
body1:destroy()
test:assertEquals(true, body1:isDestroyed(), 'check destroyed')
end
-- Contact (love.physics.World:getContacts)
love.test.physics.Contact = function(test)
test:skipTest('test class needs writing')
local world = love.physics.newWorld(1, 1, true)
local body1 = love.physics.newBody(world, 0, 0, 'dynamic')
local body2 = love.physics.newBody(world, 10, 10, 'dynamic')
local rectangle1 = love.physics.newRectangleShape(body1, 0, 0, 10, 10)
local rectangle2 = love.physics.newRectangleShape(body2, 0, 0, 10, 10)
rectangle1:setUserData('rec1')
rectangle2:setUserData('rec2')
local collided = false
local pass = 1
world:setCallbacks(
function(shape_a, shape_b, contact)
collided = true
test:assertObject(contact)
local indexA, indexB = contact:getChildren()
test:assertEquals(1, indexA, 'check child indice a')
test:assertEquals(1, indexB, 'check child indice b')
local shapeA, shapeB = contact:getShapes()
test:assertEquals(shape_a:getUserData(), shapeA:getUserData(), 'check shape a matches')
test:assertEquals(shape_b:getUserData(), shapeB:getUserData(), 'check shape b matches')
local nx, ny = contact:getNormal()
test:assertEquals(1, nx, 'check normal x')
test:assertEquals(0, ny, 'check normal y')
local px1, py1, px2, py2 = contact:getPositions()
test:assertEquals(5, math.floor(px1), 'check collide x 1')
test:assertEquals(5, math.floor(py1), 'check collide y 1')
test:assertEquals(5, math.floor(px2), 'check collide x 2')
test:assertEquals(5, math.floor(py2), 'check collide y 2')
test:assertEquals(true, contact:isTouching(), 'check touching')
test:assertEquals(pass == 1, contact:isEnabled(), 'check enabled for pass ' .. tostring(pass))
test:assertEquals(2, math.floor(contact:getFriction()*10), 'check def friction')
contact:setFriction(0.1)
test:assertEquals(1, math.floor(contact:getFriction()*10), 'check set friction')
contact:resetFriction()
test:assertEquals(2, math.floor(contact:getFriction()*10), 'check reset friction')
test:assertEquals(0, contact:getRestitution(), 'check def restitution')
contact:setRestitution(1)
test:assertEquals(1, contact:getRestitution(), 'check set restitution')
contact:resetRestitution()
test:assertEquals(0, contact:getRestitution(), 'check reset restitution')
pass = pass + 1
end, function() end, function(shape_a, shape_b, contact)
if pass > 2 then
contact:setEnabled(false)
end
end, function() end
)
world:update(1)
test:assertEquals(true, collided, 'check bodies collided')
-- update again for enabled check
world:update(1)
test:assertEquals(2, pass, 'check ran twice')
end
@@ -52,10 +245,131 @@ love.test.physics.Joint = function(test)
end
--love.test.physics.Test1 = function(test)
-- local world = love.physics.newWorld(0, 0, false)
-- local body1 = love.physics.newBody(world, 0, 0, 'dynamic')
-- local shape1 = love.physics.newRectangleShape(body1, 5, 5, 10, 10)
-- local tlx, tly, brx, bry = shape1:getBoundingBox(1)
-- print('position:', tlx, tly, brx, bry) -- (-0.3, -0.3, 10.3, 10.3)
-- test:assertEquals(true, shape1:testPoint(5, 5), 'check point 1') -- returns false
--end
-- Shape (love.physics.newCircleShape)
-- @NOTE includes Fixture methods too now so enjoy
-- @NOTE in 12.0 fixtures have been merged into shapes
love.test.physics.Shape = function(test)
test:skipTest('test class needs writing')
-- create shape
local world = love.physics.newWorld(0, 0, false)
local body1 = love.physics.newBody(world, 0, 0, 'dynamic')
local shape1 = love.physics.newRectangleShape(body1, 5, 5, 10, 10)
test:assertObject(shape1)
-- check base properties
test:assertEquals(1, shape1:getChildCount(), 'check child count')
test:assertEquals(0, math.floor(shape1:getRadius()), 'check radius')
test:assertEquals('polygon', shape1:getType(), 'check rectangle type')
test:assertEquals(0, shape1:getBody():getX(), 'check body link')
test:assertEquals(1, shape1:getCategory(), 'check def category')
shape1:setCategory(3, 5, 6)
local categories = {shape1:getCategory()}
test:assertEquals(14, categories[1] + categories[2] + categories[3], 'check set category')
test:assertEquals(false, shape1:isSensor(), 'check sensor def')
shape1:setSensor(true)
test:assertEquals(true, shape1:isSensor(), 'check set sensor')
shape1:setSensor(false)
test:assertEquals(false, shape1:isDestroyed(), 'check not destroyed')
test:assertEquals(nil, shape1:getUserData(), 'check no user data')
shape1:setUserData({ test = 14 })
test:assertEquals(14, shape1:getUserData().test, 'check user data set')
-- check bounding box
-- polygons have an additional skin radius to help with collisions
-- so this wont be 0, 0, 10, 10 as you'd think but has an additional 0.3 padding
local topLeftX, topLeftY, bottomRightX, bottomRightY = shape1:computeAABB(0, 0, 0, 1)
local tlx, tly, brx, bry = shape1:getBoundingBox(1)
test:assertEquals(topLeftX, tlx, 'check bbox methods match tlx')
test:assertEquals(topLeftY, tly, 'check bbox methods match tly')
test:assertEquals(bottomRightX, brx, 'check bbox methods match brx')
test:assertEquals(bottomRightY, bry, 'check bbox methods match bry')
test:assertEquals(topLeftX, topLeftY, 'check bbox tl 1')
test:assertEquals(-3, math.floor(topLeftY*10), 'check bbox tl 2')
test:assertEquals(bottomRightX, bottomRightY, 'check bbox br 1')
test:assertEquals(10, math.floor(bottomRightX), 'check bbox br 2')
-- check physics props
test:assertEquals(1, shape1:getDensity(), 'check def density')
shape1:setDensity(5)
test:assertEquals(5, shape1:getDensity(), 'check set density')
local x, y, mass, inertia = shape1:getMassData()
test:assertEquals(5, math.floor(x), 'check shape mass pos x')
test:assertEquals(5, math.floor(y), 'check shape mass pos y')
test:assertEquals(5, math.floor(mass*10), 'check mass at 1 density')
test:assertEquals(0, math.floor(inertia*10), 'check intertia at 1 density')
x, y, mass, inertia = shape1:computeMass(1000)
test:assertEquals(111, math.floor(mass), 'check mass at 1000 density')
test:assertEquals(7407, math.floor(inertia), 'check intertia at 1000 density')
test:assertEquals(2, math.floor(shape1:getFriction()*10), 'check def friction')
shape1:setFriction(1)
test:assertEquals(1, shape1:getFriction(), 'check set friction')
test:assertEquals(0, shape1:getRestitution(), 'check def restitution')
shape1:setRestitution(0.5)
test:assertEquals(5, math.floor(shape1:getRestitution()*10), 'check set restitution')
-- check points
local shape2 = love.physics.newRectangleShape(body1, 5, 5, 10, 10)
tlx, tly, brx, bry = shape2:getBoundingBox(1)
test:assertEquals(true, shape2:testPoint(5, 5), 'check point 5,5')
test:assertEquals(true, shape2:testPoint(15, 15, 10, 10, 0), 'check point 15,15 after translate 10,10')
test:assertEquals(true, shape2:testPoint(15, 15, 10, 10, 90), 'check point 15,15 after translate 10,10,90')
test:assertEquals(false, shape2:testPoint(5, 5, 10, 10, 90), 'check point 5,5 after translate 10,10,90')
test:assertEquals(false, shape2:testPoint(15, 15), 'check point 15,15')
local xn, yn, fraction = shape2:rayCast(-20, -20, 20, 20, 100, 0, 0, 0, 1)
test:assertNotEquals(nil, xn, 'check ray 1 x')
test:assertNotEquals(nil, xn, 'check ray 1 y')
xn, yn, fraction = shape2:rayCast(10, 10, -150, -150, 100, 0, 0, 0, 1)
test:assertEquals(nil, xn, 'check ray 2 x')
test:assertEquals(nil, xn, 'check ray 2 y')
-- check filtering
test:assertEquals(nil, shape2:getMask(), 'check no mask')
shape2:setMask(1, 2, 3)
test:assertEquals(3, #{shape2:getMask()}, 'check set mask')
test:assertEquals(0, shape2:getGroupIndex(), 'check no index')
shape2:setGroupIndex(-1)
test:assertEquals(-1, shape2:getGroupIndex(), 'check set index')
local cat, mask, group = shape2:getFilterData()
test:assertEquals(1, cat, 'check filter cat')
test:assertEquals(65528, mask, 'check filter mask')
test:assertEquals(-1, group, 'check filter group')
-- run some collision checks using filters
shape1:destroy()
test:assertEquals(true, shape1:isDestroyed(), 'check destroyed')
shape2:destroy()
local body2 = love.physics.newBody(world, 5, 5, 'dynamic')
local shape3 = love.physics.newRectangleShape(body1, 0, 0, 10, 10)
local shape4 = love.physics.newRectangleShape(body2, 0, 0, 10, 10)
local collisions = 0
world:setCallbacks(
function() collisions = collisions + 1 end,
function() end,
function() end,
function() end
)
-- same group will always collide if the group is positive or never collide if it's negative
shape3:setGroupIndex(1)
shape4:setGroupIndex(1)
world:update(1)
test:assertEquals(1, collisions, 'check positive group collide')
shape3:setGroupIndex(-1)
shape4:setGroupIndex(-1)
body2:setPosition(20, 20); world:update(1); body2:setPosition(0, 0); world:update(1)
test:assertEquals(1, collisions, 'check negative group collide')
-- mask sets which categories this fixture should NOT collide with.
shape3:setGroupIndex(0)
shape4:setGroupIndex(0)
shape3:setCategory(2)
shape4:setMask(3)
body2:setPosition(20, 20); world:update(1); body2:setPosition(0, 0); world:update(1)
test:assertEquals(2, collisions, 'check mask collide')
shape3:setCategory(2)
shape4:setMask(2, 4, 6)
body2:setPosition(20, 20); world:update(1); body2:setPosition(0, 0); world:update(1)
test:assertEquals(2, collisions, 'check mask not collide')
end