Merge pull request #1974 from ellraiser/12.0-testsuite
basic API test suite
@@ -3,7 +3,13 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
linux-os:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
checks: write
|
||||
pull-requests: write
|
||||
env:
|
||||
ALSOFT_CONF: love2d-${{ github.sha }}/testing/resources/alsoft.conf
|
||||
DISPLAY: :99
|
||||
steps:
|
||||
- name: Update APT
|
||||
run: sudo apt-get update
|
||||
@@ -16,7 +22,8 @@ jobs:
|
||||
libgl1-mesa-dev libdbus-1-dev libudev-dev libgles2-mesa-dev \
|
||||
libegl1-mesa-dev libibus-1.0-dev fcitx-libs-dev libsamplerate0-dev \
|
||||
libsndio-dev libwayland-dev libxkbcommon-dev libdrm-dev libgbm-dev \
|
||||
libcurl4-openssl-dev
|
||||
libcurl4-openssl-dev libfuse2 wmctrl openbox mesa-vulkan-drivers \
|
||||
libvulkan1 vulkan-tools vulkan-validationlayers
|
||||
- name: Checkout love-appimage-source
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
@@ -40,6 +47,83 @@ jobs:
|
||||
run: make LOVE_BRANCH=${{ github.sha }}
|
||||
- name: Print LuaJIT branch
|
||||
run: git -C LuaJIT-v2.1 branch -v
|
||||
# start xvfb for test running
|
||||
- name: Start xvfb and openbox
|
||||
run: |
|
||||
echo "Starting XVFB on $DISPLAY"
|
||||
Xvfb $DISPLAY -screen 0, 360x240x24 &
|
||||
echo "XVFBPID=$!" >> $GITHUB_ENV
|
||||
# wait for xvfb to startup (3s is the same amount xvfb-run waits by default)
|
||||
sleep 3
|
||||
openbox &
|
||||
echo "OPENBOXPID=$!" >> $GITHUB_ENV
|
||||
# linux opengl tests
|
||||
- name: Run Test Suite (opengl)
|
||||
run: |
|
||||
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
|
||||
title: test-report-linux-opengl
|
||||
path: love2d-${{ github.sha }}/testing/output/lovetest_runAllTests.md
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Zip Test Output (opengl)
|
||||
run: |
|
||||
7z a -tzip test-output-linux-opengl.zip love2d-${{ github.sha }}/testing/output/
|
||||
- name: Artifact Test Output (opengl)
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: test-output-linux-opengl-${{ steps.report1.outputs.conclusion }}
|
||||
path: test-output-linux-opengl.zip
|
||||
# linux opengles tests
|
||||
- name: Run Test Suite (opengles)
|
||||
run: |
|
||||
export LOVE_GRAPHICS_USE_OPENGLES=1
|
||||
./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
|
||||
path: love2d-${{ github.sha }}/testing/output/lovetest_runAllTests.md
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Zip Test Output (opengles)
|
||||
run: |
|
||||
7z a -tzip test-output-linux-opengles.zip love2d-${{ github.sha }}/testing/output/
|
||||
- name: Artifact Test Output (opengles)
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: test-output-linux-opengles-${{ steps.report2.outputs.conclusion }}
|
||||
path: test-output-linux-opengles.zip
|
||||
# # linux vulkan tests
|
||||
# - name: Run Test Suite (vulkan)
|
||||
# run: |
|
||||
# export LOVE_GRAPHICS_DEBUG=1
|
||||
# ./love-${{ github.sha }}.AppImage love2d-${{ github.sha }}/testing/main.lua --runAllTests --isRunner --renderers vulkan
|
||||
# - name: Love Test Report (vulkan)
|
||||
# uses: ellraiser/love-test-report@main
|
||||
# with:
|
||||
# name: Love Testsuite Linux
|
||||
# title: test-report-linux-vulkan
|
||||
# path: love2d-${{ github.sha }}/testing/output/lovetest_runAllTests.md
|
||||
# - name: Zip Test Output (vulkan)
|
||||
# run: |
|
||||
# 7z a -tzip test-output-linux-vulkan.zip love2d-${{ github.sha }}/testing/output/
|
||||
# - name: Artifact Test Output (vulkan)
|
||||
# uses: actions/upload-artifact@v3
|
||||
# with:
|
||||
# name: test-output-linux-vulkan
|
||||
# path: test-output-linux-vulkan.zip
|
||||
- name: Stop xvfb and openbox
|
||||
# should always stop xvfb and openbox even if other steps failed
|
||||
if: always()
|
||||
run: |
|
||||
kill $XVFBPID
|
||||
kill $OPENBOXPID
|
||||
- name: Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
@@ -50,8 +134,21 @@ jobs:
|
||||
with:
|
||||
name: love-x86_64-AppImage-debug
|
||||
path: love-${{ github.sha }}.AppImage-debug.tar.gz
|
||||
- name: Check Tests Passing
|
||||
if: steps.report1.outputs.conclusion == 'failure' || steps.report2.outputs.conclusion == 'failure'
|
||||
run: |
|
||||
echo "${{ steps.report1.outputs.failed }} opengl tests failed"
|
||||
echo "${{ steps.report2.outputs.failed }} opengles tests failed"
|
||||
exit 1
|
||||
windows-os:
|
||||
runs-on: windows-latest
|
||||
permissions:
|
||||
checks: write
|
||||
pull-requests: write
|
||||
env:
|
||||
ALSOFT_CONF: megasource/libs/love/testing/resources/alsoft.conf
|
||||
VK_ICD_FILENAMES: ${{ github.workspace }}\mesa\x64\lvp_icd.x86_64.json
|
||||
VULKAN_SDK: C:/VulkanSDK/1.3.231.1
|
||||
strategy:
|
||||
matrix:
|
||||
platform: [Win32, x64, ARM64]
|
||||
@@ -206,8 +303,115 @@ jobs:
|
||||
with:
|
||||
name: love-windows-${{ steps.vars.outputs.arch }}${{ steps.vars.outputs.compatname }}-dbg
|
||||
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' && 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' && 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)
|
||||
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)
|
||||
title: test-report-windows-${{ steps.vars.outputs.arch }}${{ steps.vars.outputs.compatname }}-opengl
|
||||
path: megasource/libs/love/testing/output/lovetest_runAllTests.md
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Zip Test Output (opengl)
|
||||
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' && steps.vars.outputs.compatname != '-compat'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
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' && 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)
|
||||
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)
|
||||
title: test-report-windows-${{ steps.vars.outputs.arch }}${{ steps.vars.outputs.compatname }}-opengles
|
||||
path: megasource/libs/love/testing/output/lovetest_runAllTests.md
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Zip Test Output (opengles)
|
||||
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' && steps.vars.outputs.compatname != '-compat'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: test-output-windows-${{ steps.vars.outputs.arch }}-opengles-${{ steps.report2.outputs.conclusion }}
|
||||
path: test-output-windows-${{ steps.vars.outputs.arch }}-opengles.zip
|
||||
- name: Check Tests Passing
|
||||
if: steps.report1.outputs.conclusion == 'failure' || steps.report2.outputs.conclusion == 'failure'
|
||||
run: |
|
||||
echo "${{ steps.report1.outputs.failed }} opengl tests failed"
|
||||
echo "${{ steps.report2.outputs.failed }} opengles tests failed"
|
||||
exit 1
|
||||
# # install vulkan
|
||||
# - name: Install Vulkan
|
||||
# if: steps.vars.outputs.arch != 'ARM64'
|
||||
# run: |
|
||||
# curl -L --show-error --output VulkanSDK.exe https://sdk.lunarg.com/sdk/download/1.3.231.1/windows/VulkanSDK-1.3.231.1-Installer.exe
|
||||
# ./VulkanSDK.exe --root C:/VulkanSDK/1.3.231.1 --accept-licenses --default-answer --confirm-command install com.lunarg.vulkan.core com.lunarg.vulkan.vma
|
||||
# curl -L --show-error --output vulkan-runtime.zip https://sdk.lunarg.com/sdk/download/1.3.231.1/windows/vulkan-runtime-components.zip
|
||||
# 7z e vulkan-runtime.zip -o"C:/VulkanSDK/1.3.231.1/runtime/x64" */x64
|
||||
# copy "C:/VulkanSDK/1.3.231.1/runtime/x64/vulkan-1.dll" "mesa/x64"
|
||||
# copy "C:/VulkanSDK/1.3.231.1/runtime/x64/vulkan-1.dll" "C:/Windows/System32"
|
||||
# copy "C:/VulkanSDK/1.3.231.1/runtime/x64/vulkan-1.dll" "love-12.0-win64/love-12.0-win64"
|
||||
# reg add HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\Vulkan\Drivers /v "${{ github.workspace }}\mesa\x64\lvp_icd.x86_64.json" /t REG_DWORD /d 0
|
||||
# powershell.exe C:/VulkanSDK/1.3.231.1/runtime/x64/vulkaninfo.exe --summary
|
||||
# # windows vulkan tests
|
||||
# - name: Run Tests (vulkan)
|
||||
# if: steps.vars.outputs.arch != 'ARM64'
|
||||
# run: |
|
||||
# $ENV:LOVE_GRAPHICS_DEBUG=1
|
||||
# powershell.exe ./install/lovec.exe ./megasource/libs/love/testing/main.lua --runAllTests --isRunner --renderers vulkan
|
||||
# - name: Love Test Report (vulkan)
|
||||
# if: steps.vars.outputs.arch != 'ARM64'
|
||||
# uses: ellraiser/love-test-report@main
|
||||
# with:
|
||||
# name: Love Testsuite Windows ${{ steps.vars.outputs.arch }} ${{ steps.vars.outputs.compatname }} (vulkan)
|
||||
# title: test-report-windows-${{ steps.vars.outputs.arch }}${{ steps.vars.outputs.compatname }}-vulkan
|
||||
# path: megasource/libs/love/testing/output/lovetest_runAllTests.md
|
||||
# - name: Zip Test Output (vulkan)
|
||||
# if: steps.vars.outputs.arch != 'ARM64'
|
||||
# run: |
|
||||
# 7z a -tzip test-output-windows-${{ steps.vars.outputs.arch }}${{ steps.vars.outputs.compatname }}-vulkan.zip megasource/libs/love/testing/output/
|
||||
# - name: Artifact Test Output (vulkan)
|
||||
# if: steps.vars.outputs.arch != 'ARM64'
|
||||
# uses: actions/upload-artifact@v3
|
||||
# with:
|
||||
# name: test-output-windows-${{ steps.vars.outputs.arch }}${{ steps.vars.outputs.compatname }}-vulkan
|
||||
# path: test-output-windows-${{ steps.vars.outputs.arch }}${{ steps.vars.outputs.compatname }}-vulkan.zip
|
||||
macOS:
|
||||
runs-on: macos-latest
|
||||
permissions:
|
||||
checks: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
@@ -234,6 +438,32 @@ jobs:
|
||||
with:
|
||||
name: love-macos
|
||||
path: love-macos.zip
|
||||
# macos opengl tests (metal not supported on runners)
|
||||
- name: Run Test Suite
|
||||
run: |
|
||||
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
|
||||
title: test-report-macos
|
||||
path: testing/output/lovetest_runAllTests.md
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Zip Test Output
|
||||
run: |
|
||||
7z a -tzip test-output-macos-opengl.zip ./testing/output/
|
||||
- name: Artifact Test Output
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: test-output-macos-opengl-${{ steps.report1.outputs.conclusion }}
|
||||
path: test-output-macos-opengl.zip
|
||||
- name: Check Tests Passing
|
||||
if: steps.report1.outputs.conclusion == 'failure'
|
||||
run: |
|
||||
echo "${{ steps.report1.outputs.failed }} opengl tests failed"
|
||||
exit 1
|
||||
iOS-Simulator:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
|
||||
@@ -68,4 +68,8 @@ stamp-h1
|
||||
/src/love
|
||||
/src/tags
|
||||
.vs/
|
||||
.vscode/
|
||||
.vscode/
|
||||
/testing/output/*.xml
|
||||
/testing/output/*.html
|
||||
/testing/output/*.md
|
||||
/testing/output/actual/*.png
|
||||
|
||||
@@ -0,0 +1,540 @@
|
||||
-- @class - TestMethod
|
||||
-- @desc - used to run a specific method from a module's /test/ suite
|
||||
-- each assertion is tracked and then printed to output
|
||||
TestMethod = {
|
||||
|
||||
|
||||
-- @method - TestMethod:new()
|
||||
-- @desc - create a new TestMethod object
|
||||
-- @param {string} method - string of method name to run
|
||||
-- @param {TestMethod} testmethod - parent testmethod this test belongs to
|
||||
-- @return {table} - returns the new Test object
|
||||
new = function(self, method, testmodule)
|
||||
local test = {
|
||||
testmodule = testmodule,
|
||||
method = method,
|
||||
asserts = {},
|
||||
start = love.timer.getTime(),
|
||||
finish = 0,
|
||||
count = 0,
|
||||
passed = false,
|
||||
skipped = false,
|
||||
skipreason = '',
|
||||
rgba_tolerance = 0,
|
||||
pixel_tolerance = 0,
|
||||
fatal = '',
|
||||
message = nil,
|
||||
result = {},
|
||||
colors = {
|
||||
red = {1, 0, 0, 1},
|
||||
redpale = {1, 0.5, 0.5, 1},
|
||||
red07 = {0.7, 0, 0, 1},
|
||||
green = {0, 1, 0, 1},
|
||||
greenhalf = {0, 0.5, 0, 1},
|
||||
greenfade = {0, 1, 0, 0.5},
|
||||
blue = {0, 0, 1, 1},
|
||||
bluefade = {0, 0, 1, 0.5},
|
||||
yellow = {1, 1, 0, 1},
|
||||
pink = {1, 0, 1, 1},
|
||||
black = {0, 0, 0, 1},
|
||||
white = {1, 1, 1, 1},
|
||||
lovepink = {214/255, 86/255, 151/255, 1},
|
||||
loveblue = {83/255, 168/255, 220/255, 1}
|
||||
},
|
||||
imgs = 1,
|
||||
delay = 0,
|
||||
delayed = false,
|
||||
store = {},
|
||||
co = nil
|
||||
}
|
||||
setmetatable(test, self)
|
||||
self.__index = self
|
||||
return test
|
||||
end,
|
||||
|
||||
|
||||
-- @method - TestMethod:assertEquals()
|
||||
-- @desc - used to assert two values are equals
|
||||
-- @param {any} expected - expected value of the test
|
||||
-- @param {any} actual - actual value of the test
|
||||
-- @param {string} label - label for this test to use in exports
|
||||
-- @return {nil}
|
||||
assertEquals = function(self, expected, actual, label)
|
||||
self.count = self.count + 1
|
||||
table.insert(self.asserts, {
|
||||
key = 'assert ' .. tostring(self.count),
|
||||
passed = expected == actual,
|
||||
message = 'expected \'' .. tostring(expected) .. '\' got \'' ..
|
||||
tostring(actual) .. '\'',
|
||||
test = label or 'no label given'
|
||||
})
|
||||
end,
|
||||
|
||||
|
||||
-- @method - TestMethod:assertTrue()
|
||||
-- @desc - used to assert a value is true
|
||||
-- @param {any} value - value to test
|
||||
-- @param {string} label - label for this test to use in exports
|
||||
-- @return {nil}
|
||||
assertTrue = function(self, value, label)
|
||||
self.count = self.count + 1
|
||||
table.insert(self.asserts, {
|
||||
key = 'assert ' .. tostring(self.count),
|
||||
passed = value == true,
|
||||
message = 'expected \'true\' got \'' ..
|
||||
tostring(value) .. '\'',
|
||||
test = label or 'no label given'
|
||||
})
|
||||
end,
|
||||
|
||||
|
||||
-- @method - TestMethod:assertFalse()
|
||||
-- @desc - used to assert a value is false
|
||||
-- @param {any} value - value to test
|
||||
-- @param {string} label - label for this test to use in exports
|
||||
-- @return {nil}
|
||||
assertFalse = function(self, value, label)
|
||||
self.count = self.count + 1
|
||||
table.insert(self.asserts, {
|
||||
key = 'assert ' .. tostring(self.count),
|
||||
passed = value == false,
|
||||
message = 'expected \'false\' got \'' ..
|
||||
tostring(value) .. '\'',
|
||||
test = label or 'no label given'
|
||||
})
|
||||
end,
|
||||
|
||||
|
||||
-- @method - TestMethod:assertNotEquals()
|
||||
-- @desc - used to assert two values are not equal
|
||||
-- @param {any} expected - expected value of the test
|
||||
-- @param {any} actual - actual value of the test
|
||||
-- @param {string} label - label for this test to use in exports
|
||||
-- @return {nil}
|
||||
assertNotEquals = function(self, expected, actual, label)
|
||||
self.count = self.count + 1
|
||||
table.insert(self.asserts, {
|
||||
key = 'assert ' .. tostring(self.count),
|
||||
passed = expected ~= actual,
|
||||
message = 'avoiding \'' .. tostring(expected) .. '\' got \'' ..
|
||||
tostring(actual) .. '\'',
|
||||
test = label or 'no label given'
|
||||
})
|
||||
end,
|
||||
|
||||
|
||||
-- @method - TestMethod:assertPixels()
|
||||
-- @desc - checks a list of coloured pixels agaisnt given imgdata
|
||||
-- @param {ImageData} imgdata - image data to check
|
||||
-- @param {table} pixels - map of colors to list of pixel coords, i.e.
|
||||
-- { blue = { {1, 1}, {2, 2}, {3, 4} } }
|
||||
-- @return {nil}
|
||||
assertPixels = function(self, imgdata, pixels, label)
|
||||
for i, v in pairs(pixels) do
|
||||
local col = self.colors[i]
|
||||
local pixels = v
|
||||
for p=1,#pixels do
|
||||
local coord = pixels[p]
|
||||
local tr, tg, tb, ta = imgdata:getPixel(coord[1], coord[2])
|
||||
local compare_id = tostring(coord[1]) .. ',' .. tostring(coord[2])
|
||||
-- prevent us getting stuff like 0.501960785 for 0.5 red
|
||||
tr = math.floor((tr*10)+0.5)/10
|
||||
tg = math.floor((tg*10)+0.5)/10
|
||||
tb = math.floor((tb*10)+0.5)/10
|
||||
ta = math.floor((ta*10)+0.5)/10
|
||||
col[1] = math.floor((col[1]*10)+0.5)/10
|
||||
col[2] = math.floor((col[2]*10)+0.5)/10
|
||||
col[3] = math.floor((col[3]*10)+0.5)/10
|
||||
col[4] = math.floor((col[4]*10)+0.5)/10
|
||||
self:assertEquals(col[1], tr, 'check pixel r for ' .. i .. ' at ' .. compare_id .. '(' .. label .. ')')
|
||||
self:assertEquals(col[2], tg, 'check pixel g for ' .. i .. ' at ' .. compare_id .. '(' .. label .. ')')
|
||||
self:assertEquals(col[3], tb, 'check pixel b for ' .. i .. ' at ' .. compare_id .. '(' .. label .. ')')
|
||||
self:assertEquals(col[4], ta, 'check pixel a for ' .. i .. ' at ' .. compare_id .. '(' .. label .. ')')
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
|
||||
-- @method - TestMethod:assertRange()
|
||||
-- @desc - used to check a value is within an expected range
|
||||
-- @param {number} actual - actual value of the test
|
||||
-- @param {number} min - minimum value the actual should be >= to
|
||||
-- @param {number} max - maximum value the actual should be <= to
|
||||
-- @param {string} label - label for this test to use in exports
|
||||
-- @return {nil}
|
||||
assertRange = function(self, actual, min, max, label)
|
||||
self.count = self.count + 1
|
||||
table.insert(self.asserts, {
|
||||
key = 'assert ' .. tostring(self.count),
|
||||
passed = actual >= min and actual <= max,
|
||||
message = 'value \'' .. tostring(actual) .. '\' out of range \'' ..
|
||||
tostring(min) .. '-' .. tostring(max) .. '\'',
|
||||
test = label or 'no label given'
|
||||
})
|
||||
end,
|
||||
|
||||
|
||||
-- @method - TestMethod:assertMatch()
|
||||
-- @desc - used to check a value is within a list of values
|
||||
-- @param {number} list - list of valid values for the test
|
||||
-- @param {number} actual - actual value of the test to check is in the list
|
||||
-- @param {string} label - label for this test to use in exports
|
||||
-- @return {nil}
|
||||
assertMatch = function(self, list, actual, label)
|
||||
self.count = self.count + 1
|
||||
local found = false
|
||||
for l=1,#list do
|
||||
if list[l] == actual then found = true end;
|
||||
end
|
||||
table.insert(self.asserts, {
|
||||
key = 'assert ' .. tostring(self.count),
|
||||
passed = found == true,
|
||||
message = 'value \'' .. tostring(actual) .. '\' not found in \'' ..
|
||||
table.concat(list, ',') .. '\'',
|
||||
test = label or 'no label given'
|
||||
})
|
||||
end,
|
||||
|
||||
|
||||
-- @method - TestMethod:assertGreaterEqual()
|
||||
-- @desc - used to check a value is >= than a certain target value
|
||||
-- @param {any} target - value to check the test agaisnt
|
||||
-- @param {any} actual - actual value of the test
|
||||
-- @param {string} label - label for this test to use in exports
|
||||
-- @return {nil}
|
||||
assertGreaterEqual = function(self, target, actual, label)
|
||||
self.count = self.count + 1
|
||||
local passing = false
|
||||
if target ~= nil and actual ~= nil then
|
||||
passing = actual >= target
|
||||
end
|
||||
table.insert(self.asserts, {
|
||||
key = 'assert ' .. tostring(self.count),
|
||||
passed = passing,
|
||||
message = 'value \'' .. tostring(actual) .. '\' not >= \'' ..
|
||||
tostring(target) .. '\'',
|
||||
test = label or 'no label given'
|
||||
})
|
||||
end,
|
||||
|
||||
|
||||
-- @method - TestMethod:assertLessEqual()
|
||||
-- @desc - used to check a value is <= than a certain target value
|
||||
-- @param {any} target - value to check the test agaisnt
|
||||
-- @param {any} actual - actual value of the test
|
||||
-- @param {string} label - label for this test to use in exports
|
||||
-- @return {nil}
|
||||
assertLessEqual = function(self, target, actual, label)
|
||||
self.count = self.count + 1
|
||||
local passing = false
|
||||
if target ~= nil and actual ~= nil then
|
||||
passing = actual <= target
|
||||
end
|
||||
table.insert(self.asserts, {
|
||||
key = 'assert ' .. tostring(self.count),
|
||||
passed = passing,
|
||||
message = 'value \'' .. tostring(actual) .. '\' not <= \'' ..
|
||||
tostring(target) .. '\'',
|
||||
test = label or 'no label given'
|
||||
})
|
||||
end,
|
||||
|
||||
|
||||
-- @method - TestMethod:assertObject()
|
||||
-- @desc - used to check a table is a love object, this runs 3 seperate
|
||||
-- tests to check table has the basic properties of an object
|
||||
-- @note - actual object functionality tests have their own methods
|
||||
-- @param {table} obj - table to check is a valid love object
|
||||
-- @return {nil}
|
||||
assertObject = function(self, obj)
|
||||
self:assertNotNil(obj)
|
||||
self:assertEquals('userdata', type(obj), 'check is userdata')
|
||||
if obj ~= nil then
|
||||
self:assertNotEquals(nil, obj:type(), 'check has :type()')
|
||||
end
|
||||
end,
|
||||
|
||||
|
||||
-- @method - TestMethod:assertCoords()
|
||||
-- @desc - used to check a pair of values (usually coordinates)
|
||||
-- @param {table} obj - table to check is a valid love object
|
||||
-- @return {nil}
|
||||
assertCoords = function(self, expected, actual, label)
|
||||
self.count = self.count + 1
|
||||
local passing = false
|
||||
if expected ~= nil and actual ~= nil then
|
||||
if expected[1] == actual[1] and expected[2] == actual[2] then
|
||||
passing = true
|
||||
end
|
||||
end
|
||||
table.insert(self.asserts, {
|
||||
key = 'assert ' .. tostring(self.count),
|
||||
passed = passing,
|
||||
message = 'expected \'' .. tostring(expected[1]) .. 'x,' ..
|
||||
tostring(expected[2]) .. 'y\' got \'' ..
|
||||
tostring(actual[1]) .. 'x,' .. tostring(actual[2]) .. 'y\'',
|
||||
test = label or 'no label given'
|
||||
})
|
||||
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, err)
|
||||
self:assertNotEquals(nil, value, 'check not nil')
|
||||
if err ~= nil then
|
||||
table.insert(self.asserts, {
|
||||
key = 'assert ' .. tostring(self.count),
|
||||
passed = false,
|
||||
message = err,
|
||||
test = 'assert not nil catch'
|
||||
})
|
||||
end
|
||||
end,
|
||||
|
||||
|
||||
-- @method - TestMethod:compareImg()
|
||||
-- @desc - compares a given image to the 'expected' version, with a tolerance of
|
||||
-- 1px in any direction, and then saves it as the 'actual' version for
|
||||
-- report viewing
|
||||
-- @param {table} imgdata - imgdata to save as a png
|
||||
-- @return {nil}
|
||||
compareImg = function(self, imgdata)
|
||||
local expected = love.image.newImageData(
|
||||
'tempoutput/expected/love.test.graphics.' .. self.method .. '-' ..
|
||||
tostring(self.imgs) .. '.png'
|
||||
)
|
||||
local iw = imgdata:getWidth()-2
|
||||
local ih = imgdata:getHeight()-2
|
||||
local rgba_tolerance = self.rgba_tolerance * (1/255)
|
||||
for ix=2,iw do
|
||||
for iy=2,ih do
|
||||
local ir, ig, ib, ia = imgdata:getPixel(ix, iy)
|
||||
local points = {
|
||||
{expected:getPixel(ix, iy)}
|
||||
}
|
||||
if self.pixel_tolerance > 0 then
|
||||
table.insert(points, {expected:getPixel(ix-1, iy+1)})
|
||||
table.insert(points, {expected:getPixel(ix-1, iy)})
|
||||
table.insert(points, {expected:getPixel(ix-1, iy-1)})
|
||||
table.insert(points, {expected:getPixel(ix, iy+1)})
|
||||
table.insert(points, {expected:getPixel(ix, iy-1)})
|
||||
table.insert(points, {expected:getPixel(ix+1, iy+1)})
|
||||
table.insert(points, {expected:getPixel(ix+1, iy)})
|
||||
table.insert(points, {expected:getPixel(ix+1, iy-1)})
|
||||
end
|
||||
local has_match_r = false
|
||||
local has_match_g = false
|
||||
local has_match_b = false
|
||||
local has_match_a = false
|
||||
for t=1,#points do
|
||||
local epoint = points[t]
|
||||
if ir >= epoint[1] - rgba_tolerance and ir <= epoint[1] + rgba_tolerance then has_match_r = true; end
|
||||
if ig >= epoint[2] - rgba_tolerance and ig <= epoint[2] + rgba_tolerance then has_match_g = true; end
|
||||
if ib >= epoint[3] - rgba_tolerance and ib <= epoint[3] + rgba_tolerance then has_match_b = true; end
|
||||
if ia >= epoint[4] - rgba_tolerance and ia <= epoint[4] + rgba_tolerance then has_match_a = true; end
|
||||
end
|
||||
local matching = has_match_r and has_match_g and has_match_b and has_match_a
|
||||
local ymatch = ''
|
||||
local nmatch = ''
|
||||
if has_match_r then ymatch = ymatch .. 'r' else nmatch = nmatch .. 'r' end
|
||||
if has_match_g then ymatch = ymatch .. 'g' else nmatch = nmatch .. 'g' end
|
||||
if has_match_b then ymatch = ymatch .. 'b' else nmatch = nmatch .. 'b' end
|
||||
if has_match_a then ymatch = ymatch .. 'a' else nmatch = nmatch .. 'a' end
|
||||
local pixel = tostring(ir)..','..tostring(ig)..','..tostring(ib)..','..tostring(ia)
|
||||
self:assertEquals(true, matching, 'compare image pixel (' .. pixel .. ') at ' ..
|
||||
tostring(ix) .. ',' .. tostring(iy) .. ', matching = ' .. ymatch ..
|
||||
', not matching = ' .. nmatch .. ' (' .. self.method .. '-' .. tostring(self.imgs) .. ')'
|
||||
)
|
||||
end
|
||||
end
|
||||
local path = 'tempoutput/actual/love.test.graphics.' ..
|
||||
self.method .. '-' .. tostring(self.imgs) .. '.png'
|
||||
imgdata:encode('png', path)
|
||||
self.imgs = self.imgs + 1
|
||||
end,
|
||||
|
||||
|
||||
-- @method - TestMethod:skipTest()
|
||||
-- @desc - used to mark this test as skipped for a specific reason
|
||||
-- @param {string} reason - reason why method is being skipped
|
||||
-- @return {nil}
|
||||
skipTest = function(self, reason)
|
||||
self.skipped = true
|
||||
self.skipreason = reason
|
||||
end,
|
||||
|
||||
|
||||
waitFrames = function(self, frames)
|
||||
for i=1,frames do coroutine.yield() end
|
||||
end,
|
||||
|
||||
|
||||
-- @method - TestMethod:evaluateTest()
|
||||
-- @desc - evaluates the results of all assertions for a final restult
|
||||
-- @return {nil}
|
||||
evaluateTest = function(self)
|
||||
local failure = ''
|
||||
local failures = 0
|
||||
for a=1,#self.asserts do
|
||||
-- @TODO just return first failed assertion msg? or all?
|
||||
-- currently just shows the first assert that failed
|
||||
if self.asserts[a].passed == false and self.skipped == false then
|
||||
if failure == '' then failure = self.asserts[a] end
|
||||
failures = failures + 1
|
||||
end
|
||||
end
|
||||
if self.fatal ~= '' then failure = self.fatal end
|
||||
local passed = tostring(#self.asserts - failures)
|
||||
local total = '(' .. passed .. '/' .. tostring(#self.asserts) .. ')'
|
||||
if self.skipped == true then
|
||||
self.testmodule.skipped = self.testmodule.skipped + 1
|
||||
love.test.totals[3] = love.test.totals[3] + 1
|
||||
self.result = {
|
||||
total = '',
|
||||
result = "SKIP",
|
||||
passed = false,
|
||||
message = '(0/0) - method skipped [' .. self.skipreason .. ']'
|
||||
}
|
||||
else
|
||||
if failure == '' and #self.asserts > 0 then
|
||||
self.passed = true
|
||||
self.testmodule.passed = self.testmodule.passed + 1
|
||||
love.test.totals[1] = love.test.totals[1] + 1
|
||||
self.result = {
|
||||
total = total,
|
||||
result = 'PASS',
|
||||
passed = true,
|
||||
message = nil
|
||||
}
|
||||
else
|
||||
self.passed = false
|
||||
self.testmodule.failed = self.testmodule.failed + 1
|
||||
love.test.totals[2] = love.test.totals[2] + 1
|
||||
if #self.asserts == 0 then
|
||||
local msg = 'no asserts defined'
|
||||
if self.fatal ~= '' then msg = self.fatal end
|
||||
self.result = {
|
||||
total = total,
|
||||
result = 'FAIL',
|
||||
passed = false,
|
||||
key = 'test',
|
||||
message = msg
|
||||
}
|
||||
else
|
||||
local key = failure['key']
|
||||
if failure['test'] ~= nil then
|
||||
key = key .. ' [' .. failure['test'] .. ']'
|
||||
end
|
||||
local msg = failure['message']
|
||||
if self.fatal ~= '' then
|
||||
key = 'code'
|
||||
msg = self.fatal
|
||||
end
|
||||
self.result = {
|
||||
total = total,
|
||||
result = 'FAIL',
|
||||
passed = false,
|
||||
key = key,
|
||||
message = msg
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
self:printResult()
|
||||
end,
|
||||
|
||||
|
||||
-- @method - TestMethod:printResult()
|
||||
-- @desc - prints the result of the test to the console as well as appends
|
||||
-- the XML + HTML for the test to the testsuite output
|
||||
-- @return {nil}
|
||||
printResult = function(self)
|
||||
|
||||
-- get total timestamp
|
||||
-- @TODO make nicer, just need a 3DP ms value
|
||||
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 = UtilTimeFormat(love.timer.getTime() - self.start)
|
||||
|
||||
-- get failure/skip message for output (if any)
|
||||
local failure = ''
|
||||
local output = ''
|
||||
if self.passed == false and self.skipped == false then
|
||||
failure = '\t\t\t<failure message="' .. self.result.key .. ' ' ..
|
||||
self.result.message .. '">' .. self.result.key .. ' ' .. self.result.message .. '</failure>\n'
|
||||
output = self.result.key .. ' ' .. self.result.message
|
||||
-- append failures if any to report md
|
||||
love.test.mdfailures = love.test.mdfailures .. '> 🔴 ' .. self.method .. ' \n' ..
|
||||
'> ' .. output .. ' \n\n'
|
||||
end
|
||||
if output == '' and self.skipped == true then
|
||||
failure = '\t\t\t<skipped message="' .. self.skipreason .. '" />\n'
|
||||
output = self.skipreason
|
||||
end
|
||||
|
||||
|
||||
-- append XML for the test class result
|
||||
self.testmodule.xml = self.testmodule.xml .. '\t\t<testcase classname="' ..
|
||||
self.method .. '" name="' .. self.method .. '" assertions="' .. tostring(#self.asserts) ..
|
||||
'" time="' .. endtime .. '">\n' ..
|
||||
failure .. '\t\t</testcase>\n'
|
||||
|
||||
-- unused currently, adds a preview image for certain graphics methods to the output
|
||||
local preview = ''
|
||||
if self.testmodule.module == 'graphics' then
|
||||
local filename = 'love.test.graphics.' .. self.method
|
||||
if love.filesystem.openFile('tempoutput/actual/' .. filename .. '-1.png', 'r') then
|
||||
preview = '<div class="preview">' .. '<img src="expected/' .. filename .. '-1.png"/><p>Expected</p></div>' ..
|
||||
'<div class="preview">' .. '<img src="actual/' .. filename .. '-1.png"/><p>Actual</p></div>'
|
||||
end
|
||||
if love.filesystem.openFile('tempoutput/actual/' .. filename .. '-2.png', 'r') then
|
||||
preview = preview .. '<div class="preview">' .. '<img src="expected/' .. filename .. '-2.png"/><p>Expected</p></div>' ..
|
||||
'<div class="preview">' .. '<img src="actual/' .. filename .. '-2.png"/><p>Actual</p></div>'
|
||||
end
|
||||
if love.filesystem.openFile('tempoutput/actual/' .. filename .. '-3.png', 'r') then
|
||||
preview = preview .. '<div class="preview">' .. '<img src="expected/' .. filename .. '-3.png"/><p>Expected</p></div>' ..
|
||||
'<div class="preview">' .. '<img src="actual/' .. filename .. '-3.png"/><p>Actual</p></div>'
|
||||
end
|
||||
end
|
||||
|
||||
-- append HTML for the test class result
|
||||
local status = '🔴'
|
||||
local cls = 'red'
|
||||
if self.passed == true then status = '🟢'; cls = '' end
|
||||
if self.skipped == true then status = '🟡'; cls = '' end
|
||||
self.testmodule.html = self.testmodule.html ..
|
||||
'<tr class=" ' .. cls .. '">' ..
|
||||
'<td>' .. status .. '</td>' ..
|
||||
'<td>' .. self.method .. '</td>' ..
|
||||
'<td>' .. endtime .. 's</td>' ..
|
||||
'<td>' .. output .. preview .. '</td>' ..
|
||||
'</tr>'
|
||||
|
||||
-- add message if assert failed
|
||||
local msg = ''
|
||||
if self.result.message ~= nil and self.skipped == false then
|
||||
msg = ' - ' .. self.result.key ..
|
||||
' failed - (' .. self.result.message .. ')'
|
||||
end
|
||||
if self.skipped == true then
|
||||
msg = self.result.message
|
||||
end
|
||||
|
||||
-- log final test result to console
|
||||
-- i know its hacky but its neat soz
|
||||
local tested = 'love.' .. self.testmodule.module .. '.' .. self.method .. '()'
|
||||
local matching = string.sub(self.testmodule.spacer, string.len(tested), 40)
|
||||
self.testmodule:log(
|
||||
self.testmodule.colors[self.result.result],
|
||||
' ' .. tested .. matching,
|
||||
' ==> ' .. self.result.result .. ' - ' .. endtime .. 's ' ..
|
||||
self.result.total .. msg
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
-- @class - TestModule
|
||||
-- @desc - used to run tests for a given module, each test method will spawn
|
||||
-- a love.test.Test object
|
||||
TestModule = {
|
||||
|
||||
|
||||
-- @method - TestModule:new()
|
||||
-- @desc - create a new Suite object
|
||||
-- @param {string} module - string of love module the suite is for
|
||||
-- @return {table} - returns the new Suite object
|
||||
new = function(self, module, method)
|
||||
local testmodule = {
|
||||
time = 0,
|
||||
spacer = ' ',
|
||||
colors = {
|
||||
PASS = 'green', FAIL = 'red', SKIP = 'grey'
|
||||
},
|
||||
colormap = {
|
||||
grey = '\27[37m',
|
||||
green = '\27[32m',
|
||||
red = '\27[31m',
|
||||
yellow = '\27[33m'
|
||||
},
|
||||
xml = '',
|
||||
html = '',
|
||||
tests = {},
|
||||
running = {},
|
||||
called = {},
|
||||
passed = 0,
|
||||
failed = 0,
|
||||
skipped = 0,
|
||||
module = module,
|
||||
method = method,
|
||||
index = 1,
|
||||
start = false,
|
||||
}
|
||||
setmetatable(testmodule, self)
|
||||
self.__index = self
|
||||
return testmodule
|
||||
end,
|
||||
|
||||
|
||||
-- @method - TestModule:log()
|
||||
-- @desc - log to console with specific colors, split out to make it easier
|
||||
-- to adjust all console output across the tests
|
||||
-- @param {string} color - color key to use for the log
|
||||
-- @param {string} line - main message to write (LHS)
|
||||
-- @param {string} result - result message to write (RHS)
|
||||
-- @return {nil}
|
||||
log = function(self, color, line, result)
|
||||
if result == nil then result = '' end
|
||||
print(self.colormap[color] .. line .. result)
|
||||
end,
|
||||
|
||||
|
||||
-- @method - TestModule:runTests()
|
||||
-- @desc - starts the running of tests and sets up the list of methods to test
|
||||
-- @param {string} module - module to set for the test suite
|
||||
-- @param {string} method - specific method to test, if nil all methods tested
|
||||
-- @return {nil}
|
||||
runTests = function(self)
|
||||
self.running = {}
|
||||
self.passed = 0
|
||||
self.failed = 0
|
||||
if self.method ~= nil then
|
||||
table.insert(self.running, self.method)
|
||||
else
|
||||
for i,_ in pairs(love.test[self.module]) do
|
||||
table.insert(self.running, i)
|
||||
end
|
||||
table.sort(self.running)
|
||||
end
|
||||
self.index = 1
|
||||
self.start = true
|
||||
self:log('yellow', '\nlove.' .. self.module .. '.testmodule.start')
|
||||
end,
|
||||
|
||||
|
||||
-- @method - TestModule:printResult()
|
||||
-- @desc - prints the result of the module to the console as well as appends
|
||||
-- the XML + HTML for the test to the testsuite output
|
||||
-- @return {nil}
|
||||
printResult = function(self)
|
||||
local finaltime = UtilTimeFormat(self.time)
|
||||
local status = '🔴'
|
||||
if self.failed == 0 then status = '🟢' end
|
||||
-- add md row to main output
|
||||
love.test.mdrows = love.test.mdrows .. '| ' .. status ..
|
||||
' ' .. self.module ..
|
||||
' | ' .. tostring(self.passed) ..
|
||||
' | ' .. tostring(self.failed) ..
|
||||
' | ' .. tostring(self.skipped) ..
|
||||
' | ' .. finaltime .. 's |' .. '\n'
|
||||
-- add xml to main output
|
||||
love.test.xml = love.test.xml .. '\t<testsuite name="love.' .. self.module ..
|
||||
'" tests="' .. tostring(self.passed) ..
|
||||
'" failures="' .. tostring(self.failed) ..
|
||||
'" skipped="' .. tostring(self.skipped) ..
|
||||
'" time="' .. finaltime .. '">\n' .. self.xml .. '\t</testsuite>\n'
|
||||
-- add html to main output
|
||||
love.test.html = love.test.html .. '<h2>' .. status .. ' love.' .. self.module .. '</h2><ul class="summary">' ..
|
||||
'<li>🟢 ' .. tostring(self.passed) .. ' Tests</li>' ..
|
||||
'<li>🔴 ' .. tostring(self.failed) .. ' Failures</li>' ..
|
||||
'<li>🟡 ' .. tostring(self.skipped) .. ' Skipped</li>' ..
|
||||
'<li>' .. finaltime .. 's</li>' .. '<ul><br/><br/>' ..
|
||||
'<table><thead><tr><td width="20px"></td><td width="100px">Method</td><td width="60px">Time</td><td>Details</td></tr></thead><tbody>' ..
|
||||
self.html .. '</tbody></table>'
|
||||
-- print module results to console
|
||||
self:log('yellow', 'love.' .. self.module .. '.testmodule.end')
|
||||
local failedcol = '\27[31m'
|
||||
if self.failed == 0 then failedcol = '\27[37m' end
|
||||
self:log('green', tostring(self.passed) .. ' PASSED' .. ' || ' ..
|
||||
failedcol .. tostring(self.failed) .. ' FAILED || \27[37m' ..
|
||||
tostring(self.skipped) .. ' SKIPPED || ' .. finaltime .. 's')
|
||||
self.start = false
|
||||
self.fakequit = false
|
||||
end
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
TestSuite = {
|
||||
|
||||
|
||||
-- @method - TestSuite:new()
|
||||
-- @desc - creates a new TestSuite object that handles all the tests
|
||||
-- @return {table} - returns the new TestSuite object
|
||||
new = function(self)
|
||||
local test = {
|
||||
|
||||
-- testsuite internals
|
||||
modules = {},
|
||||
module = nil,
|
||||
test = nil,
|
||||
testcanvas = nil,
|
||||
current = 1,
|
||||
output = '',
|
||||
totals = {0, 0, 0},
|
||||
time = 0,
|
||||
xml = '',
|
||||
html = '',
|
||||
mdrows = '',
|
||||
mdfailures = '',
|
||||
delayed = nil,
|
||||
fakequit = false,
|
||||
windowmode = true,
|
||||
|
||||
-- love modules to test
|
||||
audio = {},
|
||||
data = {},
|
||||
event = {},
|
||||
filesystem = {},
|
||||
font = {},
|
||||
graphics = {},
|
||||
image = {},
|
||||
joystick = {},
|
||||
math = {},
|
||||
mouse = {},
|
||||
physics = {},
|
||||
sound = {},
|
||||
system = {},
|
||||
thread = {},
|
||||
timer = {},
|
||||
touch = {},
|
||||
video = {},
|
||||
window = {}
|
||||
|
||||
}
|
||||
setmetatable(test, self)
|
||||
self.__index = self
|
||||
return test
|
||||
end,
|
||||
|
||||
|
||||
-- @method - TestSuite:runSuite()
|
||||
-- @desc - called in love.update, runs through every method or every module
|
||||
-- @param {number} delta - delta from love.update to track time elapsed
|
||||
-- @return {nil}
|
||||
runSuite = function(self, delta)
|
||||
|
||||
-- stagger between tests
|
||||
if self.module ~= nil then
|
||||
|
||||
if self.module.start == true then
|
||||
|
||||
-- work through each test method 1 by 1
|
||||
if self.module.index <= #self.module.running then
|
||||
|
||||
-- run method once
|
||||
if self.module.called[self.module.index] == nil then
|
||||
self.module.called[self.module.index] = true
|
||||
local method = self.module.running[self.module.index]
|
||||
self.test = TestMethod:new(method, self.module)
|
||||
TextRun:set('love.' .. self.module.module .. '.' .. method)
|
||||
|
||||
self.test.co = coroutine.create(function()
|
||||
local ok, chunk, err = pcall(love.test[love.test.module.module][method], love.test.test)
|
||||
if ok == false then
|
||||
love.test.test.passed = false
|
||||
love.test.test.fatal = tostring(chunk) .. tostring(err)
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
-- once called we have a corouting, so just call resume every frame
|
||||
-- until we have finished
|
||||
else
|
||||
|
||||
-- move onto next yield if any
|
||||
-- pauses can be set with TestMethod:waitFrames(frames)
|
||||
coroutine.resume(self.test.co)
|
||||
|
||||
-- when wait finished (or no yields)
|
||||
if coroutine.status(self.test.co) == 'dead' then
|
||||
-- now we're all done evaluate the test
|
||||
local ok, chunk, err = pcall(self.test.evaluateTest, self.test)
|
||||
if ok == false then
|
||||
self.test.passed = false
|
||||
self.test.fatal = tostring(chunk) .. tostring(err)
|
||||
end
|
||||
-- save having to :release() anything we made in the last test
|
||||
collectgarbage("collect")
|
||||
-- move onto the next test
|
||||
self.module.index = self.module.index + 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- once all tests have run
|
||||
else
|
||||
|
||||
-- print module results and add to output
|
||||
self.module:printResult()
|
||||
|
||||
-- if we have more modules to go run the next one
|
||||
self.current = self.current + 1
|
||||
if #self.modules >= self.current then
|
||||
self.module = self.modules[self.current]
|
||||
self.module:runTests()
|
||||
|
||||
-- otherwise print the final results and export output
|
||||
else
|
||||
self:printResult()
|
||||
love.event.quit(0)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end,
|
||||
|
||||
|
||||
-- @method - TestSuite:printResult()
|
||||
-- @desc - prints the result of the whole test suite as well as writes
|
||||
-- the MD, XML + HTML of the testsuite output
|
||||
-- @return {nil}
|
||||
printResult = function(self)
|
||||
local finaltime = UtilTimeFormat(self.time)
|
||||
|
||||
local name, version, vendor, device = love.graphics.getRendererInfo()
|
||||
|
||||
local md = '<!-- PASSED ' .. tostring(self.totals[1]) ..
|
||||
' || FAILED ' .. tostring(self.totals[2]) ..
|
||||
' || SKIPPED ' .. tostring(self.totals[3]) ..
|
||||
' || TIME ' .. finaltime .. ' -->\n\n### Info\n' ..
|
||||
'**' .. tostring(self.totals[1] + self.totals[2] + self.totals[3]) .. '** tests were completed in **' ..
|
||||
finaltime .. 's** with **' ..
|
||||
tostring(self.totals[1]) .. '** passed, **' ..
|
||||
tostring(self.totals[2]) .. '** failed, and **' ..
|
||||
tostring(self.totals[3]) .. '** skipped\n\n' ..
|
||||
'Renderer: ' .. name .. ' | ' .. version .. ' | ' .. vendor .. ' | ' .. device .. '\n\n' ..
|
||||
'### Report\n' ..
|
||||
'| Module | Pass | Fail | Skip | Time |\n' ..
|
||||
'| --------------------- | ------ | ------ | ------- | ------ |\n' ..
|
||||
self.mdrows .. '\n### Failures\n' .. self.mdfailures
|
||||
|
||||
local xml = '<testsuites name="love.test" tests="' .. tostring(self.totals[1]) ..
|
||||
'" failures="' .. tostring(self.totals[2]) ..
|
||||
'" skipped="' .. tostring(self.totals[3]) ..
|
||||
'" time="' .. finaltime .. '">\n'
|
||||
|
||||
local status = '🔴'
|
||||
if self.totals[2] == 0 then status = '🟢' end
|
||||
local html = '<html><head><style>* { font-family: monospace; margin: 0; font-size: 11px; padding: 0; } body { margin: 50px; } h1 { padding-bottom: 10px; font-size: 13px; } h2 { padding: 20px 0 10px 0; font-size: 12px; } .summary { list-style: none; margin: 0; padding: 0; } .summary li { float: left; background: #eee; padding: 5px; margin-right: 10px; } table { background: #eee; margin-top: 10px; width: 100%; max-width: 800px; border-collapse: collapse } table thead { background: #ddd; } table th, table td { padding: 2px; } tr.red { color: red } .wrap { max-width: 800px; margin: auto; } .preview { width: 64px; height: 80px; float: left; margin-right: 10px; } .preview img { width: 100% } .preview p { text-align: center; }</style></head><body><div class="wrap"><h1>' .. status .. ' love.test</h1><ul class="summary">'
|
||||
html = html ..
|
||||
'<li>🟢 ' .. tostring(self.totals[1]) .. ' Tests</li>' ..
|
||||
'<li>🔴 ' .. tostring(self.totals[2]) .. ' Failures</li>' ..
|
||||
'<li>🟡 ' .. tostring(self.totals[3]) .. ' Skipped</li>' ..
|
||||
'<li>' .. finaltime .. 's</li></ul><br/><br/>'
|
||||
|
||||
love.filesystem.write('tempoutput/' .. self.output .. '.xml', xml .. self.xml .. '</testsuites>')
|
||||
love.filesystem.write('tempoutput/' .. self.output .. '.html', html .. self.html .. '</div></body></html>')
|
||||
love.filesystem.write('tempoutput/' .. self.output .. '.md', md)
|
||||
|
||||
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')
|
||||
|
||||
end
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
function love.conf(t)
|
||||
t.console = true
|
||||
t.window.name = 'love.test'
|
||||
t.window.width = 360
|
||||
t.window.height = 240
|
||||
t.window.resizable = true
|
||||
t.renderers = {"opengl"}
|
||||
t.modules.audio = true
|
||||
t.modules.data = true
|
||||
t.modules.event = true
|
||||
t.modules.filesystem = true
|
||||
t.modules.font = true
|
||||
t.modules.graphics = true
|
||||
t.modules.image = true
|
||||
t.modules.math = true
|
||||
t.modules.objects = true
|
||||
t.modules.physics = true
|
||||
t.modules.sound = true
|
||||
t.modules.system = true
|
||||
t.modules.thread = true
|
||||
t.modules.timer = true
|
||||
t.modules.video = true
|
||||
t.modules.window = true
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
<!-- PASSED 287 || FAILED 0 || SKIPPED 14 || TIME 14.726 -->
|
||||
|
||||
### Info
|
||||
**301** tests were completed in **14.726s** with **287** passed, **0** failed, and **14** skipped
|
||||
|
||||
Renderer: OpenGL | 4.1 Metal - 76.3 | Apple | Apple M1 Max
|
||||
|
||||
### Report
|
||||
| Module | Pass | Fail | Skip | Time |
|
||||
| --------------------- | ------ | ------ | ------- | ------ |
|
||||
| 🟢 audio | 28 | 0 | 0 | 0.894s |
|
||||
| 🟢 data | 12 | 0 | 0 | 0.209s |
|
||||
| 🟢 event | 4 | 0 | 2 | 0.103s |
|
||||
| 🟢 filesystem | 29 | 0 | 2 | 0.550s |
|
||||
| 🟢 font | 7 | 0 | 0 | 0.124s |
|
||||
| 🟢 graphics | 102 | 0 | 3 | 3.231s |
|
||||
| 🟢 image | 5 | 0 | 0 | 0.098s |
|
||||
| 🟢 math | 20 | 0 | 0 | 0.353s |
|
||||
| 🟢 physics | 23 | 0 | 3 | 0.449s |
|
||||
| 🟢 sound | 4 | 0 | 0 | 0.074s |
|
||||
| 🟢 system | 6 | 0 | 2 | 0.144s |
|
||||
| 🟢 thread | 5 | 0 | 0 | 0.377s |
|
||||
| 🟢 timer | 6 | 0 | 0 | 2.093s |
|
||||
| 🟢 video | 2 | 0 | 0 | 0.040s |
|
||||
| 🟢 window | 34 | 0 | 2 | 5.986s |
|
||||
|
||||
### Failures
|
||||
@@ -0,0 +1,648 @@
|
||||
<testsuites name="love.test" tests="287" failures="0" skipped="14" time="14.726">
|
||||
<testsuite name="love.audio" tests="28" failures="0" skipped="0" time="0.894">
|
||||
<testcase classname="RecordingDevice" name="RecordingDevice" assertions="20" time="0.398">
|
||||
</testcase>
|
||||
<testcase classname="Source" name="Source" assertions="54" time="0.024">
|
||||
</testcase>
|
||||
<testcase classname="getActiveEffects" name="getActiveEffects" assertions="3" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="getActiveSourceCount" name="getActiveSourceCount" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getDistanceModel" name="getDistanceModel" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getDopplerScale" name="getDopplerScale" assertions="2" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="getEffect" name="getEffect" assertions="4" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="getMaxSceneEffects" name="getMaxSceneEffects" assertions="1" time="0.016">
|
||||
</testcase>
|
||||
<testcase classname="getMaxSourceEffects" name="getMaxSourceEffects" assertions="1" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="getOrientation" name="getOrientation" assertions="6" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="getPosition" name="getPosition" assertions="3" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="getRecordingDevices" name="getRecordingDevices" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getVelocity" name="getVelocity" assertions="3" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="getVolume" name="getVolume" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="isEffectsSupported" name="isEffectsSupported" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="newQueueableSource" name="newQueueableSource" assertions="3" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="newSource" name="newSource" assertions="6" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="pause" name="pause" assertions="2" time="0.020">
|
||||
</testcase>
|
||||
<testcase classname="play" name="play" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="setDistanceModel" name="setDistanceModel" assertions="7" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="setDopplerScale" name="setDopplerScale" assertions="2" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="setEffect" name="setEffect" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="setMixWithSystem" name="setMixWithSystem" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="setOrientation" name="setOrientation" assertions="6" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="setPosition" name="setPosition" assertions="3" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="setVelocity" name="setVelocity" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="setVolume" name="setVolume" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="stop" name="stop" assertions="2" time="0.019">
|
||||
</testcase>
|
||||
</testsuite>
|
||||
<testsuite name="love.data" tests="12" failures="0" skipped="0" time="0.209">
|
||||
<testcase classname="ByteData" name="ByteData" assertions="10" time="0.015">
|
||||
</testcase>
|
||||
<testcase classname="CompressedData" name="CompressedData" assertions="12" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="compress" name="compress" assertions="45" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="decode" name="decode" assertions="4" time="0.014">
|
||||
</testcase>
|
||||
<testcase classname="decompress" name="decompress" assertions="18" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="encode" name="encode" assertions="15" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="getPackedSize" name="getPackedSize" assertions="3" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="hash" name="hash" assertions="6" time="0.016">
|
||||
</testcase>
|
||||
<testcase classname="newByteData" name="newByteData" assertions="3" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="newDataView" name="newDataView" assertions="3" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="pack" name="pack" assertions="4" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="unpack" name="unpack" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
</testsuite>
|
||||
<testsuite name="love.event" tests="4" failures="0" skipped="2" time="0.103">
|
||||
<testcase classname="clear" name="clear" assertions="1" time="0.016">
|
||||
</testcase>
|
||||
<testcase classname="poll" name="poll" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="pump" name="pump" assertions="0" time="0.018">
|
||||
<skipped message="used internally" />
|
||||
</testcase>
|
||||
<testcase classname="push" name="push" assertions="1" time="0.016">
|
||||
</testcase>
|
||||
<testcase classname="quit" name="quit" assertions="1" time="0.016">
|
||||
</testcase>
|
||||
<testcase classname="wait" name="wait" assertions="0" time="0.019">
|
||||
<skipped message="used internally" />
|
||||
</testcase>
|
||||
</testsuite>
|
||||
<testsuite name="love.filesystem" tests="29" failures="0" skipped="2" time="0.550">
|
||||
<testcase classname="File" name="File" assertions="36" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="FileData" name="FileData" assertions="12" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="append" name="append" assertions="6" time="0.020">
|
||||
</testcase>
|
||||
<testcase classname="areSymlinksEnabled" name="areSymlinksEnabled" assertions="1" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="createDirectory" name="createDirectory" assertions="3" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="getAppdataDirectory" name="getAppdataDirectory" assertions="1" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="getCRequirePath" name="getCRequirePath" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getDirectoryItems" name="getDirectoryItems" assertions="2" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getIdentity" name="getIdentity" assertions="1" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="getInfo" name="getInfo" assertions="3" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="getRealDirectory" name="getRealDirectory" assertions="1" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="getRequirePath" name="getRequirePath" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getSaveDirectory" name="getSaveDirectory" assertions="1" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="getSource" name="getSource" assertions="0" time="0.017">
|
||||
<skipped message="used internally" />
|
||||
</testcase>
|
||||
<testcase classname="getSourceBaseDirectory" name="getSourceBaseDirectory" assertions="1" time="0.020">
|
||||
</testcase>
|
||||
<testcase classname="getUserDirectory" name="getUserDirectory" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getWorkingDirectory" name="getWorkingDirectory" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="isFused" name="isFused" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="lines" name="lines" assertions="6" time="0.020">
|
||||
</testcase>
|
||||
<testcase classname="load" name="load" assertions="4" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="mount" name="mount" assertions="5" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="newFileData" name="newFileData" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="openFile" name="openFile" assertions="4" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="read" name="read" assertions="6" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="remove" name="remove" assertions="5" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="setCRequirePath" name="setCRequirePath" assertions="1" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="setIdentity" name="setIdentity" assertions="1" time="0.015">
|
||||
</testcase>
|
||||
<testcase classname="setRequirePath" name="setRequirePath" assertions="1" time="0.016">
|
||||
</testcase>
|
||||
<testcase classname="setSource" name="setSource" assertions="0" time="0.016">
|
||||
<skipped message="used internally" />
|
||||
</testcase>
|
||||
<testcase classname="unmount" name="unmount" assertions="2" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="write" name="write" assertions="3" time="0.017">
|
||||
</testcase>
|
||||
</testsuite>
|
||||
<testsuite name="love.font" tests="7" failures="0" skipped="0" time="0.124">
|
||||
<testcase classname="GlyphData" name="GlyphData" assertions="17" time="0.016">
|
||||
</testcase>
|
||||
<testcase classname="Rasterizer" name="Rasterizer" assertions="13" time="0.016">
|
||||
</testcase>
|
||||
<testcase classname="newBMFontRasterizer" name="newBMFontRasterizer" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="newGlyphData" name="newGlyphData" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="newImageRasterizer" name="newImageRasterizer" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="newRasterizer" name="newRasterizer" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="newTrueTypeRasterizer" name="newTrueTypeRasterizer" assertions="6" time="0.020">
|
||||
</testcase>
|
||||
</testsuite>
|
||||
<testsuite name="love.graphics" tests="102" failures="0" skipped="3" time="3.231">
|
||||
<testcase classname="Canvas" name="Canvas" assertions="44" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="Font" name="Font" assertions="90" time="0.021">
|
||||
</testcase>
|
||||
<testcase classname="Image" name="Image" assertions="40" time="0.020">
|
||||
</testcase>
|
||||
<testcase classname="Mesh" name="Mesh" assertions="0" time="0.018">
|
||||
<skipped message="test class needs writing" />
|
||||
</testcase>
|
||||
<testcase classname="ParticleSystem" name="ParticleSystem" assertions="0" time="0.017">
|
||||
<skipped message="test class needs writing" />
|
||||
</testcase>
|
||||
<testcase classname="Quad" name="Quad" assertions="47" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="Shader" name="Shader" assertions="39" time="0.029">
|
||||
</testcase>
|
||||
<testcase classname="SpriteBatch" name="SpriteBatch" assertions="203" time="0.027">
|
||||
</testcase>
|
||||
<testcase classname="Text" name="Text" assertions="90" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="Video" name="Video" assertions="48" time="1.040">
|
||||
</testcase>
|
||||
<testcase classname="applyTransform" name="applyTransform" assertions="4" time="0.006">
|
||||
</testcase>
|
||||
<testcase classname="arc" name="arc" assertions="264" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="captureScreenshot" name="captureScreenshot" assertions="1" time="0.183">
|
||||
</testcase>
|
||||
<testcase classname="circle" name="circle" assertions="192" time="0.020">
|
||||
</testcase>
|
||||
<testcase classname="clear" name="clear" assertions="20" time="0.031">
|
||||
</testcase>
|
||||
<testcase classname="discard" name="discard" assertions="0" time="0.016">
|
||||
<skipped message="cant test this worked" />
|
||||
</testcase>
|
||||
<testcase classname="draw" name="draw" assertions="112" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="drawInstanced" name="drawInstanced" assertions="16" time="0.030">
|
||||
</testcase>
|
||||
<testcase classname="drawLayer" name="drawLayer" assertions="144" time="0.025">
|
||||
</testcase>
|
||||
<testcase classname="ellipse" name="ellipse" assertions="80" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="flushBatch" name="flushBatch" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getBackgroundColor" name="getBackgroundColor" assertions="8" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getBlendMode" name="getBlendMode" assertions="4" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="getCanvas" name="getCanvas" assertions="4" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getColor" name="getColor" assertions="8" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getColorMask" name="getColorMask" assertions="8" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="getDPIScale" name="getDPIScale" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getDefaultFilter" name="getDefaultFilter" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getDepthMode" name="getDepthMode" assertions="2" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="getDimensions" name="getDimensions" assertions="2" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="getFont" name="getFont" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getFrontFaceWinding" name="getFrontFaceWinding" assertions="2" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="getHeight" name="getHeight" assertions="1" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="getLineJoin" name="getLineJoin" assertions="2" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="getLineStyle" name="getLineStyle" assertions="2" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getLineWidth" name="getLineWidth" assertions="2" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="getMeshCullMode" name="getMeshCullMode" assertions="2" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getPixelDimensions" name="getPixelDimensions" assertions="2" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getPixelHeight" name="getPixelHeight" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getPixelWidth" name="getPixelWidth" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getPointSize" name="getPointSize" assertions="2" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getRendererInfo" name="getRendererInfo" assertions="4" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="getScissor" name="getScissor" assertions="8" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="getShader" name="getShader" assertions="1" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="getStackDepth" name="getStackDepth" assertions="4" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getStats" name="getStats" assertions="7" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="getStencilMode" name="getStencilMode" assertions="6" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="getSupported" name="getSupported" assertions="17" time="0.016">
|
||||
</testcase>
|
||||
<testcase classname="getSystemLimits" name="getSystemLimits" assertions="13" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="getTextureFormats" name="getTextureFormats" assertions="79" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="getTextureTypes" name="getTextureTypes" assertions="4" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getWidth" name="getWidth" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="intersectScissor" name="intersectScissor" assertions="20" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="inverseTransformPoint" name="inverseTransformPoint" assertions="4" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="isActive" name="isActive" assertions="1" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="isGammaCorrect" name="isGammaCorrect" assertions="1" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="isWireframe" name="isWireframe" assertions="2" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="line" name="line" assertions="64" time="0.020">
|
||||
</testcase>
|
||||
<testcase classname="newArrayImage" name="newArrayImage" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="newCanvas" name="newCanvas" assertions="6" time="0.015">
|
||||
</testcase>
|
||||
<testcase classname="newCubeImage" name="newCubeImage" assertions="3" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="newFont" name="newFont" assertions="6" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="newImage" name="newImage" assertions="3" time="0.016">
|
||||
</testcase>
|
||||
<testcase classname="newImageFont" name="newImageFont" assertions="3" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="newMesh" name="newMesh" assertions="3" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="newParticleSystem" name="newParticleSystem" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="newQuad" name="newQuad" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="newShader" name="newShader" assertions="3" time="0.023">
|
||||
</testcase>
|
||||
<testcase classname="newSpriteBatch" name="newSpriteBatch" assertions="3" time="0.016">
|
||||
</testcase>
|
||||
<testcase classname="newTextBatch" name="newTextBatch" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="newVideo" name="newVideo" assertions="3" time="0.021">
|
||||
</testcase>
|
||||
<testcase classname="newVolumeImage" name="newVolumeImage" assertions="3" time="0.016">
|
||||
</testcase>
|
||||
<testcase classname="origin" name="origin" assertions="4" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="points" name="points" assertions="48" time="0.020">
|
||||
</testcase>
|
||||
<testcase classname="polygon" name="polygon" assertions="56" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="pop" name="pop" assertions="4" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="print" name="print" assertions="148" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="printf" name="printf" assertions="180" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="push" name="push" assertions="4" time="0.026">
|
||||
</testcase>
|
||||
<testcase classname="rectangle" name="rectangle" assertions="116" time="0.025">
|
||||
</testcase>
|
||||
<testcase classname="replaceTransform" name="replaceTransform" assertions="4" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="reset" name="reset" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="rotate" name="rotate" assertions="16" time="0.030">
|
||||
</testcase>
|
||||
<testcase classname="scale" name="scale" assertions="16" time="0.013">
|
||||
</testcase>
|
||||
<testcase classname="setBackgroundColor" name="setBackgroundColor" assertions="4" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="setBlendMode" name="setBlendMode" assertions="16" time="0.028">
|
||||
</testcase>
|
||||
<testcase classname="setCanvas" name="setCanvas" assertions="19" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="setColor" name="setColor" assertions="68" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="setColorMask" name="setColorMask" assertions="20" time="0.034">
|
||||
</testcase>
|
||||
<testcase classname="setDefaultFilter" name="setDefaultFilter" assertions="3" time="0.014">
|
||||
</testcase>
|
||||
<testcase classname="setDepthMode" name="setDepthMode" assertions="8" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="setFont" name="setFont" assertions="40" time="0.029">
|
||||
</testcase>
|
||||
<testcase classname="setFrontFaceWinding" name="setFrontFaceWinding" assertions="2" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="setLineJoin" name="setLineJoin" assertions="16" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="setLineStyle" name="setLineStyle" assertions="24" time="0.033">
|
||||
</testcase>
|
||||
<testcase classname="setLineWidth" name="setLineWidth" assertions="72" time="0.023">
|
||||
</testcase>
|
||||
<testcase classname="setMeshCullMode" name="setMeshCullMode" assertions="3" time="0.014">
|
||||
</testcase>
|
||||
<testcase classname="setScissor" name="setScissor" assertions="32" time="0.027">
|
||||
</testcase>
|
||||
<testcase classname="setShader" name="setShader" assertions="16" time="0.024">
|
||||
</testcase>
|
||||
<testcase classname="setStencilMode" name="setStencilMode" assertions="32" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="setWireframe" name="setWireframe" assertions="28" time="0.036">
|
||||
</testcase>
|
||||
<testcase classname="shear" name="shear" assertions="32" time="0.022">
|
||||
</testcase>
|
||||
<testcase classname="transformPoint" name="transformPoint" assertions="4" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="translate" name="translate" assertions="16" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="validateShader" name="validateShader" assertions="2" time="0.020">
|
||||
</testcase>
|
||||
</testsuite>
|
||||
<testsuite name="love.image" tests="5" failures="0" skipped="0" time="0.098">
|
||||
<testcase classname="CompressedImageData" name="CompressedImageData" assertions="11" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="ImageData" name="ImageData" assertions="14" time="0.036">
|
||||
</testcase>
|
||||
<testcase classname="isCompressed" name="isCompressed" assertions="1" time="0.013">
|
||||
</testcase>
|
||||
<testcase classname="newCompressedData" name="newCompressedData" assertions="3" time="0.016">
|
||||
</testcase>
|
||||
<testcase classname="newImageData" name="newImageData" assertions="6" time="0.016">
|
||||
</testcase>
|
||||
</testsuite>
|
||||
<testsuite name="love.math" tests="20" failures="0" skipped="0" time="0.353">
|
||||
<testcase classname="BezierCurve" name="BezierCurve" assertions="31" time="0.016">
|
||||
</testcase>
|
||||
<testcase classname="RandomGenerator" name="RandomGenerator" assertions="10" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="Transform" name="Transform" assertions="14" time="0.016">
|
||||
</testcase>
|
||||
<testcase classname="colorFromBytes" name="colorFromBytes" assertions="12" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="colorToBytes" name="colorToBytes" assertions="12" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="gammaToLinear" name="gammaToLinear" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getRandomSeed" name="getRandomSeed" assertions="2" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getRandomState" name="getRandomState" assertions="1" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="isConvex" name="isConvex" assertions="2" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="linearToGamma" name="linearToGamma" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="newBezierCurve" name="newBezierCurve" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="newRandomGenerator" name="newRandomGenerator" assertions="3" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="newTransform" name="newTransform" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="perlinNoise" name="perlinNoise" assertions="4" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="random" name="random" assertions="10" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="randomNormal" name="randomNormal" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="setRandomSeed" name="setRandomSeed" assertions="2" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="setRandomState" name="setRandomState" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="simplexNoise" name="simplexNoise" assertions="4" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="triangulate" name="triangulate" assertions="2" time="0.017">
|
||||
</testcase>
|
||||
</testsuite>
|
||||
<testsuite name="love.physics" tests="23" failures="0" skipped="3" time="0.449">
|
||||
<testcase classname="Body" name="Body" assertions="0" time="0.016">
|
||||
<skipped message="test class needs writing" />
|
||||
</testcase>
|
||||
<testcase classname="Contact" name="Contact" assertions="0" time="0.017">
|
||||
<skipped message="test class needs writing" />
|
||||
</testcase>
|
||||
<testcase classname="Joint" name="Joint" assertions="17" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="Shape" name="Shape" assertions="0" time="0.018">
|
||||
<skipped message="test class needs writing" />
|
||||
</testcase>
|
||||
<testcase classname="World" name="World" assertions="33" time="0.016">
|
||||
</testcase>
|
||||
<testcase classname="getDistance" name="getDistance" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getMeter" name="getMeter" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="newBody" name="newBody" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="newChainShape" name="newChainShape" assertions="3" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="newCircleShape" name="newCircleShape" assertions="3" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="newDistanceJoint" name="newDistanceJoint" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="newEdgeShape" name="newEdgeShape" assertions="3" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="newFrictionJoint" name="newFrictionJoint" assertions="3" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="newGearJoint" name="newGearJoint" assertions="3" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="newMotorJoint" name="newMotorJoint" assertions="3" time="0.015">
|
||||
</testcase>
|
||||
<testcase classname="newMouseJoint" name="newMouseJoint" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="newPolygonShape" name="newPolygonShape" assertions="3" time="0.016">
|
||||
</testcase>
|
||||
<testcase classname="newPrismaticJoint" name="newPrismaticJoint" assertions="3" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="newPulleyJoint" name="newPulleyJoint" assertions="3" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="newRectangleShape" name="newRectangleShape" assertions="6" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="newRevoluteJoint" name="newRevoluteJoint" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="newRopeJoint" name="newRopeJoint" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="newWeldJoint" name="newWeldJoint" assertions="3" time="0.016">
|
||||
</testcase>
|
||||
<testcase classname="newWheelJoint" name="newWheelJoint" assertions="3" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="newWorld" name="newWorld" assertions="3" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="setMeter" name="setMeter" assertions="2" time="0.018">
|
||||
</testcase>
|
||||
</testsuite>
|
||||
<testsuite name="love.sound" tests="4" failures="0" skipped="0" time="0.074">
|
||||
<testcase classname="Decoder" name="Decoder" assertions="14" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="SoundData" name="SoundData" assertions="20" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="newDecoder" name="newDecoder" assertions="3" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="newSoundData" name="newSoundData" assertions="6" time="0.019">
|
||||
</testcase>
|
||||
</testsuite>
|
||||
<testsuite name="love.system" tests="6" failures="0" skipped="2" time="0.144">
|
||||
<testcase classname="getClipboardText" name="getClipboardText" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getOS" name="getOS" assertions="1" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="getPowerInfo" name="getPowerInfo" assertions="1" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="getProcessorCount" name="getProcessorCount" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="hasBackgroundMusic" name="hasBackgroundMusic" assertions="1" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="openURL" name="openURL" assertions="0" time="0.018">
|
||||
<skipped message="cant test this worked" />
|
||||
</testcase>
|
||||
<testcase classname="setClipboardText" name="setClipboardText" assertions="1" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="vibrate" name="vibrate" assertions="0" time="0.017">
|
||||
<skipped message="cant test this worked" />
|
||||
</testcase>
|
||||
</testsuite>
|
||||
<testsuite name="love.thread" tests="5" failures="0" skipped="0" time="0.377">
|
||||
<testcase classname="Channel" name="Channel" assertions="10" time="0.230">
|
||||
</testcase>
|
||||
<testcase classname="Thread" name="Thread" assertions="7" time="0.099">
|
||||
</testcase>
|
||||
<testcase classname="getChannel" name="getChannel" assertions="3" time="0.016">
|
||||
</testcase>
|
||||
<testcase classname="newChannel" name="newChannel" assertions="3" time="0.016">
|
||||
</testcase>
|
||||
<testcase classname="newThread" name="newThread" assertions="3" time="0.017">
|
||||
</testcase>
|
||||
</testsuite>
|
||||
<testsuite name="love.timer" tests="6" failures="0" skipped="0" time="2.093">
|
||||
<testcase classname="getAverageDelta" name="getAverageDelta" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getDelta" name="getDelta" assertions="1" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="getFPS" name="getFPS" assertions="1" time="0.015">
|
||||
</testcase>
|
||||
<testcase classname="getTime" name="getTime" assertions="1" time="1.019">
|
||||
</testcase>
|
||||
<testcase classname="sleep" name="sleep" assertions="1" time="1.011">
|
||||
</testcase>
|
||||
<testcase classname="step" name="step" assertions="1" time="0.011">
|
||||
</testcase>
|
||||
</testsuite>
|
||||
<testsuite name="love.video" tests="2" failures="0" skipped="0" time="0.040">
|
||||
<testcase classname="VideoStream" name="VideoStream" assertions="9" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="newVideoStream" name="newVideoStream" assertions="3" time="0.021">
|
||||
</testcase>
|
||||
</testsuite>
|
||||
<testsuite name="love.window" tests="34" failures="0" skipped="2" time="5.986">
|
||||
<testcase classname="close" name="close" assertions="2" time="0.045">
|
||||
</testcase>
|
||||
<testcase classname="fromPixels" name="fromPixels" assertions="1" time="0.002">
|
||||
</testcase>
|
||||
<testcase classname="getDPIScale" name="getDPIScale" assertions="1" time="0.002">
|
||||
</testcase>
|
||||
<testcase classname="getDesktopDimensions" name="getDesktopDimensions" assertions="2" time="0.002">
|
||||
</testcase>
|
||||
<testcase classname="getDisplayCount" name="getDisplayCount" assertions="1" time="0.015">
|
||||
</testcase>
|
||||
<testcase classname="getDisplayName" name="getDisplayName" assertions="1" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="getDisplayOrientation" name="getDisplayOrientation" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getFullscreen" name="getFullscreen" assertions="2" time="1.346">
|
||||
</testcase>
|
||||
<testcase classname="getFullscreenModes" name="getFullscreenModes" assertions="1" time="0.014">
|
||||
</testcase>
|
||||
<testcase classname="getIcon" name="getIcon" assertions="2" time="0.020">
|
||||
</testcase>
|
||||
<testcase classname="getMode" name="getMode" assertions="3" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="getPosition" name="getPosition" assertions="2" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="getSafeArea" name="getSafeArea" assertions="4" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="getTitle" name="getTitle" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="getVSync" name="getVSync" assertions="1" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="hasFocus" name="hasFocus" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="hasMouseFocus" name="hasMouseFocus" assertions="1" time="0.018">
|
||||
</testcase>
|
||||
<testcase classname="isDisplaySleepEnabled" name="isDisplaySleepEnabled" assertions="3" time="0.017">
|
||||
</testcase>
|
||||
<testcase classname="isMaximized" name="isMaximized" assertions="2" time="0.184">
|
||||
</testcase>
|
||||
<testcase classname="isMinimized" name="isMinimized" assertions="2" time="0.728">
|
||||
</testcase>
|
||||
<testcase classname="isOpen" name="isOpen" assertions="2" time="0.049">
|
||||
</testcase>
|
||||
<testcase classname="isVisible" name="isVisible" assertions="2" time="0.024">
|
||||
</testcase>
|
||||
<testcase classname="maximize" name="maximize" assertions="2" time="0.156">
|
||||
</testcase>
|
||||
<testcase classname="minimize" name="minimize" assertions="2" time="0.731">
|
||||
</testcase>
|
||||
<testcase classname="requestAttention" name="requestAttention" assertions="0" time="0.012">
|
||||
<skipped message="cant test this worked" />
|
||||
</testcase>
|
||||
<testcase classname="restore" name="restore" assertions="1" time="0.864">
|
||||
</testcase>
|
||||
<testcase classname="setDisplaySleepEnabled" name="setDisplaySleepEnabled" assertions="2" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="setFullscreen" name="setFullscreen" assertions="2" time="1.336">
|
||||
</testcase>
|
||||
<testcase classname="setIcon" name="setIcon" assertions="1" time="0.014">
|
||||
</testcase>
|
||||
<testcase classname="setMode" name="setMode" assertions="4" time="0.022">
|
||||
</testcase>
|
||||
<testcase classname="setPosition" name="setPosition" assertions="2" time="0.180">
|
||||
</testcase>
|
||||
<testcase classname="setTitle" name="setTitle" assertions="1" time="0.019">
|
||||
</testcase>
|
||||
<testcase classname="setVSync" name="setVSync" assertions="1" time="0.016">
|
||||
</testcase>
|
||||
<testcase classname="showMessageBox" name="showMessageBox" assertions="0" time="0.002">
|
||||
<skipped message="cant test this worked" />
|
||||
</testcase>
|
||||
<testcase classname="toPixels" name="toPixels" assertions="1" time="0.002">
|
||||
</testcase>
|
||||
<testcase classname="updateMode" name="updateMode" assertions="4" time="0.011">
|
||||
</testcase>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
@@ -0,0 +1,216 @@
|
||||
-- & 'c:\Program Files\LOVE\love.exe' ./ --console
|
||||
-- /Applications/love_12.app/Contents/MacOS/love ./testing
|
||||
|
||||
-- load test objs
|
||||
require('classes.TestSuite')
|
||||
require('classes.TestModule')
|
||||
require('classes.TestMethod')
|
||||
|
||||
-- create testsuite obj
|
||||
love.test = TestSuite:new()
|
||||
|
||||
-- load test scripts if module is active
|
||||
if love.audio ~= nil then require('tests.audio') end
|
||||
if love.data ~= nil then require('tests.data') end
|
||||
if love.event ~= nil then require('tests.event') end
|
||||
if love.filesystem ~= nil then require('tests.filesystem') end
|
||||
if love.font ~= nil then require('tests.font') end
|
||||
if love.graphics ~= nil then require('tests.graphics') end
|
||||
if love.image ~= nil then require('tests.image') end
|
||||
if love.math ~= nil then require('tests.math') end
|
||||
if love.physics ~= nil then require('tests.physics') end
|
||||
if love.sound ~= nil then require('tests.sound') end
|
||||
if love.system ~= nil then require('tests.system') end
|
||||
if love.thread ~= nil then require('tests.thread') end
|
||||
if love.timer ~= nil then require('tests.timer') end
|
||||
if love.video ~= nil then require('tests.video') end
|
||||
if love.window ~= nil then require('tests.window') end
|
||||
|
||||
-- love.load
|
||||
-- load given arguments and run the test suite
|
||||
love.load = function(args)
|
||||
|
||||
-- setup basic img to display
|
||||
if love.window ~= nil then
|
||||
love.window.setMode(360, 240, {
|
||||
fullscreen = false,
|
||||
resizable = true,
|
||||
centered = true
|
||||
})
|
||||
if love.graphics ~= nil then
|
||||
love.graphics.setDefaultFilter("nearest", "nearest")
|
||||
love.graphics.setLineStyle('rough')
|
||||
love.graphics.setLineWidth(1)
|
||||
Logo = {
|
||||
texture = love.graphics.newImage('resources/love.png'),
|
||||
img = nil
|
||||
}
|
||||
Logo.img = love.graphics.newQuad(0, 0, 64, 64, Logo.texture)
|
||||
Font = love.graphics.newFont('resources/font.ttf', 8, 'normal')
|
||||
local txtobj = love.graphics.newTextBatch or love.graphics.newText
|
||||
TextCommand = txtobj(Font, 'Loading...')
|
||||
TextRun = txtobj(Font, '')
|
||||
end
|
||||
end
|
||||
|
||||
-- mount for output later
|
||||
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 = {}
|
||||
for a=1,#args do
|
||||
local splits = UtilStringSplit(args[a], '([^,]+)')
|
||||
for s=1,#splits do
|
||||
table.insert(arglist, splits[s])
|
||||
end
|
||||
end
|
||||
|
||||
-- convert args to the cmd to run, modules, method (if any) and disabled
|
||||
local testcmd = '--runAllTests'
|
||||
local module = ''
|
||||
local method = ''
|
||||
local cmderr = 'Invalid flag used'
|
||||
local modules = {
|
||||
'audio', 'data', 'event', 'filesystem', 'font', 'graphics',
|
||||
'image', 'math', 'physics', 'sound', 'system',
|
||||
'thread', 'timer', 'video', 'window'
|
||||
}
|
||||
GITHUB_RUNNER = false
|
||||
for a=1,#arglist do
|
||||
if testcmd == '--runSpecificMethod' then
|
||||
if module == '' and love[ arglist[a] ] ~= nil then
|
||||
module = arglist[a]
|
||||
table.insert(modules, module)
|
||||
elseif module ~= '' and love[module] ~= nil and method == '' then
|
||||
if love.test[module][arglist[a]] ~= nil then method = arglist[a] end
|
||||
end
|
||||
end
|
||||
if testcmd == '--runSpecificModules' then
|
||||
if love[ arglist[a] ] ~= nil and arglist[a] ~= '--isRunner' then
|
||||
table.insert(modules, arglist[a])
|
||||
end
|
||||
end
|
||||
if arglist[a] == '--runSpecificMethod' then
|
||||
testcmd = arglist[a]
|
||||
modules = {}
|
||||
end
|
||||
if arglist[a] == '--runSpecificModules' then
|
||||
testcmd = arglist[a]
|
||||
modules = {}
|
||||
end
|
||||
if arglist[a] == '--isRunner' then
|
||||
GITHUB_RUNNER = true
|
||||
end
|
||||
end
|
||||
|
||||
-- runSpecificMethod uses the module + method given
|
||||
if testcmd == '--runSpecificMethod' then
|
||||
local testmodule = TestModule:new(module, method)
|
||||
table.insert(love.test.modules, testmodule)
|
||||
if module ~= '' and method ~= '' then
|
||||
love.test.module = testmodule
|
||||
love.test.module:log('grey', '--runSpecificMethod "' .. module .. '" "' .. method .. '"')
|
||||
love.test.output = 'lovetest_runSpecificMethod_' .. module .. '_' .. method
|
||||
else
|
||||
if method == '' then cmderr = 'No valid method specified' end
|
||||
if module == '' then cmderr = 'No valid module specified' end
|
||||
end
|
||||
end
|
||||
|
||||
-- runSpecificModules runs all methods for all the modules given
|
||||
if testcmd == '--runSpecificModules' then
|
||||
local modulelist = {}
|
||||
for m=1,#modules do
|
||||
local testmodule = TestModule:new(modules[m])
|
||||
table.insert(love.test.modules, testmodule)
|
||||
table.insert(modulelist, modules[m])
|
||||
end
|
||||
if #modulelist > 0 then
|
||||
love.test.module = love.test.modules[1]
|
||||
love.test.module:log('grey', '--runSpecificModules "' .. table.concat(modulelist, '" "') .. '"')
|
||||
love.test.output = 'lovetest_runSpecificModules_' .. table.concat(modulelist, '_')
|
||||
else
|
||||
cmderr = 'No modules specified'
|
||||
end
|
||||
end
|
||||
|
||||
-- otherwise default runs all methods for all modules
|
||||
if arglist[1] == nil or arglist[1] == '' or arglist[1] == '--runAllTests' then
|
||||
for m=1,#modules do
|
||||
local testmodule = TestModule:new(modules[m])
|
||||
table.insert(love.test.modules, testmodule)
|
||||
end
|
||||
love.test.module = love.test.modules[1]
|
||||
love.test.module:log('grey', '--runAllTests')
|
||||
love.test.output = 'lovetest_runAllTests'
|
||||
end
|
||||
|
||||
if GITHUB_RUNNER then
|
||||
love.test.module:log('grey', '--isRunner')
|
||||
end
|
||||
|
||||
-- invalid command
|
||||
if love.test.module == nil then
|
||||
print(cmderr)
|
||||
love.event.quit(0)
|
||||
else
|
||||
-- start first module
|
||||
TextCommand:set(testcmd)
|
||||
love.test.module:runTests()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- love.update
|
||||
-- run test suite logic
|
||||
love.update = function(delta)
|
||||
love.test:runSuite(delta)
|
||||
end
|
||||
|
||||
|
||||
-- love.draw
|
||||
-- draw a little logo to the screen
|
||||
love.draw = function()
|
||||
local lw = (love.graphics.getPixelWidth() - 128) / 2
|
||||
local lh = (love.graphics.getPixelHeight() - 128) / 2
|
||||
love.graphics.draw(Logo.texture, Logo.img, lw, lh, 0, 2, 2)
|
||||
love.graphics.draw(TextCommand, 4, 12, 0, 2, 2)
|
||||
love.graphics.draw(TextRun, 4, 32, 0, 2, 2)
|
||||
end
|
||||
|
||||
|
||||
-- love.quit
|
||||
-- add a hook to allow test modules to fake quit
|
||||
love.quit = function()
|
||||
if love.test.module ~= nil and love.test.module.fakequit == true then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- added so bad threads dont fail
|
||||
function love.threaderror(thread, errorstr) end
|
||||
|
||||
|
||||
-- string split helper
|
||||
function UtilStringSplit(str, splitter)
|
||||
local splits = {}
|
||||
for word in string.gmatch(str, splitter) do
|
||||
table.insert(splits, word)
|
||||
end
|
||||
return splits
|
||||
end
|
||||
|
||||
|
||||
-- string time formatter
|
||||
function UtilTimeFormat(seconds)
|
||||
return string.format("%.3f", tostring(seconds))
|
||||
end
|
||||
|
||||
function UtilDebugLog(a, b, c)
|
||||
if GITHUB_RUNNER == true then print("DEBUG ==> ", a, b, c) end
|
||||
end
|
||||
@@ -0,0 +1,2 @@
|
||||
# Actual Graphics Output
|
||||
The images generated by the tests
|
||||
|
After Width: | Height: | Size: 92 B |
|
After Width: | Height: | Size: 92 B |
|
After Width: | Height: | Size: 102 B |
|
After Width: | Height: | Size: 104 B |
|
After Width: | Height: | Size: 375 B |
|
After Width: | Height: | Size: 134 B |
|
After Width: | Height: | Size: 265 B |
|
After Width: | Height: | Size: 114 B |
|
After Width: | Height: | Size: 96 B |
|
After Width: | Height: | Size: 111 B |
|
After Width: | Height: | Size: 112 B |
|
After Width: | Height: | Size: 72 B |
|
After Width: | Height: | Size: 209 B |
|
After Width: | Height: | Size: 449 B |
|
After Width: | Height: | Size: 197 B |
|
After Width: | Height: | Size: 89 B |
|
After Width: | Height: | Size: 245 B |
|
After Width: | Height: | Size: 217 B |
|
After Width: | Height: | Size: 223 B |
|
After Width: | Height: | Size: 212 B |
|
After Width: | Height: | Size: 84 B |
|
After Width: | Height: | Size: 219 B |
|
After Width: | Height: | Size: 369 B |
|
After Width: | Height: | Size: 386 B |
|
After Width: | Height: | Size: 185 B |
|
After Width: | Height: | Size: 91 B |
|
After Width: | Height: | Size: 139 B |
|
After Width: | Height: | Size: 90 B |
|
After Width: | Height: | Size: 111 B |
|
After Width: | Height: | Size: 154 B |
|
After Width: | Height: | Size: 90 B |
|
After Width: | Height: | Size: 154 B |
|
After Width: | Height: | Size: 196 B |
|
After Width: | Height: | Size: 91 B |
|
After Width: | Height: | Size: 92 B |
|
After Width: | Height: | Size: 103 B |
|
After Width: | Height: | Size: 89 B |
|
After Width: | Height: | Size: 91 B |
|
After Width: | Height: | Size: 123 B |
|
After Width: | Height: | Size: 84 B |
|
After Width: | Height: | Size: 110 B |
|
After Width: | Height: | Size: 84 B |
|
After Width: | Height: | Size: 106 B |
|
After Width: | Height: | Size: 122 B |
|
After Width: | Height: | Size: 102 B |
|
After Width: | Height: | Size: 118 B |
|
After Width: | Height: | Size: 89 B |
|
After Width: | Height: | Size: 84 B |
|
After Width: | Height: | Size: 107 B |
|
After Width: | Height: | Size: 128 B |
|
After Width: | Height: | Size: 98 B |
|
After Width: | Height: | Size: 101 B |
|
After Width: | Height: | Size: 93 B |
@@ -0,0 +1,2 @@
|
||||
# Expected Graphics Output
|
||||
The images expected by the tests
|
||||
@@ -0,0 +1,2 @@
|
||||
# Testing Output
|
||||
Any tests run will output an XML, MD, and HTML file here, assuming the tests are run with readwrite permissions for this repo
|
||||
@@ -0,0 +1,155 @@
|
||||
# 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. 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 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
|
||||
- [x] Ability to easily run an individual test
|
||||
- [x] Ability to see all visual results at a glance
|
||||
- [x] Compare graphics test output with an expected output
|
||||
- [x] Automatic testing that happens after every commit
|
||||
- [x] No platform-specific dependencies / scripts
|
||||
|
||||
---
|
||||
|
||||
## Coverage
|
||||
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 |
|
||||
| 🟢 data | 12 | 0 | 0 |
|
||||
| 🟢 event | 4 | 0 | 2 |
|
||||
| 🟢 filesystem | 29 | 0 | 2 |
|
||||
| 🟢 font | 7 | 0 | 0 |
|
||||
| 🟢 graphics | 104 | 0 | 1 |
|
||||
| 🟢 image | 5 | 0 | 0 |
|
||||
| 🟢 math | 20 | 0 | 0 |
|
||||
| 🟢 physics | 26 | 0 | 0 |
|
||||
| 🟢 sound | 4 | 0 | 0 |
|
||||
| 🟢 system | 6 | 0 | 2 |
|
||||
| 🟢 thread | 5 | 0 | 0 |
|
||||
| 🟢 timer | 6 | 0 | 0 |
|
||||
| 🟢 video | 2 | 0 | 0 |
|
||||
| 🟢 window | 34 | 0 | 2 |
|
||||
|
||||
> The following modules are not covered as we can't really emulate input nicely:
|
||||
> `joystick`, `keyboard`, `mouse`, and `touch`
|
||||
|
||||
---
|
||||
|
||||
## Running Tests
|
||||
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/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:
|
||||
`--runSpecificModules filesystem,audio`
|
||||
If you want to specify only 1 specific method only you can use:
|
||||
`--runSpecificMethod filesystem write`
|
||||
|
||||
All results will be printed in the console per method as PASS, FAIL, or SKIP with total assertions met on a module level and overall level.
|
||||
|
||||
When finished, the following files will be generated in the `/output` directory with a summary of the test results:
|
||||
- an `XML` file in the style of [JUnit XML](https://www.ibm.com/docs/en/developer-for-zos/14.1?topic=formats-junit-xml-format)
|
||||
- a `HTML` file that shows the report + any visual test results
|
||||
- a `Markdown` file you can use with [this github action](https://github.com/ellraiser/love-test-report)
|
||||
> An example of all types of output can be found in the `/examples`
|
||||
> The visual results of any graphic tests can be found in `/output/actual`
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
Each method and object has it's own test method written in `/tests` under the matching module name.
|
||||
|
||||
When you run the tests, a single TestSuite object is created which handles the progress + totals for all the tests.
|
||||
Each module has a TestModule object created, and each test method has a TestMethod object created which keeps track of assertions for that method. You can currently do the following assertions:
|
||||
- **assertNotNil**(value)
|
||||
- **assertEquals**(expected, actual, label)
|
||||
- **assertTrue**(value, label)
|
||||
- **assertFalse**(value, label)
|
||||
- **assertNotEquals**(expected, actual, label)
|
||||
- **assertRange**(actual, min, max, label)
|
||||
- **assertMatch**({option1, option2, option3 ...}, actual, label)
|
||||
- **assertGreaterEqual**(expected, actual, label)
|
||||
- **assertLessEqual**(expected, actual, label)
|
||||
- **assertObject**(table)
|
||||
- **assertPixels**(imgdata, pixeltable, label)
|
||||
- **assertCoords**(expected, actual, label)
|
||||
|
||||
Example test method:
|
||||
```lua
|
||||
-- love.filesystem.read test method
|
||||
-- all methods should be put under love.test.MODULE.METHOD, matching the API
|
||||
love.test.filesystem.read = function(test)
|
||||
-- setup any data needed then run any asserts using the passed test object
|
||||
local content, size = love.filesystem.read('resources/test.txt')
|
||||
test:assertNotNil(content)
|
||||
test:assertEquals('helloworld', content, 'check content match')
|
||||
test:assertEquals(10, size, 'check size match')
|
||||
content, size = love.filesystem.read('resources/test.txt', 5)
|
||||
test:assertNotNil(content)
|
||||
test:assertEquals('hello', content, 'check content match')
|
||||
test:assertEquals(5, size, 'check size match')
|
||||
-- no need to return anything or cleanup, GCC is called after each method
|
||||
end
|
||||
```
|
||||
|
||||
Each test is run inside it's own coroutine - you can use `test:waitFrames(frames)` to pause the test for a small period if you need to check things that won't happen for a few seconds.
|
||||
|
||||
After each test method is ran, the assertions are totalled up, printed, and we move onto the next method! Once all methods in the suite are run a total pass/fail/skip is given for that module and we move onto the next module (if any)
|
||||
|
||||
For sanity-checking, if it's currently not covered or it's not possible to test the method we can set the test to be skipped with `test:skipTest(reason)` - this way we still see the method listed in the test output without it affected the pass/fail totals
|
||||
|
||||
---
|
||||
|
||||
## 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.
|
||||
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 |
|
||||
@@ -0,0 +1,491 @@
|
||||
# OpenAL config file.
|
||||
#
|
||||
# Option blocks may appear multiple times, and duplicated options will take the
|
||||
# last value specified. Environment variables may be specified within option
|
||||
# values, and are automatically substituted when the config file is loaded.
|
||||
# Environment variable names may only contain alpha-numeric characters (a-z,
|
||||
# A-Z, 0-9) and underscores (_), and are prefixed with $. For example,
|
||||
# specifying "$HOME/file.ext" would typically result in something like
|
||||
# "/home/user/file.ext". To specify an actual "$" character, use "$$".
|
||||
#
|
||||
# Device-specific values may be specified by including the device name in the
|
||||
# block name, with "general" replaced by the device name. That is, general
|
||||
# options for the device "Name of Device" would be in the [Name of Device]
|
||||
# block, while ALSA options would be in the [alsa/Name of Device] block.
|
||||
# Options marked as "(global)" are not influenced by the device.
|
||||
#
|
||||
# The system-wide settings can be put in /etc/openal/alsoft.conf and user-
|
||||
# specific override settings in $HOME/.alsoftrc.
|
||||
# For Windows, these settings should go into $AppData\alsoft.ini
|
||||
#
|
||||
# Option and block names are case-senstive. The supplied values are only hints
|
||||
# and may not be honored (though generally it'll try to get as close as
|
||||
# possible). Note: options that are left unset may default to app- or system-
|
||||
# specified values. These are the current available settings:
|
||||
|
||||
##
|
||||
## General stuff
|
||||
##
|
||||
[general]
|
||||
|
||||
## disable-cpu-exts: (global)
|
||||
# Disables use of specialized methods that use specific CPU intrinsics.
|
||||
# Certain methods may utilize CPU extensions for improved performance, and
|
||||
# this option is useful for preventing some or all of those methods from being
|
||||
# used. The available extensions are: sse, sse2, sse3, sse4.1, and neon.
|
||||
# Specifying 'all' disables use of all such specialized methods.
|
||||
#disable-cpu-exts =
|
||||
|
||||
## drivers: (global)
|
||||
# Sets the backend driver list order, comma-seperated. Unknown backends and
|
||||
# duplicated names are ignored. Unlisted backends won't be considered for use
|
||||
# unless the list is ended with a comma (e.g. 'oss,' will try OSS first before
|
||||
# other backends, while 'oss' will try OSS only). Backends prepended with -
|
||||
# won't be considered for use (e.g. '-oss,' will try all available backends
|
||||
# except OSS). An empty list means to try all backends.
|
||||
drivers = wave
|
||||
|
||||
## channels:
|
||||
# Sets the output channel configuration. If left unspecified, one will try to
|
||||
# be detected from the system, and defaulting to stereo. The available values
|
||||
# are: mono, stereo, quad, surround51, surround51rear, surround61, surround71,
|
||||
# ambi1, ambi2, ambi3. Note that the ambi* configurations provide ambisonic
|
||||
# channels of the given order (using ACN ordering and SN3D normalization by
|
||||
# default), which need to be decoded to play correctly on speakers.
|
||||
#channels =
|
||||
|
||||
## sample-type:
|
||||
# Sets the output sample type. Currently, all mixing is done with 32-bit float
|
||||
# and converted to the output sample type as needed. Available values are:
|
||||
# int8 - signed 8-bit int
|
||||
# uint8 - unsigned 8-bit int
|
||||
# int16 - signed 16-bit int
|
||||
# uint16 - unsigned 16-bit int
|
||||
# int32 - signed 32-bit int
|
||||
# uint32 - unsigned 32-bit int
|
||||
# float32 - 32-bit float
|
||||
#sample-type = float32
|
||||
|
||||
## frequency:
|
||||
# Sets the output frequency. If left unspecified it will try to detect a
|
||||
# default from the system, otherwise it will default to 44100.
|
||||
#frequency =
|
||||
|
||||
## period_size:
|
||||
# Sets the update period size, in frames. This is the number of frames needed
|
||||
# for each mixing update. Acceptable values range between 64 and 8192.
|
||||
#period_size = 1024
|
||||
|
||||
## periods:
|
||||
# Sets the number of update periods. Higher values create a larger mix ahead,
|
||||
# which helps protect against skips when the CPU is under load, but increases
|
||||
# the delay between a sound getting mixed and being heard. Acceptable values
|
||||
# range between 2 and 16.
|
||||
#periods = 3
|
||||
|
||||
## stereo-mode:
|
||||
# Specifies if stereo output is treated as being headphones or speakers. With
|
||||
# headphones, HRTF or crossfeed filters may be used for better audio quality.
|
||||
# Valid settings are auto, speakers, and headphones.
|
||||
#stereo-mode = auto
|
||||
|
||||
## stereo-encoding:
|
||||
# Specifies the encoding method for non-HRTF stereo output. 'panpot' (default)
|
||||
# uses standard amplitude panning (aka pair-wise, stereo pair, etc) between
|
||||
# -30 and +30 degrees, while 'uhj' creates stereo-compatible two-channel UHJ
|
||||
# output, which encodes some surround sound information into stereo output
|
||||
# that can be decoded with a surround sound receiver. If crossfeed filters are
|
||||
# used, UHJ is disabled.
|
||||
#stereo-encoding = panpot
|
||||
|
||||
## ambi-format:
|
||||
# Specifies the channel order and normalization for the "ambi*" set of channel
|
||||
# configurations. Valid settings are: fuma, acn+sn3d, acn+n3d
|
||||
#ambi-format = acn+sn3d
|
||||
|
||||
## hrtf:
|
||||
# Controls HRTF processing. These filters provide better spatialization of
|
||||
# sounds while using headphones, but do require a bit more CPU power. The
|
||||
# default filters will only work with 44100hz or 48000hz stereo output. While
|
||||
# HRTF is used, the cf_level option is ignored. Setting this to auto (default)
|
||||
# will allow HRTF to be used when headphones are detected or the app requests
|
||||
# it, while setting true or false will forcefully enable or disable HRTF
|
||||
# respectively.
|
||||
#hrtf = auto
|
||||
|
||||
## default-hrtf:
|
||||
# Specifies the default HRTF to use. When multiple HRTFs are available, this
|
||||
# determines the preferred one to use if none are specifically requested. Note
|
||||
# that this is the enumerated HRTF name, not necessarily the filename.
|
||||
#default-hrtf =
|
||||
|
||||
## hrtf-paths:
|
||||
# Specifies a comma-separated list of paths containing HRTF data sets. The
|
||||
# format of the files are described in docs/hrtf.txt. The files within the
|
||||
# directories must have the .mhr file extension to be recognized. By default,
|
||||
# OS-dependent data paths will be used. They will also be used if the list
|
||||
# ends with a comma. On Windows this is:
|
||||
# $AppData\openal\hrtf
|
||||
# And on other systems, it's (in order):
|
||||
# $XDG_DATA_HOME/openal/hrtf (defaults to $HOME/.local/share/openal/hrtf)
|
||||
# $XDG_DATA_DIRS/openal/hrtf (defaults to /usr/local/share/openal/hrtf and
|
||||
# /usr/share/openal/hrtf)
|
||||
#hrtf-paths =
|
||||
|
||||
## cf_level:
|
||||
# Sets the crossfeed level for stereo output. Valid values are:
|
||||
# 0 - No crossfeed
|
||||
# 1 - Low crossfeed
|
||||
# 2 - Middle crossfeed
|
||||
# 3 - High crossfeed (virtual speakers are closer to itself)
|
||||
# 4 - Low easy crossfeed
|
||||
# 5 - Middle easy crossfeed
|
||||
# 6 - High easy crossfeed
|
||||
# Users of headphones may want to try various settings. Has no effect on non-
|
||||
# stereo modes.
|
||||
#cf_level = 0
|
||||
|
||||
## resampler: (global)
|
||||
# Selects the resampler used when mixing sources. Valid values are:
|
||||
# point - nearest sample, no interpolation
|
||||
# linear - extrapolates samples using a linear slope between samples
|
||||
# cubic - extrapolates samples using a Catmull-Rom spline
|
||||
# bsinc12 - extrapolates samples using a band-limited Sinc filter (varying
|
||||
# between 12 and 24 points, with anti-aliasing)
|
||||
# bsinc24 - extrapolates samples using a band-limited Sinc filter (varying
|
||||
# between 24 and 48 points, with anti-aliasing)
|
||||
#resampler = linear
|
||||
|
||||
## rt-prio: (global)
|
||||
# Sets real-time priority for the mixing thread. Not all drivers may use this
|
||||
# (eg. PortAudio) as they already control the priority of the mixing thread.
|
||||
# 0 and negative values will disable it. Note that this may constitute a
|
||||
# security risk since a real-time priority thread can indefinitely block
|
||||
# normal-priority threads if it fails to wait. As such, the default is
|
||||
# disabled.
|
||||
#rt-prio = 0
|
||||
|
||||
## sources:
|
||||
# Sets the maximum number of allocatable sources. Lower values may help for
|
||||
# systems with apps that try to play more sounds than the CPU can handle.
|
||||
#sources = 256
|
||||
|
||||
## slots:
|
||||
# Sets the maximum number of Auxiliary Effect Slots an app can create. A slot
|
||||
# can use a non-negligible amount of CPU time if an effect is set on it even
|
||||
# if no sources are feeding it, so this may help when apps use more than the
|
||||
# system can handle.
|
||||
#slots = 64
|
||||
|
||||
## sends:
|
||||
# Limits the number of auxiliary sends allowed per source. Setting this higher
|
||||
# than the default has no effect.
|
||||
#sends = 16
|
||||
|
||||
## front-stablizer:
|
||||
# Applies filters to "stablize" front sound imaging. A psychoacoustic method
|
||||
# is used to generate a front-center channel signal from the front-left and
|
||||
# front-right channels, improving the front response by reducing the combing
|
||||
# artifacts and phase errors. Consequently, it will only work with channel
|
||||
# configurations that include front-left, front-right, and front-center.
|
||||
#front-stablizer = false
|
||||
|
||||
## output-limiter:
|
||||
# Applies a gain limiter on the final mixed output. This reduces the volume
|
||||
# when the output samples would otherwise clamp, avoiding excessive clipping
|
||||
# noise.
|
||||
#output-limiter = true
|
||||
|
||||
## dither:
|
||||
# Applies dithering on the final mix, for 8- and 16-bit output by default.
|
||||
# This replaces the distortion created by nearest-value quantization with low-
|
||||
# level whitenoise.
|
||||
#dither = true
|
||||
|
||||
## dither-depth:
|
||||
# Quantization bit-depth for dithered output. A value of 0 (or less) will
|
||||
# match the output sample depth. For int32, uint32, and float32 output, 0 will
|
||||
# disable dithering because they're at or beyond the rendered precision. The
|
||||
# maximum dither depth is 24.
|
||||
#dither-depth = 0
|
||||
|
||||
## volume-adjust:
|
||||
# A global volume adjustment for source output, expressed in decibels. The
|
||||
# value is logarithmic, so +6 will be a scale of (approximately) 2x, +12 will
|
||||
# be a scale of 4x, etc. Similarly, -6 will be x1/2, and -12 is about x1/4. A
|
||||
# value of 0 means no change.
|
||||
#volume-adjust = 0
|
||||
|
||||
## excludefx: (global)
|
||||
# Sets which effects to exclude, preventing apps from using them. This can
|
||||
# help for apps that try to use effects which are too CPU intensive for the
|
||||
# system to handle. Available effects are: eaxreverb,reverb,autowah,chorus,
|
||||
# compressor,distortion,echo,equalizer,flanger,modulator,dedicated,pshifter,
|
||||
# fshifter
|
||||
#excludefx =
|
||||
|
||||
## default-reverb: (global)
|
||||
# A reverb preset that applies by default to all sources on send 0
|
||||
# (applications that set their own slots on send 0 will override this).
|
||||
# Available presets are: None, Generic, PaddedCell, Room, Bathroom,
|
||||
# Livingroom, Stoneroom, Auditorium, ConcertHall, Cave, Arena, Hangar,
|
||||
# CarpetedHallway, Hallway, StoneCorridor, Alley, Forest, City, Moutains,
|
||||
# Quarry, Plain, ParkingLot, SewerPipe, Underwater, Drugged, Dizzy, Psychotic.
|
||||
#default-reverb =
|
||||
|
||||
## trap-alc-error: (global)
|
||||
# Generates a SIGTRAP signal when an ALC device error is generated, on systems
|
||||
# that support it. This helps when debugging, while trying to find the cause
|
||||
# of a device error. On Windows, a breakpoint exception is generated.
|
||||
#trap-alc-error = false
|
||||
|
||||
## trap-al-error: (global)
|
||||
# Generates a SIGTRAP signal when an AL context error is generated, on systems
|
||||
# that support it. This helps when debugging, while trying to find the cause
|
||||
# of a context error. On Windows, a breakpoint exception is generated.
|
||||
#trap-al-error = false
|
||||
|
||||
##
|
||||
## Ambisonic decoder stuff
|
||||
##
|
||||
[decoder]
|
||||
|
||||
## hq-mode:
|
||||
# Enables a high-quality ambisonic decoder. This mode is capable of frequency-
|
||||
# dependent processing, creating a better reproduction of 3D sound rendering
|
||||
# over surround sound speakers. Enabling this also requires specifying decoder
|
||||
# configuration files for the appropriate speaker configuration you intend to
|
||||
# use (see the quad, surround51, etc options below). Currently, up to third-
|
||||
# order decoding is supported.
|
||||
hq-mode = false
|
||||
|
||||
## distance-comp:
|
||||
# Enables compensation for the speakers' relative distances to the listener.
|
||||
# This applies the necessary delays and attenuation to make the speakers
|
||||
# behave as though they are all equidistant, which is important for proper
|
||||
# playback of 3D sound rendering. Requires the proper distances to be
|
||||
# specified in the decoder configuration file.
|
||||
distance-comp = true
|
||||
|
||||
## nfc:
|
||||
# Enables near-field control filters. This simulates and compensates for low-
|
||||
# frequency effects caused by the curvature of nearby sound-waves, which
|
||||
# creates a more realistic perception of sound distance. Note that the effect
|
||||
# may be stronger or weaker than intended if the application doesn't use or
|
||||
# specify an appropriate unit scale, or if incorrect speaker distances are set
|
||||
# in the decoder configuration file. Requires hq-mode to be enabled.
|
||||
nfc = true
|
||||
|
||||
## nfc-ref-delay
|
||||
# Specifies the reference delay value for ambisonic output. When channels is
|
||||
# set to one of the ambi* formats, this option enables NFC-HOA output with the
|
||||
# specified Reference Delay parameter. The specified value can then be shared
|
||||
# with an appropriate NFC-HOA decoder to reproduce correct near-field effects.
|
||||
# Keep in mind that despite being designed for higher-order ambisonics, this
|
||||
# applies to first-order output all the same. When left unset, normal output
|
||||
# is created with no near-field simulation.
|
||||
nfc-ref-delay =
|
||||
|
||||
## quad:
|
||||
# Decoder configuration file for Quadraphonic channel output. See
|
||||
# docs/ambdec.txt for a description of the file format.
|
||||
quad =
|
||||
|
||||
## surround51:
|
||||
# Decoder configuration file for 5.1 Surround (Side and Rear) channel output.
|
||||
# See docs/ambdec.txt for a description of the file format.
|
||||
surround51 =
|
||||
|
||||
## surround61:
|
||||
# Decoder configuration file for 6.1 Surround channel output. See
|
||||
# docs/ambdec.txt for a description of the file format.
|
||||
surround61 =
|
||||
|
||||
## surround71:
|
||||
# Decoder configuration file for 7.1 Surround channel output. See
|
||||
# docs/ambdec.txt for a description of the file format. Note: This can be used
|
||||
# to enable 3D7.1 with the appropriate configuration and speaker placement,
|
||||
# see docs/3D7.1.txt.
|
||||
surround71 =
|
||||
|
||||
##
|
||||
## Reverb effect stuff (includes EAX reverb)
|
||||
##
|
||||
[reverb]
|
||||
|
||||
## boost: (global)
|
||||
# A global amplification for reverb output, expressed in decibels. The value
|
||||
# is logarithmic, so +6 will be a scale of (approximately) 2x, +12 will be a
|
||||
# scale of 4x, etc. Similarly, -6 will be about half, and -12 about 1/4th. A
|
||||
# value of 0 means no change.
|
||||
#boost = 0
|
||||
|
||||
##
|
||||
## PulseAudio backend stuff
|
||||
##
|
||||
[pulse]
|
||||
|
||||
## spawn-server: (global)
|
||||
# Attempts to autospawn a PulseAudio server whenever needed (initializing the
|
||||
# backend, enumerating devices, etc). Setting autospawn to false in Pulse's
|
||||
# client.conf will still prevent autospawning even if this is set to true.
|
||||
#spawn-server = true
|
||||
|
||||
## allow-moves: (global)
|
||||
# Allows PulseAudio to move active streams to different devices. Note that the
|
||||
# device specifier (seen by applications) will not be updated when this
|
||||
# occurs, and neither will the AL device configuration (sample rate, format,
|
||||
# etc).
|
||||
#allow-moves = false
|
||||
|
||||
## fix-rate:
|
||||
# Specifies whether to match the playback stream's sample rate to the device's
|
||||
# sample rate. Enabling this forces OpenAL Soft to mix sources and effects
|
||||
# directly to the actual output rate, avoiding a second resample pass by the
|
||||
# PulseAudio server.
|
||||
#fix-rate = false
|
||||
|
||||
##
|
||||
## ALSA backend stuff
|
||||
##
|
||||
[alsa]
|
||||
|
||||
## device: (global)
|
||||
# Sets the device name for the default playback device.
|
||||
#device = default
|
||||
|
||||
## device-prefix: (global)
|
||||
# Sets the prefix used by the discovered (non-default) playback devices. This
|
||||
# will be appended with "CARD=c,DEV=d", where c is the card id and d is the
|
||||
# device index for the requested device name.
|
||||
#device-prefix = plughw:
|
||||
|
||||
## device-prefix-*: (global)
|
||||
# Card- and device-specific prefixes may be used to override the device-prefix
|
||||
# option. The option may specify the card id (eg, device-prefix-NVidia), or
|
||||
# the card id and device index (eg, device-prefix-NVidia-0). The card id is
|
||||
# case-sensitive.
|
||||
#device-prefix- =
|
||||
|
||||
## capture: (global)
|
||||
# Sets the device name for the default capture device.
|
||||
#capture = default
|
||||
|
||||
## capture-prefix: (global)
|
||||
# Sets the prefix used by the discovered (non-default) capture devices. This
|
||||
# will be appended with "CARD=c,DEV=d", where c is the card id and d is the
|
||||
# device number for the requested device name.
|
||||
#capture-prefix = plughw:
|
||||
|
||||
## capture-prefix-*: (global)
|
||||
# Card- and device-specific prefixes may be used to override the
|
||||
# capture-prefix option. The option may specify the card id (eg,
|
||||
# capture-prefix-NVidia), or the card id and device index (eg,
|
||||
# capture-prefix-NVidia-0). The card id is case-sensitive.
|
||||
#capture-prefix- =
|
||||
|
||||
## mmap:
|
||||
# Sets whether to try using mmap mode (helps reduce latencies and CPU
|
||||
# consumption). If mmap isn't available, it will automatically fall back to
|
||||
# non-mmap mode. True, yes, on, and non-0 values will attempt to use mmap. 0
|
||||
# and anything else will force mmap off.
|
||||
#mmap = true
|
||||
|
||||
## allow-resampler:
|
||||
# Specifies whether to allow ALSA's built-in resampler. Enabling this will
|
||||
# allow the playback device to be set to a different sample rate than the
|
||||
# actual output, causing ALSA to apply its own resampling pass after OpenAL
|
||||
# Soft resamples and mixes the sources and effects for output.
|
||||
#allow-resampler = false
|
||||
|
||||
##
|
||||
## OSS backend stuff
|
||||
##
|
||||
[oss]
|
||||
|
||||
## device: (global)
|
||||
# Sets the device name for OSS output.
|
||||
#device = /dev/dsp
|
||||
|
||||
## capture: (global)
|
||||
# Sets the device name for OSS capture.
|
||||
#capture = /dev/dsp
|
||||
|
||||
##
|
||||
## Solaris backend stuff
|
||||
##
|
||||
[solaris]
|
||||
|
||||
## device: (global)
|
||||
# Sets the device name for Solaris output.
|
||||
#device = /dev/audio
|
||||
|
||||
##
|
||||
## QSA backend stuff
|
||||
##
|
||||
[qsa]
|
||||
|
||||
##
|
||||
## JACK backend stuff
|
||||
##
|
||||
[jack]
|
||||
|
||||
## spawn-server: (global)
|
||||
# Attempts to autospawn a JACK server whenever needed (initializing the
|
||||
# backend, opening devices, etc).
|
||||
#spawn-server = false
|
||||
|
||||
## buffer-size:
|
||||
# Sets the update buffer size, in samples, that the backend will keep buffered
|
||||
# to handle the server's real-time processing requests. This value must be a
|
||||
# power of 2, or else it will be rounded up to the next power of 2. If it is
|
||||
# less than JACK's buffer update size, it will be clamped. This option may
|
||||
# be useful in case the server's update size is too small and doesn't give the
|
||||
# mixer time to keep enough audio available for the processing requests.
|
||||
#buffer-size = 0
|
||||
|
||||
##
|
||||
## WASAPI backend stuff
|
||||
##
|
||||
[wasapi]
|
||||
|
||||
##
|
||||
## DirectSound backend stuff
|
||||
##
|
||||
[dsound]
|
||||
|
||||
##
|
||||
## Windows Multimedia backend stuff
|
||||
##
|
||||
[winmm]
|
||||
|
||||
##
|
||||
## PortAudio backend stuff
|
||||
##
|
||||
[port]
|
||||
|
||||
## device: (global)
|
||||
# Sets the device index for output. Negative values will use the default as
|
||||
# given by PortAudio itself.
|
||||
#device = -1
|
||||
|
||||
## capture: (global)
|
||||
# Sets the device index for capture. Negative values will use the default as
|
||||
# given by PortAudio itself.
|
||||
#capture = -1
|
||||
|
||||
##
|
||||
## Wave File Writer stuff
|
||||
##
|
||||
[wave]
|
||||
|
||||
## file: (global)
|
||||
# Sets the filename of the wave file to write to. An empty name prevents the
|
||||
# backend from opening, even when explicitly requested.
|
||||
# THIS WILL OVERWRITE EXISTING FILES WITHOUT QUESTION!
|
||||
file = output.wav
|
||||
|
||||
## bformat: (global)
|
||||
# Creates AMB format files using first-order ambisonics instead of a standard
|
||||
# single- or multi-channel .wav file.
|
||||
#bformat = false
|
||||
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 146 B |
|
After Width: | Height: | Size: 146 B |
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 680 B |
|
After Width: | Height: | Size: 680 B |
|
After Width: | Height: | Size: 680 B |
|
After Width: | Height: | Size: 680 B |
|
After Width: | Height: | Size: 81 B |
@@ -0,0 +1 @@
|
||||
helloworld
|
||||
@@ -0,0 +1,478 @@
|
||||
-- love.audio
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
------------------------------------OBJECTS-------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- RecordingDevice (love.audio.getRecordingDevices)
|
||||
love.test.audio.RecordingDevice = function(test)
|
||||
|
||||
-- skip recording device on runners, they cant emulate it
|
||||
if GITHUB_RUNNER == true then
|
||||
return test:skipTest('cant emulate recording devices in CI')
|
||||
end
|
||||
|
||||
-- check devices first
|
||||
local devices = love.audio.getRecordingDevices()
|
||||
if #devices == 0 then
|
||||
return test:skipTest('cant test this works: no recording devices found')
|
||||
end
|
||||
|
||||
-- check object created and basics
|
||||
local device = devices[1]
|
||||
test:assertObject(device)
|
||||
test:assertMatch({1, 2}, device:getChannelCount(), 'check channel count is 1 or 2')
|
||||
test:assertNotEquals(nil, device:getName(), 'check has name')
|
||||
|
||||
-- check initial data is empty as we haven't recorded anything yet
|
||||
test:assertNotNil(device:getBitDepth())
|
||||
test:assertEquals(nil, device:getData(), 'check initial data empty')
|
||||
test:assertEquals(0, device:getSampleCount(), 'check initial sample empty')
|
||||
test:assertNotNil(device:getSampleRate())
|
||||
test:assertFalse(device:isRecording(), 'check not recording')
|
||||
|
||||
-- start recording for a short time
|
||||
local startrecording = device:start(32000, 4000, 16, 1)
|
||||
test:waitFrames(10)
|
||||
test:assertTrue(startrecording, 'check recording started')
|
||||
test:assertTrue(device:isRecording(), 'check now recording')
|
||||
test:assertEquals(4000, device:getSampleRate(), 'check sample rate set')
|
||||
test:assertEquals(16, device:getBitDepth(), 'check bit depth set')
|
||||
test:assertEquals(1, device:getChannelCount(), 'check channel count set')
|
||||
local recording = device:stop()
|
||||
test:waitFrames(10)
|
||||
|
||||
-- after recording
|
||||
test:assertFalse(device:isRecording(), 'check not recording')
|
||||
test:assertEquals(nil, device:getData(), 'using stop should clear buffer')
|
||||
test:assertObject(recording)
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- Source (love.audio.newSource)
|
||||
love.test.audio.Source = function(test)
|
||||
|
||||
-- create stereo source
|
||||
local stereo = love.audio.newSource('resources/click.ogg', 'static')
|
||||
test:assertObject(stereo)
|
||||
|
||||
-- check stereo props
|
||||
test:assertEquals(2, stereo:getChannelCount(), 'check stereo src')
|
||||
test:assertRange(stereo:getDuration("seconds"), 0, 0.1, 'check stereo seconds')
|
||||
test:assertNotNil(stereo:getFreeBufferCount())
|
||||
test:assertEquals('static', stereo:getType(), 'check stereo type')
|
||||
|
||||
-- check cloning a stereo
|
||||
local clone = stereo:clone()
|
||||
test:assertEquals(2, clone:getChannelCount(), 'check clone stereo src')
|
||||
test:assertRange(clone:getDuration("seconds"), 0, 0.1, 'check clone stereo seconds')
|
||||
test:assertNotNil(clone:getFreeBufferCount())
|
||||
test:assertEquals('static', clone:getType(), 'check cloned stereo type')
|
||||
|
||||
-- mess with stereo playing
|
||||
test:assertFalse(stereo:isPlaying(), 'check not playing')
|
||||
stereo:setLooping(true)
|
||||
stereo:play()
|
||||
test:assertTrue(stereo:isPlaying(), 'check now playing')
|
||||
test:assertTrue(stereo:isLooping(), 'check now playing')
|
||||
stereo:pause()
|
||||
stereo:seek(0.01, 'seconds')
|
||||
test:assertEquals(0.01, stereo:tell('seconds'), 'check seek/tell')
|
||||
stereo:stop()
|
||||
test:assertFalse(stereo:isPlaying(), 'check stopped playing')
|
||||
|
||||
-- check volume limits
|
||||
stereo:setVolumeLimits(0.1, 0.5)
|
||||
local min, max = stereo:getVolumeLimits()
|
||||
test:assertRange(min, 0.1, 0.2, 'check min limit')
|
||||
test:assertRange(max, 0.5, 0.6, 'check max limit')
|
||||
|
||||
-- check setting volume
|
||||
stereo:setVolume(1)
|
||||
test:assertEquals(1, stereo:getVolume(), 'check set volume')
|
||||
stereo:setVolume(0)
|
||||
test:assertEquals(0, stereo:getVolume(), 'check set volume')
|
||||
|
||||
-- change some get/set props that can apply to stereo
|
||||
stereo:setPitch(2)
|
||||
test:assertEquals(2, stereo:getPitch(), 'check pitch change')
|
||||
|
||||
-- create mono source
|
||||
local mono = love.audio.newSource('resources/clickmono.ogg', 'stream')
|
||||
test:assertObject(mono)
|
||||
test:assertEquals(1, mono:getChannelCount(), 'check mono src')
|
||||
test:assertEquals(2927, mono:getDuration("samples"), 'check mono seconds')
|
||||
test:assertEquals('stream', mono:getType(), 'check mono type')
|
||||
|
||||
-- air absorption
|
||||
test:assertEquals(0, mono:getAirAbsorption(), 'get air absorption')
|
||||
mono:setAirAbsorption(1)
|
||||
test:assertEquals(1, mono:getAirAbsorption(), 'set air absorption')
|
||||
|
||||
-- cone
|
||||
mono:setCone(0, 90*(math.pi/180), 1)
|
||||
local ia, oa, ov = mono:getCone()
|
||||
test:assertEquals(0, ia, 'check cone ia')
|
||||
test:assertEquals(math.floor(9000*(math.pi/180)), math.floor(oa*100), 'check cone oa')
|
||||
test:assertEquals(1, ov, 'check cone ov')
|
||||
|
||||
-- direction
|
||||
mono:setDirection(3, 1, -1)
|
||||
local x, y, z = mono:getDirection()
|
||||
test:assertEquals(3, x, 'check direction x')
|
||||
test:assertEquals(1, y, 'check direction y')
|
||||
test:assertEquals(-1, z, 'check direction z')
|
||||
|
||||
-- relative
|
||||
mono:setRelative(true)
|
||||
test:assertTrue(mono:isRelative(), 'check set relative')
|
||||
|
||||
-- position
|
||||
mono:setPosition(1, 2, 3)
|
||||
x, y, z = mono:getPosition()
|
||||
test:assertEquals(x, 1, 'check pos x')
|
||||
test:assertEquals(y, 2, 'check pos y')
|
||||
test:assertEquals(z, 3, 'check pos z')
|
||||
|
||||
-- velocity
|
||||
mono:setVelocity(1, 3, 4)
|
||||
x, y, z = mono:getVelocity()
|
||||
test:assertEquals(x, 1, 'check velocity x')
|
||||
test:assertEquals(y, 3, 'check velocity x')
|
||||
test:assertEquals(z, 4, 'check velocity x')
|
||||
|
||||
-- rolloff
|
||||
mono:setRolloff(1)
|
||||
test:assertEquals(1, mono:getRolloff(), 'check rolloff set')
|
||||
|
||||
-- create queue source
|
||||
local queue = love.audio.newQueueableSource(44100, 16, 1, 3)
|
||||
local sdata = love.sound.newSoundData(1024, 44100, 16, 1)
|
||||
test:assertObject(queue)
|
||||
local run = queue:queue(sdata)
|
||||
test:assertTrue(run, 'check queued sound')
|
||||
queue:stop()
|
||||
|
||||
-- check making a filer
|
||||
local setfilter = stereo:setFilter({
|
||||
type = 'lowpass',
|
||||
volume = 0.5,
|
||||
highgain = 0.3
|
||||
})
|
||||
test:assertTrue(setfilter, 'check filter applied')
|
||||
local filter = stereo:getFilter()
|
||||
test:assertEquals('lowpass', filter.type, 'check filter type')
|
||||
test:assertEquals(0.5, filter.volume, 'check filter volume')
|
||||
test:assertRange(filter.highgain, 0.3, 0.4, 'check filter highgain')
|
||||
test:assertEquals(nil, filter.lowgain, 'check filter lowgain')
|
||||
|
||||
-- add an effect
|
||||
local effsource = love.audio.newSource('resources/click.ogg', 'static')
|
||||
love.audio.setEffect('testeffect', {
|
||||
type = 'flanger',
|
||||
volume = 10
|
||||
})
|
||||
local seteffect, err = effsource:setEffect('testeffect', {
|
||||
type = 'highpass',
|
||||
volume = 0.3,
|
||||
lowgain = 0.1
|
||||
})
|
||||
|
||||
-- both these fail on 12 using stereo or mono, no err
|
||||
test:assertTrue(seteffect, 'check effect was applied')
|
||||
local filtersettings = effsource:getEffect('effectthatdoesntexist', {})
|
||||
test:assertNotNil(filtersettings)
|
||||
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
------------------------------------METHODS-------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- love.audio.getActiveEffects
|
||||
love.test.audio.getActiveEffects = function(test)
|
||||
-- check we get a value
|
||||
test:assertNotNil(love.audio.getActiveEffects())
|
||||
-- check setting an effect active
|
||||
love.audio.setEffect('testeffect', {
|
||||
type = 'chorus',
|
||||
volume = 10
|
||||
})
|
||||
test:assertEquals(1, #love.audio.getActiveEffects(), 'check 1 effect running')
|
||||
test:assertEquals('testeffect', love.audio.getActiveEffects()[1], 'check effect details')
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.getActiveSourceCount
|
||||
love.test.audio.getActiveSourceCount = function(test)
|
||||
-- check we get a value
|
||||
test:assertNotNil(love.audio.getActiveSourceCount())
|
||||
-- check source isn't active by default
|
||||
local testsource = love.audio.newSource('resources/click.ogg', 'static')
|
||||
test:assertEquals(0, love.audio.getActiveSourceCount(), 'check not active')
|
||||
-- check playing a source marks it as active
|
||||
love.audio.play(testsource)
|
||||
test:assertEquals(1, love.audio.getActiveSourceCount(), 'check now active')
|
||||
love.audio.pause()
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.getDistanceModel
|
||||
love.test.audio.getDistanceModel = function(test)
|
||||
-- check we get a value
|
||||
test:assertNotNil(love.audio.getDistanceModel())
|
||||
-- check default value from documentation
|
||||
test:assertEquals('inverseclamped', love.audio.getDistanceModel(), 'check default value')
|
||||
-- check get correct value after setting
|
||||
love.audio.setDistanceModel('inverse')
|
||||
test:assertEquals('inverse', love.audio.getDistanceModel(), 'check setting model')
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.getDopplerScale
|
||||
love.test.audio.getDopplerScale = function(test)
|
||||
-- check default value
|
||||
test:assertEquals(1, love.audio.getDopplerScale(), 'check default 1')
|
||||
-- check correct value after setting to 0
|
||||
love.audio.setDopplerScale(0)
|
||||
test:assertEquals(0, love.audio.getDopplerScale(), 'check setting to 0')
|
||||
love.audio.setDopplerScale(1)
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.getEffect
|
||||
love.test.audio.getEffect = function(test)
|
||||
-- check getting a non-existent effect
|
||||
test:assertEquals(nil, love.audio.getEffect('madeupname'), 'check wrong name')
|
||||
-- check getting a valid effect
|
||||
love.audio.setEffect('testeffect', {
|
||||
type = 'chorus',
|
||||
volume = 10
|
||||
})
|
||||
test:assertNotNil(love.audio.getEffect('testeffect'))
|
||||
-- check effect values match creation values
|
||||
test:assertEquals('chorus', love.audio.getEffect('testeffect').type, 'check effect type')
|
||||
test:assertEquals(10, love.audio.getEffect('testeffect').volume, 'check effect volume')
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.getMaxSceneEffects
|
||||
-- @NOTE feel like this is platform specific number so best we can do is a nil?
|
||||
love.test.audio.getMaxSceneEffects = function(test)
|
||||
test:assertNotNil(love.audio.getMaxSceneEffects())
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.getMaxSourceEffects
|
||||
-- @NOTE feel like this is platform specific number so best we can do is a nil?
|
||||
love.test.audio.getMaxSourceEffects = function(test)
|
||||
test:assertNotNil(love.audio.getMaxSourceEffects())
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.getOrientation
|
||||
-- @NOTE is there an expected default listener pos?
|
||||
love.test.audio.getOrientation = function(test)
|
||||
-- checking getting values matches what was set
|
||||
love.audio.setOrientation(1, 2, 3, 4, 5, 6)
|
||||
local fx, fy, fz, ux, uy, uz = love.audio.getOrientation()
|
||||
test:assertEquals(1, fx, 'check fx orientation')
|
||||
test:assertEquals(2, fy, 'check fy orientation')
|
||||
test:assertEquals(3, fz, 'check fz orientation')
|
||||
test:assertEquals(4, ux, 'check ux orientation')
|
||||
test:assertEquals(5, uy, 'check uy orientation')
|
||||
test:assertEquals(6, uz, 'check uz orientation')
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.getPosition
|
||||
-- @NOTE is there an expected default listener pos?
|
||||
love.test.audio.getPosition = function(test)
|
||||
-- check getting values matches what was set
|
||||
love.audio.setPosition(1, 2, 3)
|
||||
local x, y, z = love.audio.getPosition()
|
||||
test:assertEquals(1, x, 'check x position')
|
||||
test:assertEquals(2, y, 'check y position')
|
||||
test:assertEquals(3, z, 'check z position')
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.getRecordingDevices
|
||||
-- @NOTE hardware dependent so best can do is not nil check
|
||||
love.test.audio.getRecordingDevices = function(test)
|
||||
test:assertNotNil(love.audio.getRecordingDevices())
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.getVelocity
|
||||
love.test.audio.getVelocity = function(test)
|
||||
-- check getting values matches what was set
|
||||
love.audio.setVelocity(1, 2, 3)
|
||||
local x, y, z = love.audio.getVelocity()
|
||||
test:assertEquals(1, x, 'check x velocity')
|
||||
test:assertEquals(2, y, 'check y velocity')
|
||||
test:assertEquals(3, z, 'check z velocity')
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.getVolume
|
||||
love.test.audio.getVolume = function(test)
|
||||
-- check getting values matches what was set
|
||||
love.audio.setVolume(0.5)
|
||||
test:assertEquals(0.5, love.audio.getVolume(), 'check matches set')
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.isEffectsSupported
|
||||
love.test.audio.isEffectsSupported = function(test)
|
||||
test:assertNotNil(love.audio.isEffectsSupported())
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.newQueueableSource
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.audio.newQueueableSource = function(test)
|
||||
test:assertObject(love.audio.newQueueableSource(32, 8, 1, 8))
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.newSource
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.audio.newSource = function(test)
|
||||
test:assertObject(love.audio.newSource('resources/click.ogg', 'static'))
|
||||
test:assertObject(love.audio.newSource('resources/click.ogg', 'stream'))
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.pause
|
||||
love.test.audio.pause = function(test)
|
||||
-- check nothing paused (as should be nothing playing)
|
||||
local nopauses = love.audio.pause()
|
||||
test:assertEquals(0, #nopauses, 'check nothing paused')
|
||||
-- check 1 source paused after playing/pausing 1
|
||||
local source = love.audio.newSource('resources/click.ogg', 'static')
|
||||
love.audio.play(source)
|
||||
local onepause = love.audio.pause()
|
||||
test:assertEquals(1, #onepause, 'check 1 paused')
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.play
|
||||
love.test.audio.play = function(test)
|
||||
-- check playing source is detected
|
||||
local source = love.audio.newSource('resources/click.ogg', 'static')
|
||||
love.audio.play(source)
|
||||
test:assertTrue(source:isPlaying(), 'check something playing')
|
||||
love.audio.pause()
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.setDistanceModel
|
||||
love.test.audio.setDistanceModel = function(test)
|
||||
-- check setting each of the distance models is accepted and val returned
|
||||
local distancemodel = {
|
||||
'none', 'inverse', 'inverseclamped', 'linear', 'linearclamped',
|
||||
'exponent', 'exponentclamped'
|
||||
}
|
||||
for d=1,#distancemodel do
|
||||
love.audio.setDistanceModel(distancemodel[d])
|
||||
test:assertEquals(distancemodel[d], love.audio.getDistanceModel(),
|
||||
'check model set to ' .. distancemodel[d])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.setDopplerScale
|
||||
love.test.audio.setDopplerScale = function(test)
|
||||
-- check setting value is returned properly
|
||||
love.audio.setDopplerScale(0)
|
||||
test:assertEquals(0, love.audio.getDopplerScale(), 'check set to 0')
|
||||
love.audio.setDopplerScale(1)
|
||||
test:assertEquals(1, love.audio.getDopplerScale(), 'check set to 1')
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.setEffect
|
||||
love.test.audio.setEffect = function(test)
|
||||
-- check effect is set correctly
|
||||
local effect = love.audio.setEffect('testeffect', {
|
||||
type = 'chorus',
|
||||
volume = 10
|
||||
})
|
||||
test:assertTrue(effect, 'check effect created')
|
||||
-- check values set match
|
||||
local settings = love.audio.getEffect('testeffect')
|
||||
test:assertEquals('chorus', settings.type, 'check effect type')
|
||||
test:assertEquals(10, settings.volume, 'check effect volume')
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.setMixWithSystem
|
||||
love.test.audio.setMixWithSystem = function(test)
|
||||
test:assertNotNil(love.audio.setMixWithSystem(true))
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.setOrientation
|
||||
love.test.audio.setOrientation = function(test)
|
||||
-- check setting orientation vals are returned
|
||||
love.audio.setOrientation(1, 2, 3, 4, 5, 6)
|
||||
local fx, fy, fz, ux, uy, uz = love.audio.getOrientation()
|
||||
test:assertEquals(1, fx, 'check fx orientation')
|
||||
test:assertEquals(2, fy, 'check fy orientation')
|
||||
test:assertEquals(3, fz, 'check fz orientation')
|
||||
test:assertEquals(4, ux, 'check ux orientation')
|
||||
test:assertEquals(5, uy, 'check uy orientation')
|
||||
test:assertEquals(6, uz, 'check uz orientation')
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.setPosition
|
||||
love.test.audio.setPosition = function(test)
|
||||
-- check setting position vals are returned
|
||||
love.audio.setPosition(1, 2, 3)
|
||||
local x, y, z = love.audio.getPosition()
|
||||
test:assertEquals(1, x, 'check x position')
|
||||
test:assertEquals(2, y, 'check y position')
|
||||
test:assertEquals(3, z, 'check z position')
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.setVelocity
|
||||
love.test.audio.setVelocity = function(test)
|
||||
-- check setting velocity vals are returned
|
||||
love.audio.setVelocity(1, 2, 3)
|
||||
local x, y, z = love.audio.getVelocity()
|
||||
test:assertEquals(1, x, 'check x velocity')
|
||||
test:assertEquals(2, y, 'check y velocity')
|
||||
test:assertEquals(3, z, 'check z velocity')
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.setVolume
|
||||
love.test.audio.setVolume = function(test)
|
||||
-- check setting volume works
|
||||
love.audio.setVolume(0.5)
|
||||
test:assertEquals(0.5, love.audio.getVolume(), 'check set to 0.5')
|
||||
end
|
||||
|
||||
|
||||
-- love.audio.stop
|
||||
love.test.audio.stop = function(test)
|
||||
-- check source is playing first
|
||||
local source = love.audio.newSource('resources/click.ogg', 'static')
|
||||
love.audio.play(source)
|
||||
test:assertTrue(source:isPlaying(), 'check is playing')
|
||||
-- check source is then stopped
|
||||
love.audio.stop()
|
||||
test:assertFalse(source:isPlaying(), 'check stopped playing')
|
||||
end
|
||||
@@ -0,0 +1,251 @@
|
||||
-- love.data
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
------------------------------------OBJECTS-------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- ByteData (love.data.newByteData)
|
||||
love.test.data.ByteData = function(test)
|
||||
|
||||
-- create new obj
|
||||
local data = love.data.newByteData('helloworld')
|
||||
test:assertObject(data)
|
||||
|
||||
-- check properties match expected
|
||||
test:assertEquals('helloworld', data:getString(), 'check data string')
|
||||
test:assertEquals(10, data:getSize(), 'check data size')
|
||||
|
||||
-- check cloning the bytedata
|
||||
local cloneddata = data:clone()
|
||||
test:assertObject(cloneddata)
|
||||
test:assertEquals('helloworld', cloneddata:getString(), 'check cloned data')
|
||||
test:assertEquals(10, cloneddata:getSize(), 'check cloned size')
|
||||
|
||||
-- check pointer access if allowed
|
||||
if data:getFFIPointer() ~= nil and ffi ~= nil then
|
||||
local pointer = data:getFFIPointer()
|
||||
local ptr = ffi.cast('uint8_t*', pointer)
|
||||
local byte5 = ptr[4]
|
||||
test:assertEquals('o', byte5)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- CompressedData (love.data.compress)
|
||||
love.test.data.CompressedData = function(test)
|
||||
|
||||
-- create new compressed data
|
||||
local cdata = love.data.compress('data', 'zlib', 'helloworld', -1)
|
||||
test:assertObject(cdata)
|
||||
test:assertEquals('zlib', cdata:getFormat(), 'check format used')
|
||||
|
||||
-- check properties match expected
|
||||
test:assertEquals(18, cdata:getSize())
|
||||
test:assertEquals('helloworld', love.data.decompress('data', cdata):getString())
|
||||
|
||||
-- check cloning the data
|
||||
local clonedcdata = cdata:clone()
|
||||
test:assertObject(clonedcdata)
|
||||
test:assertEquals('zlib', clonedcdata:getFormat())
|
||||
test:assertEquals(18, clonedcdata:getSize())
|
||||
test:assertEquals('helloworld', love.data.decompress('data', clonedcdata):getString())
|
||||
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
------------------------------------METHODS-------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- love.data.compress
|
||||
love.test.data.compress = function(test)
|
||||
-- here just testing each combo 'works' - in decompress's test method
|
||||
-- we actually check the compress + decompress give the right value back
|
||||
local compressions = {
|
||||
{ love.data.compress('string', 'lz4', 'helloworld', -1), 'string'},
|
||||
{ love.data.compress('string', 'lz4', 'helloworld', 0), 'string'},
|
||||
{ love.data.compress('string', 'lz4', 'helloworld', 9), 'string'},
|
||||
{ love.data.compress('string', 'zlib', 'helloworld', -1), 'string'},
|
||||
{ love.data.compress('string', 'zlib', 'helloworld', 0), 'string'},
|
||||
{ love.data.compress('string', 'zlib', 'helloworld', 9), 'string'},
|
||||
{ love.data.compress('string', 'gzip', 'helloworld', -1), 'string'},
|
||||
{ love.data.compress('string', 'gzip', 'helloworld', 0), 'string'},
|
||||
{ love.data.compress('string', 'gzip', 'helloworld', 9), 'string'},
|
||||
{ love.data.compress('data', 'lz4', 'helloworld', -1), 'userdata'},
|
||||
{ love.data.compress('data', 'lz4', 'helloworld', 0), 'userdata'},
|
||||
{ love.data.compress('data', 'lz4', 'helloworld', 9), 'userdata'},
|
||||
{ love.data.compress('data', 'zlib', 'helloworld', -1), 'userdata'},
|
||||
{ love.data.compress('data', 'zlib', 'helloworld', 0), 'userdata'},
|
||||
{ love.data.compress('data', 'zlib', 'helloworld', 9), 'userdata'},
|
||||
{ love.data.compress('data', 'gzip', 'helloworld', -1), 'userdata'},
|
||||
{ love.data.compress('data', 'gzip', 'helloworld', 0), 'userdata'},
|
||||
{ love.data.compress('data', 'gzip', 'helloworld', 9), 'userdata'}
|
||||
}
|
||||
for c=1,#compressions do
|
||||
test:assertNotNil(compressions[c][1])
|
||||
-- sense check return type and make sure bytedata returns are an object
|
||||
test:assertEquals(compressions[c][2], type(compressions[c][1]), 'check is userdata')
|
||||
if compressions[c][2] == 'userdata' then
|
||||
test:assertNotEquals(nil, compressions[c][1]:type(), 'check has :type()')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- love.data.decode
|
||||
love.test.data.decode = function(test)
|
||||
-- setup encoded strings
|
||||
local str1 = love.data.encode('string', 'base64', 'helloworld', 0)
|
||||
local str2 = love.data.encode('string', 'hex', 'helloworld')
|
||||
local str3 = love.data.encode('data', 'base64', 'helloworld', 0)
|
||||
local str4 = love.data.encode('data', 'hex', 'helloworld')
|
||||
-- check value matches expected when decoded back
|
||||
test:assertEquals('helloworld', love.data.decode('string', 'base64', str1), 'check string base64 decode')
|
||||
test:assertEquals('helloworld', love.data.decode('string', 'hex', str2), 'check string hex decode')
|
||||
test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decode('data', 'base64', str3):getString(), 'check data base64 decode')
|
||||
test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decode('data', 'hex', str4):getString(), 'check data hex decode')
|
||||
end
|
||||
|
||||
|
||||
-- love.data.decompress
|
||||
love.test.data.decompress = function(test)
|
||||
-- setup compressed data for each combination
|
||||
local str1 = love.data.compress('string', 'lz4', 'helloworld', -1)
|
||||
local str2 = love.data.compress('string', 'lz4', 'helloworld', 0)
|
||||
local str3 = love.data.compress('string', 'lz4', 'helloworld', 9)
|
||||
local str4 = love.data.compress('string', 'zlib', 'helloworld', -1)
|
||||
local str5 = love.data.compress('string', 'zlib', 'helloworld', 0)
|
||||
local str6 = love.data.compress('string', 'zlib', 'helloworld', 9)
|
||||
local str7 = love.data.compress('string', 'gzip', 'helloworld', -1)
|
||||
local str8 = love.data.compress('string', 'gzip', 'helloworld', 0)
|
||||
local str9 = love.data.compress('string', 'gzip', 'helloworld', 9)
|
||||
local str10 = love.data.compress('data', 'lz4', 'helloworld', -1)
|
||||
local str11 = love.data.compress('data', 'lz4', 'helloworld', 0)
|
||||
local str12 = love.data.compress('data', 'lz4', 'helloworld', 9)
|
||||
local str13 = love.data.compress('data', 'zlib', 'helloworld', -1)
|
||||
local str14 = love.data.compress('data', 'zlib', 'helloworld', 0)
|
||||
local str15 = love.data.compress('data', 'zlib', 'helloworld', 9)
|
||||
local str16 = love.data.compress('data', 'gzip', 'helloworld', -1)
|
||||
local str17 = love.data.compress('data', 'gzip', 'helloworld', 0)
|
||||
local str18 = love.data.compress('data', 'gzip', 'helloworld', 9)
|
||||
-- check decompressed value matches whats expected
|
||||
test:assertEquals('helloworld', love.data.decompress('string', 'lz4', str1), 'check string lz4 decompress')
|
||||
test:assertEquals('helloworld', love.data.decompress('string', 'lz4', str2), 'check string lz4 decompress')
|
||||
test:assertEquals('helloworld', love.data.decompress('string', 'lz4', str3), 'check string lz4 decompress')
|
||||
test:assertEquals('helloworld', love.data.decompress('string', 'zlib', str4), 'check string zlib decompress')
|
||||
test:assertEquals('helloworld', love.data.decompress('string', 'zlib', str5), 'check string zlib decompress')
|
||||
test:assertEquals('helloworld', love.data.decompress('string', 'zlib', str6), 'check string zlib decompress')
|
||||
test:assertEquals('helloworld', love.data.decompress('string', 'gzip', str7), 'check string glib decompress')
|
||||
test:assertEquals('helloworld', love.data.decompress('string', 'gzip', str8), 'check string glib decompress')
|
||||
test:assertEquals('helloworld', love.data.decompress('string', 'gzip', str9), 'check string glib decompress')
|
||||
test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decompress('data', 'lz4', str10):getString(), 'check data lz4 decompress')
|
||||
test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decompress('data', 'lz4', str11):getString(), 'check data lz4 decompress')
|
||||
test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decompress('data', 'lz4', str12):getString(), 'check data lz4 decompress')
|
||||
test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decompress('data', 'zlib', str13):getString(), 'check data zlib decompress')
|
||||
test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decompress('data', 'zlib', str14):getString(), 'check data zlib decompress')
|
||||
test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decompress('data', 'zlib', str15):getString(), 'check data zlib decompress')
|
||||
test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decompress('data', 'gzip', str16):getString(), 'check data glib decompress')
|
||||
test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decompress('data', 'gzip', str17):getString(), 'check data glib decompress')
|
||||
test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decompress('data', 'gzip', str18):getString(), 'check data glib decompress')
|
||||
end
|
||||
|
||||
|
||||
-- love.data.encode
|
||||
love.test.data.encode = function(test)
|
||||
-- here just testing each combo 'works' - in decode's test method
|
||||
-- we actually check the encode + decode give the right value back
|
||||
local encodes = {
|
||||
{ love.data.encode('string', 'base64', 'helloworld', 0), 'string'},
|
||||
{ love.data.encode('string', 'base64', 'helloworld', 2), 'string'},
|
||||
{ love.data.encode('string', 'hex', 'helloworld'), 'string'},
|
||||
{ love.data.encode('data', 'base64', 'helloworld', 0), 'userdata'},
|
||||
{ love.data.encode('data', 'base64', 'helloworld', 2), 'userdata'},
|
||||
{ love.data.encode('data', 'hex', 'helloworld'), 'userdata'}
|
||||
}
|
||||
for e=1,#encodes do
|
||||
test:assertNotNil(encodes[e][1])
|
||||
-- sense check return type and make sure bytedata returns are an object
|
||||
test:assertEquals(encodes[e][2], type(encodes[e][1]), 'check is usedata')
|
||||
if encodes[e][2] == 'userdata' then
|
||||
test:assertNotEquals(nil, encodes[e][1]:type(), 'check has :type()')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- love.data.getPackedSize
|
||||
love.test.data.getPackedSize = function(test)
|
||||
local pack1 = love.data.getPackedSize('>xI3b')
|
||||
local pack2 = love.data.getPackedSize('>I2B')
|
||||
local pack3 = love.data.getPackedSize('>I4I4I4I4x')
|
||||
test:assertEquals(5, pack1, 'check pack size 1')
|
||||
test:assertEquals(3, pack2, 'check pack size 2')
|
||||
test:assertEquals(17, pack3, 'check pack size 3')
|
||||
end
|
||||
|
||||
|
||||
-- love.data.hash
|
||||
love.test.data.hash = function(test)
|
||||
-- setup all the different hashing types
|
||||
local str1 = love.data.hash('md5', 'helloworld')
|
||||
local str2 = love.data.hash('sha1', 'helloworld')
|
||||
local str3 = love.data.hash('sha224', 'helloworld')
|
||||
local str4 = love.data.hash('sha256', 'helloworld')
|
||||
local str5 = love.data.hash('sha384', 'helloworld')
|
||||
local str6 = love.data.hash('sha512', 'helloworld')
|
||||
-- check encoded hash value matches what's expected for that algo
|
||||
test:assertEquals('fc5e038d38a57032085441e7fe7010b0', love.data.encode("string", "hex", str1), 'check md5 encode')
|
||||
test:assertEquals('6adfb183a4a2c94a2f92dab5ade762a47889a5a1', love.data.encode("string", "hex", str2), 'check sha1 encode')
|
||||
test:assertEquals('b033d770602994efa135c5248af300d81567ad5b59cec4bccbf15bcc', love.data.encode("string", "hex", str3), 'check sha224 encode')
|
||||
test:assertEquals('936a185caaa266bb9cbe981e9e05cb78cd732b0b3280eb944412bb6f8f8f07af', love.data.encode("string", "hex", str4), 'check sha256 encode')
|
||||
test:assertEquals('97982a5b1414b9078103a1c008c4e3526c27b41cdbcf80790560a40f2a9bf2ed4427ab1428789915ed4b3dc07c454bd9', love.data.encode("string", "hex", str5), 'check sha384 encode')
|
||||
test:assertEquals('1594244d52f2d8c12b142bb61f47bc2eaf503d6d9ca8480cae9fcf112f66e4967dc5e8fa98285e36db8af1b8ffa8b84cb15e0fbcf836c3deb803c13f37659a60', love.data.encode("string", "hex", str6), 'check sha512 encode')
|
||||
end
|
||||
|
||||
|
||||
-- love.data.newByteData
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.data.newByteData = function(test)
|
||||
test:assertObject(love.data.newByteData('helloworld'))
|
||||
end
|
||||
|
||||
|
||||
-- love.data.newDataView
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.data.newDataView = function(test)
|
||||
test:assertObject(love.data.newDataView(love.data.newByteData('helloworld'), 0, 10))
|
||||
end
|
||||
|
||||
|
||||
-- love.data.pack
|
||||
love.test.data.pack = function(test)
|
||||
local packed1 = love.data.pack('string', '>I4I4I4I4', 9999, 1000, 1010, 2030)
|
||||
local packed2 = love.data.pack('data', '>I4I4I4I4', 9999, 1000, 1010, 2030)
|
||||
local a, b, c, d = love.data.unpack('>I4I4I4I4', packed1)
|
||||
local e, f, g, h = love.data.unpack('>I4I4I4I4', packed2)
|
||||
test:assertEquals(9999+9999, a+e, 'check packed 1')
|
||||
test:assertEquals(1000+1000, b+f, 'check packed 2')
|
||||
test:assertEquals(1010+1010, c+g, 'check packed 3')
|
||||
test:assertEquals(2030+2030, d+h, 'check packed 4')
|
||||
end
|
||||
|
||||
|
||||
-- love.data.unpack
|
||||
love.test.data.unpack = function(test)
|
||||
local packed1 = love.data.pack('string', '>s5s4I3', 'hello', 'love', 100)
|
||||
local packed2 = love.data.pack('data', '>s5I2', 'world', 20)
|
||||
local a, b, c = love.data.unpack('>s5s4I3', packed1)
|
||||
local d, e = love.data.unpack('>s5I2', packed2)
|
||||
test:assertEquals(a .. ' ' .. d, 'hello world', 'check unpack 1')
|
||||
test:assertEquals(b, 'love', 'check unpack 2')
|
||||
test:assertEquals(c - e, 80, 'check unpack 3')
|
||||
end
|
||||
@@ -0,0 +1,80 @@
|
||||
-- love.event
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
------------------------------------METHODS-------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- love.event.clear
|
||||
love.test.event.clear = function(test)
|
||||
-- push some events first
|
||||
love.event.push('test', 1, 2, 3)
|
||||
love.event.push('test', 1, 2, 3)
|
||||
love.event.push('test', 1, 2, 3)
|
||||
-- check after calling clear there are no events left
|
||||
love.event.clear()
|
||||
local count = 0
|
||||
for n, a, b, c, d, e, f in love.event.poll() do
|
||||
count = count + 1
|
||||
end
|
||||
test:assertEquals(0, count, 'check no events')
|
||||
end
|
||||
|
||||
|
||||
-- love.event.poll
|
||||
love.test.event.poll = function(test)
|
||||
-- push some events first
|
||||
love.event.push('test', 1, 2, 3)
|
||||
love.event.push('test', 1, 2, 3)
|
||||
love.event.push('test', 1, 2, 3)
|
||||
-- check poll recieves all events
|
||||
local count = 0
|
||||
for n, a, b, c, d, e, f in love.event.poll() do
|
||||
count = count + 1
|
||||
end
|
||||
test:assertEquals(3, count, 'check 3 events')
|
||||
end
|
||||
|
||||
|
||||
-- love.event.pump
|
||||
-- @NOTE dont think can really test as internally used
|
||||
love.test.event.pump = function(test)
|
||||
test:skipTest('used internally')
|
||||
end
|
||||
|
||||
|
||||
-- love.event.push
|
||||
love.test.event.push = function(test)
|
||||
-- check pushing some different types
|
||||
love.event.push('add', 1, 2, 3)
|
||||
love.event.push('ignore', 1, 2, 3)
|
||||
love.event.push('add', 1, 2, 3)
|
||||
love.event.push('ignore', 1, 2, 3)
|
||||
local count = 0
|
||||
for n, a, b, c, d, e, f in love.event.poll() do
|
||||
if n == 'add' then
|
||||
count = count + a + b + c
|
||||
end
|
||||
end
|
||||
test:assertEquals(12, count, 'check total events')
|
||||
end
|
||||
|
||||
|
||||
-- love.event.quit
|
||||
love.test.event.quit = function(test)
|
||||
-- setting this overrides the quit hook to prevent actually quitting
|
||||
love.test.module.fakequit = true
|
||||
love.event.quit(0)
|
||||
-- if it failed we'd have quit here
|
||||
test:assertTrue(true, 'check quit hook called')
|
||||
end
|
||||
|
||||
|
||||
-- love.event.wait
|
||||
-- @NOTE not sure best way to test this one
|
||||
love.test.event.wait = function(test)
|
||||
test:skipTest('used internally')
|
||||
end
|
||||
@@ -0,0 +1,451 @@
|
||||
-- love.filesystem
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
------------------------------------OBJECTS-------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- File (love.filesystem.newFile)
|
||||
love.test.filesystem.File = function(test)
|
||||
|
||||
-- setup a file to play with
|
||||
local file1 = love.filesystem.openFile('data.txt', 'w')
|
||||
file1:write('helloworld')
|
||||
test:assertObject(file1)
|
||||
file1:close()
|
||||
|
||||
-- test read mode
|
||||
file1:open('r')
|
||||
test:assertEquals('r', file1:getMode(), 'check read mode')
|
||||
local contents, size = file1:read()
|
||||
test:assertEquals('helloworld', contents)
|
||||
test:assertEquals(10, size, 'check file read')
|
||||
test:assertEquals(10, file1:getSize())
|
||||
local ok1, err1 = file1:write('hello')
|
||||
test:assertNotEquals(nil, err1, 'check cant write in read mode')
|
||||
local iterator = file1:lines()
|
||||
test:assertNotEquals(nil, iterator, 'check can read lines')
|
||||
test:assertEquals('data.txt', file1:getFilename(), 'check filename matches')
|
||||
file1:close()
|
||||
|
||||
-- test write mode
|
||||
file1:open('w')
|
||||
test:assertEquals('w', file1:getMode(), 'check write mode')
|
||||
contents, size = file1:read()
|
||||
test:assertEquals(nil, contents, 'check cant read file in write mode')
|
||||
test:assertEquals('string', type(size), 'check err message shown')
|
||||
local ok2, err2 = file1:write('helloworld')
|
||||
test:assertTrue(ok2, 'check file write')
|
||||
test:assertEquals(nil, err2, 'check no err writing')
|
||||
|
||||
-- test open/closing
|
||||
file1:open('r')
|
||||
test:assertTrue(file1:isOpen(), 'check file is open')
|
||||
file1:close()
|
||||
test:assertFalse(file1:isOpen(), 'check file gets closed')
|
||||
file1:close()
|
||||
|
||||
-- test buffering and flushing
|
||||
file1:open('w')
|
||||
local ok3, err3 = file1:setBuffer('full', 10000)
|
||||
test:assertTrue(ok3)
|
||||
test:assertEquals('full', file1:getBuffer())
|
||||
file1:write('replacedcontent')
|
||||
file1:flush()
|
||||
file1:close()
|
||||
file1:open('r')
|
||||
contents, size = file1:read()
|
||||
test:assertEquals('replacedcontent', contents, 'check buffered content was written')
|
||||
file1:close()
|
||||
|
||||
-- loop through file data with seek/tell until EOF
|
||||
file1:open('r')
|
||||
local counter = 0
|
||||
for i=1,100 do
|
||||
file1:seek(i)
|
||||
test:assertEquals(i, file1:tell())
|
||||
if file1:isEOF() == true then
|
||||
counter = i
|
||||
break
|
||||
end
|
||||
end
|
||||
test:assertEquals(counter, 15)
|
||||
file1:close()
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- FileData (love.filesystem.newFileData)
|
||||
love.test.filesystem.FileData = function(test)
|
||||
|
||||
-- create new obj
|
||||
local fdata = love.filesystem.newFileData('helloworld', 'test.txt')
|
||||
test:assertObject(fdata)
|
||||
test:assertEquals('test.txt', fdata:getFilename())
|
||||
test:assertEquals('txt', fdata:getExtension())
|
||||
|
||||
-- check properties match expected
|
||||
test:assertEquals('helloworld', fdata:getString(), 'check data string')
|
||||
test:assertEquals(10, fdata:getSize(), 'check data size')
|
||||
|
||||
-- check cloning the bytedata
|
||||
local clonedfdata = fdata:clone()
|
||||
test:assertObject(clonedfdata)
|
||||
test:assertEquals('helloworld', clonedfdata:getString(), 'check cloned data')
|
||||
test:assertEquals(10, clonedfdata:getSize(), 'check cloned size')
|
||||
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
------------------------------------METHODS-------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- love.filesystem.append
|
||||
love.test.filesystem.append = function(test)
|
||||
-- create a new file to test with
|
||||
love.filesystem.write('filesystem.append.txt', 'foo')
|
||||
-- try appending text and check new file contents/size matches
|
||||
local success, message = love.filesystem.append('filesystem.append.txt', 'bar')
|
||||
test:assertNotEquals(false, success, 'check success')
|
||||
test:assertEquals(nil, message, 'check no error msg')
|
||||
local contents, size = love.filesystem.read('filesystem.append.txt')
|
||||
test:assertEquals(contents, 'foobar', 'check file contents')
|
||||
test:assertEquals(size, 6, 'check file size')
|
||||
-- check appending a specific no. of bytes
|
||||
love.filesystem.append('filesystem.append.txt', 'foobarfoobarfoo', 6)
|
||||
contents, size = love.filesystem.read('filesystem.append.txt')
|
||||
test:assertEquals(contents, 'foobarfoobar', 'check appended contents')
|
||||
test:assertEquals(size, 12, 'check appended size')
|
||||
-- cleanup
|
||||
love.filesystem.remove('filesystem.append.txt')
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.areSymlinksEnabled
|
||||
-- @NOTE best can do here is just check not nil
|
||||
love.test.filesystem.areSymlinksEnabled = function(test)
|
||||
test:assertNotNil(love.filesystem.areSymlinksEnabled())
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.createDirectory
|
||||
love.test.filesystem.createDirectory = function(test)
|
||||
-- try creating a dir + subdir and check both exist
|
||||
local success = love.filesystem.createDirectory('foo/bar')
|
||||
test:assertNotEquals(false, success, 'check success')
|
||||
test:assertNotEquals(nil, love.filesystem.getInfo('foo', 'directory'), 'check directory created')
|
||||
test:assertNotEquals(nil, love.filesystem.getInfo('foo/bar', 'directory'), 'check subdirectory created')
|
||||
-- cleanup
|
||||
love.filesystem.remove('foo/bar')
|
||||
love.filesystem.remove('foo')
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.getAppdataDirectory
|
||||
-- @NOTE i think this is too platform dependent to be tested nicely
|
||||
love.test.filesystem.getAppdataDirectory = function(test)
|
||||
test:assertNotNil(love.filesystem.getAppdataDirectory())
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.getCRequirePath
|
||||
love.test.filesystem.getCRequirePath = function(test)
|
||||
-- check default value from documentation
|
||||
test:assertEquals('??', love.filesystem.getCRequirePath(), 'check default value')
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.getDirectoryItems
|
||||
love.test.filesystem.getDirectoryItems = function(test)
|
||||
-- create a dir + subdir with 2 files
|
||||
love.filesystem.createDirectory('foo/bar')
|
||||
love.filesystem.write('foo/file1.txt', 'file1')
|
||||
love.filesystem.write('foo/bar/file2.txt', 'file2')
|
||||
-- check both the file + subdir exist in the item list
|
||||
local files = love.filesystem.getDirectoryItems('foo')
|
||||
local hasfile = false
|
||||
local hasdir = false
|
||||
for _,v in ipairs(files) do
|
||||
local info = love.filesystem.getInfo('foo/'..v)
|
||||
if v == 'bar' and info.type == 'directory' then hasdir = true end
|
||||
if v == 'file1.txt' and info.type == 'file' then hasfile = true end
|
||||
end
|
||||
test:assertTrue(hasfile, 'check file exists')
|
||||
test:assertTrue(hasdir, 'check directory exists')
|
||||
-- cleanup
|
||||
love.filesystem.remove('foo/file1.txt')
|
||||
love.filesystem.remove('foo/bar/file2.txt')
|
||||
love.filesystem.remove('foo/bar')
|
||||
love.filesystem.remove('foo')
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.getIdentity
|
||||
love.test.filesystem.getIdentity = function(test)
|
||||
-- check setting identity matches
|
||||
local original = love.filesystem.getIdentity()
|
||||
love.filesystem.setIdentity('lover')
|
||||
test:assertEquals('lover', love.filesystem.getIdentity(), 'check identity matches')
|
||||
-- put back to original value
|
||||
love.filesystem.setIdentity(original)
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.getRealDirectory
|
||||
love.test.filesystem.getRealDirectory = function(test)
|
||||
-- make a test dir + file first
|
||||
love.filesystem.createDirectory('foo')
|
||||
love.filesystem.write('foo/test.txt', 'test')
|
||||
-- check save dir matches the real dir we just wrote to
|
||||
test:assertEquals(love.filesystem.getSaveDirectory(),
|
||||
love.filesystem.getRealDirectory('foo/test.txt'), 'check directory matches')
|
||||
-- cleanup
|
||||
love.filesystem.remove('foo/test.txt')
|
||||
love.filesystem.remove('foo')
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.getRequirePath
|
||||
love.test.filesystem.getRequirePath = function(test)
|
||||
test:assertEquals('?.lua;?/init.lua',
|
||||
love.filesystem.getRequirePath(), 'check default value')
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.getSource
|
||||
-- @NOTE i dont think we can test this cos love calls it first
|
||||
love.test.filesystem.getSource = function(test)
|
||||
test:skipTest('used internally')
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.getSourceBaseDirectory
|
||||
-- @NOTE i think this is too platform dependent to be tested nicely
|
||||
love.test.filesystem.getSourceBaseDirectory = function(test)
|
||||
test:assertNotNil(love.filesystem.getSourceBaseDirectory())
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.getUserDirectory
|
||||
-- @NOTE i think this is too platform dependent to be tested nicely
|
||||
love.test.filesystem.getUserDirectory = function(test)
|
||||
test:assertNotNil(love.filesystem.getUserDirectory())
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.getWorkingDirectory
|
||||
-- @NOTE i think this is too platform dependent to be tested nicely
|
||||
love.test.filesystem.getWorkingDirectory = function(test)
|
||||
test:assertNotNil(love.filesystem.getWorkingDirectory())
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.getSaveDirectory
|
||||
-- @NOTE i think this is too platform dependent to be tested nicely
|
||||
love.test.filesystem.getSaveDirectory = function(test)
|
||||
test:assertNotNil(love.filesystem.getSaveDirectory())
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.getInfo
|
||||
love.test.filesystem.getInfo = function(test)
|
||||
-- create a dir and subdir with a file
|
||||
love.filesystem.createDirectory('foo/bar')
|
||||
love.filesystem.write('foo/bar/file2.txt', 'file2')
|
||||
-- check getinfo returns the correct values
|
||||
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')
|
||||
-- @TODO test modified timestamp from info.modtime?
|
||||
-- cleanup
|
||||
love.filesystem.remove('foo/bar/file2.txt')
|
||||
love.filesystem.remove('foo/bar')
|
||||
love.filesystem.remove('foo')
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.isFused
|
||||
love.test.filesystem.isFused = function(test)
|
||||
-- kinda assuming you'd run the testsuite in a non-fused game
|
||||
test:assertEquals(love.filesystem.isFused(), false, 'check not fused')
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.lines
|
||||
love.test.filesystem.lines = function(test)
|
||||
-- check lines returns the 3 lines expected
|
||||
love.filesystem.write('file.txt', 'line1\nline2\nline3')
|
||||
local linenum = 1
|
||||
for line in love.filesystem.lines('file.txt') do
|
||||
test:assertEquals('line' .. tostring(linenum), line, 'check line matches')
|
||||
-- also check it removes newlines like the docs says it does
|
||||
test:assertEquals(nil, string.find(line, '\n'), 'check newline removed')
|
||||
linenum = linenum + 1
|
||||
end
|
||||
-- cleanup
|
||||
love.filesystem.remove('file.txt')
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.load
|
||||
love.test.filesystem.load = function(test)
|
||||
-- setup some fake lua files
|
||||
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')
|
||||
-- check invalid lua file
|
||||
local ok, chunk, err = pcall(love.filesystem.load, 'test2.lua')
|
||||
test:assertFalse(ok, 'check invalid lua file')
|
||||
-- cleanup
|
||||
love.filesystem.remove('test1.lua')
|
||||
love.filesystem.remove('test2.lua')
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.mount
|
||||
love.test.filesystem.mount = function(test)
|
||||
-- write an example zip to savedir to use
|
||||
local contents, size = love.filesystem.read('resources/test.zip') -- contains test.txt
|
||||
love.filesystem.write('test.zip', contents, size)
|
||||
-- check mounting file and check contents are mounted
|
||||
local success = love.filesystem.mount('test.zip', 'test')
|
||||
test:assertTrue(success, 'check success')
|
||||
test:assertNotEquals(nil, love.filesystem.getInfo('test'), 'check mount not nil')
|
||||
test:assertEquals('directory', love.filesystem.getInfo('test').type, 'check directory made')
|
||||
test:assertNotEquals(nil, love.filesystem.getInfo('test/test.txt'), 'check file not nil')
|
||||
test:assertEquals('file', love.filesystem.getInfo('test/test.txt').type, 'check file type')
|
||||
-- cleanup
|
||||
love.filesystem.remove('test/test.txt')
|
||||
love.filesystem.remove('test')
|
||||
love.filesystem.remove('test.zip')
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.openFile
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.filesystem.openFile = function(test)
|
||||
test:assertNotNil(love.filesystem.openFile('file2.txt', 'w'))
|
||||
test:assertNotNil(love.filesystem.openFile('file2.txt', 'r'))
|
||||
test:assertNotNil(love.filesystem.openFile('file2.txt', 'a'))
|
||||
test:assertNotNil(love.filesystem.openFile('file2.txt', 'c'))
|
||||
love.filesystem.remove('file2.txt')
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.newFileData
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.filesystem.newFileData = function(test)
|
||||
test:assertNotNil(love.filesystem.newFileData('helloworld', 'file1'))
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.read
|
||||
love.test.filesystem.read = function(test)
|
||||
-- check reading a full file
|
||||
local content, size = love.filesystem.read('resources/test.txt')
|
||||
test:assertNotEquals(nil, content, 'check not nil')
|
||||
test:assertEquals('helloworld', content, 'check content match')
|
||||
test:assertEquals(10, size, 'check size match')
|
||||
-- check reading partial file
|
||||
content, size = love.filesystem.read('resources/test.txt', 5)
|
||||
test:assertNotEquals(nil, content, 'check not nil')
|
||||
test:assertEquals('hello', content, 'check content match')
|
||||
test:assertEquals(5, size, 'check size match')
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.remove
|
||||
love.test.filesystem.remove = function(test)
|
||||
-- create a dir + subdir with a file
|
||||
love.filesystem.createDirectory('foo/bar')
|
||||
love.filesystem.write('foo/bar/file2.txt', 'helloworld')
|
||||
-- check removing files + dirs (should fail to remove dir if file inside)
|
||||
test:assertFalse(love.filesystem.remove('foo'), 'check fail when file inside')
|
||||
test:assertFalse(love.filesystem.remove('foo/bar'), 'check fail when file inside')
|
||||
test:assertTrue(love.filesystem.remove('foo/bar/file2.txt'), 'check file removed')
|
||||
test:assertTrue(love.filesystem.remove('foo/bar'), 'check subdirectory removed')
|
||||
test:assertTrue(love.filesystem.remove('foo'), 'check directory removed')
|
||||
-- cleanup not needed here hopefully...
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.setCRequirePath
|
||||
love.test.filesystem.setCRequirePath = function(test)
|
||||
-- check setting path val is returned
|
||||
love.filesystem.setCRequirePath('/??')
|
||||
test:assertEquals('/??', love.filesystem.getCRequirePath(), 'check crequirepath value')
|
||||
love.filesystem.setCRequirePath('??')
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.setIdentity
|
||||
love.test.filesystem.setIdentity = function(test)
|
||||
-- check setting identity val is returned
|
||||
local original = love.filesystem.getIdentity()
|
||||
love.filesystem.setIdentity('lover')
|
||||
test:assertEquals('lover', love.filesystem.getIdentity(), 'check indentity value')
|
||||
-- return value to original
|
||||
love.filesystem.setIdentity(original)
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.setRequirePath
|
||||
love.test.filesystem.setRequirePath = function(test)
|
||||
-- check setting path val is returned
|
||||
love.filesystem.setRequirePath('?.lua;?/start.lua')
|
||||
test:assertEquals('?.lua;?/start.lua', love.filesystem.getRequirePath(), 'check require path')
|
||||
-- reset to default
|
||||
love.filesystem.setRequirePath('?.lua;?/init.lua')
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.setSource
|
||||
love.test.filesystem.setSource = function(test)
|
||||
test:skipTest('used internally')
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.unmount
|
||||
love.test.filesystem.unmount = function(test)
|
||||
-- create a zip file mounted to use
|
||||
local contents, size = love.filesystem.read('resources/test.zip') -- contains test.txt
|
||||
love.filesystem.write('test.zip', contents, size)
|
||||
love.filesystem.mount('test.zip', 'test')
|
||||
-- check mounted, unmount, then check its unmounted
|
||||
test:assertNotEquals(nil, love.filesystem.getInfo('test/test.txt'), 'check mount exists')
|
||||
love.filesystem.unmount('test.zip')
|
||||
test:assertEquals(nil, love.filesystem.getInfo('test/test.txt'), 'check unmounted')
|
||||
-- cleanup
|
||||
love.filesystem.remove('test/test.txt')
|
||||
love.filesystem.remove('test')
|
||||
love.filesystem.remove('test.zip')
|
||||
end
|
||||
|
||||
|
||||
-- love.filesystem.write
|
||||
love.test.filesystem.write = function(test)
|
||||
-- check writing a bunch of files matches whats read back
|
||||
love.filesystem.write('test1.txt', 'helloworld')
|
||||
love.filesystem.write('test2.txt', 'helloworld', 10)
|
||||
love.filesystem.write('test3.txt', 'helloworld', 5)
|
||||
test:assertEquals('helloworld', love.filesystem.read('test1.txt'), 'check read file')
|
||||
test:assertEquals('helloworld', love.filesystem.read('test2.txt'), 'check read all')
|
||||
test:assertEquals('hello', love.filesystem.read('test3.txt'), 'check read partial')
|
||||
-- cleanup
|
||||
love.filesystem.remove('test1.txt')
|
||||
love.filesystem.remove('test2.txt')
|
||||
love.filesystem.remove('test3.txt')
|
||||
end
|
||||
@@ -0,0 +1,131 @@
|
||||
-- love.font
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
------------------------------------OBJECTS-------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- GlyphData (love.font.newGlyphData)
|
||||
love.test.font.GlyphData = function(test)
|
||||
|
||||
-- create obj
|
||||
local rasterizer = love.font.newRasterizer('resources/font.ttf')
|
||||
local gdata = love.font.newGlyphData(rasterizer, 97) -- 'a'
|
||||
test:assertObject(gdata)
|
||||
|
||||
-- check properties match expected
|
||||
test:assertNotNil(gdata:getString())
|
||||
test:assertEquals(128, gdata:getSize(), 'check data size')
|
||||
test:assertEquals(9, gdata:getAdvance(), 'check advance')
|
||||
test:assertEquals('la8', gdata:getFormat(), 'check format')
|
||||
|
||||
-- @TODO
|
||||
--[[
|
||||
currently these will return 0 and '' respectively as not implemented
|
||||
https://github.com/love2d/love/blob/12.0-development/src/modules/font/freetype/TrueTypeRasterizer.cpp#L140-L141
|
||||
"basically I haven't decided what to do here yet, because of the more
|
||||
advanced text shaping that happens in love 12 having a unicode codepoint
|
||||
associated with a glyph probably doesn't make sense in the first place"
|
||||
]]--
|
||||
--test:assertEquals(97, gdata:getGlyph(), 'check glyph number') - returns 0
|
||||
--test:assertEquals('a', gdata:getGlyphString(), 'check glyph string') - returns ''
|
||||
|
||||
-- check height + width
|
||||
test:assertEquals(8, gdata:getHeight(), 'check height')
|
||||
test:assertEquals(8, gdata:getWidth(), 'check width')
|
||||
|
||||
-- check boundary / dimensions
|
||||
local x, y, w, h = gdata:getBoundingBox()
|
||||
local dw, dh = gdata:getDimensions()
|
||||
test:assertEquals(0, x, 'check bbox x')
|
||||
test:assertEquals(-3, y, 'check bbox y')
|
||||
test:assertEquals(8, w, 'check bbox w')
|
||||
test:assertEquals(14, h, 'check bbox h')
|
||||
test:assertEquals(8, dw, 'check dim width')
|
||||
test:assertEquals(8, dh, 'check dim height')
|
||||
|
||||
-- check bearing
|
||||
local bw, bh = gdata:getBearing()
|
||||
test:assertEquals(0, bw, 'check bearing w')
|
||||
test:assertEquals(11, bh, 'check bearing h')
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- Rasterizer (love.font.newRasterizer)
|
||||
love.test.font.Rasterizer = function(test)
|
||||
|
||||
-- create obj
|
||||
local rasterizer = love.font.newRasterizer('resources/font.ttf')
|
||||
test:assertObject(rasterizer)
|
||||
|
||||
-- check advance
|
||||
test:assertEquals(9, rasterizer:getAdvance(), 'check advance')
|
||||
|
||||
-- check ascent/descent
|
||||
test:assertEquals(9, rasterizer:getAscent(), 'check ascent')
|
||||
test:assertEquals(-3, rasterizer:getDescent(), 'check descent')
|
||||
|
||||
-- check glyphcount
|
||||
test:assertEquals(77, rasterizer:getGlyphCount(), 'check glyph count')
|
||||
|
||||
-- check specific glyphs
|
||||
test:assertObject(rasterizer:getGlyphData('L'))
|
||||
test:assertTrue(rasterizer:hasGlyphs('L', 'O', 'V', 'E'), 'check LOVE')
|
||||
|
||||
-- check height + lineheight
|
||||
test:assertEquals(12, rasterizer:getHeight(), 'check height')
|
||||
test:assertEquals(15, rasterizer:getLineHeight(), 'check line height')
|
||||
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
------------------------------------METHODS-------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- love.font.newBMFontRasterizer
|
||||
love.test.font.newBMFontRasterizer = function(test)
|
||||
local rasterizer = love.font.newBMFontRasterizer('resources/love.png');
|
||||
test:assertObject(rasterizer)
|
||||
end
|
||||
|
||||
|
||||
-- love.font.newGlyphData
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.font.newGlyphData = function(test)
|
||||
local img = love.image.newImageData('resources/love.png')
|
||||
local rasterizer = love.font.newImageRasterizer(img, 'ABC', 0, 1);
|
||||
local glyphdata = love.font.newGlyphData(rasterizer, 65)
|
||||
test:assertObject(glyphdata)
|
||||
end
|
||||
|
||||
|
||||
-- love.font.newImageRasterizer
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.font.newImageRasterizer = function(test)
|
||||
local img = love.image.newImageData('resources/love.png')
|
||||
local rasterizer = love.font.newImageRasterizer(img, 'ABC', 0, 1);
|
||||
test:assertObject(rasterizer)
|
||||
end
|
||||
|
||||
|
||||
-- love.font.newRasterizer
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.font.newRasterizer = function(test)
|
||||
test:assertObject(love.font.newRasterizer('resources/font.ttf'))
|
||||
end
|
||||
|
||||
|
||||
-- love.font.newTrueTypeRasterizer
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.font.newTrueTypeRasterizer = function(test)
|
||||
test:assertObject(love.font.newTrueTypeRasterizer(12, "normal", 1))
|
||||
test:assertObject(love.font.newTrueTypeRasterizer('resources/font.ttf', 8, "normal", 1))
|
||||
end
|
||||
@@ -0,0 +1,119 @@
|
||||
-- love.image
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
------------------------------------OBJECTS-------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- CompressedImageData (love.image.newCompressedImageData)
|
||||
love.test.image.CompressedImageData = function(test)
|
||||
|
||||
-- create obj
|
||||
local idata = love.image.newCompressedData('resources/love.dxt1')
|
||||
test:assertObject(idata)
|
||||
|
||||
-- check string + size
|
||||
test:assertNotEquals(nil, idata:getString(), 'check data string')
|
||||
test:assertEquals(2744, idata:getSize(), 'check data size')
|
||||
|
||||
-- check img dimensions
|
||||
local iw, ih = idata:getDimensions()
|
||||
test:assertEquals(64, iw, 'check image dimension w')
|
||||
test:assertEquals(64, ih, 'check image dimension h')
|
||||
test:assertEquals(64, idata:getWidth(), 'check image direct w')
|
||||
test:assertEquals(64, idata:getHeight(), 'check image direct h')
|
||||
|
||||
-- check format
|
||||
test:assertEquals('DXT1', idata:getFormat(), 'check image format')
|
||||
|
||||
-- check mipmap count
|
||||
test:assertEquals(7, idata:getMipmapCount(), 'check mipmap count')
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- ImageData (love.image.newImageData)
|
||||
love.test.image.ImageData = function(test)
|
||||
|
||||
-- create obj
|
||||
local idata = love.image.newImageData('resources/love.png')
|
||||
test:assertObject(idata)
|
||||
|
||||
-- check string + size
|
||||
test:assertNotEquals(nil, idata:getString(), 'check data string')
|
||||
test:assertEquals(16384, idata:getSize(), 'check data size')
|
||||
|
||||
-- check img dimensions
|
||||
local iw, ih = idata:getDimensions()
|
||||
test:assertEquals(64, iw, 'check image dimension w')
|
||||
test:assertEquals(64, ih, 'check image dimension h')
|
||||
test:assertEquals(64, idata:getWidth(), 'check image direct w')
|
||||
test:assertEquals(64, idata:getHeight(), 'check image direct h')
|
||||
|
||||
-- check format
|
||||
test:assertEquals('rgba8', idata:getFormat(), 'check image format')
|
||||
|
||||
-- manipulate image data so white heart is black
|
||||
local mapdata = function(x, y, r, g, b, a)
|
||||
if r == 1 and g == 1 and b == 1 then
|
||||
r = 0; g = 0; b = 0
|
||||
end
|
||||
return r, g, b, a
|
||||
end
|
||||
idata:mapPixel(mapdata, 0, 0, 64, 64)
|
||||
local r1, g1, b1 = idata:getPixel(25, 25)
|
||||
test:assertEquals(0, r1+g1+b1, 'check mapped black')
|
||||
|
||||
-- map some other data into the idata
|
||||
local idata2 = love.image.newImageData('resources/loveinv.png')
|
||||
idata:paste(idata2, 0, 0, 0, 0)
|
||||
r1, g1, b1 = idata:getPixel(25, 25)
|
||||
test:assertEquals(3, r1+g1+b1, 'check back to white')
|
||||
|
||||
-- set pixels directly
|
||||
idata:setPixel(25, 25, 1, 0, 0, 1)
|
||||
local r2, g2, b2 = idata:getPixel(25, 25)
|
||||
test:assertEquals(1, r2+g2+b2, 'check set to red')
|
||||
|
||||
-- check encoding to an image
|
||||
idata:encode('png', 'test-encode.png')
|
||||
local read = love.filesystem.openFile('test-encode.png', 'r')
|
||||
test:assertNotNil(read)
|
||||
love.filesystem.remove('test-encode.png')
|
||||
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
------------------------------------METHODS-------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- love.image.isCompressed
|
||||
-- @NOTE really we need to test each of the files listed here:
|
||||
-- https://love2d.org/wiki/CompressedImageFormat
|
||||
-- also need to be platform dependent (e.g. dxt not suppored on phones)
|
||||
love.test.image.isCompressed = function(test)
|
||||
test:assertTrue(love.image.isCompressed('resources/love.dxt1'),
|
||||
'check dxt1 valid compressed image')
|
||||
end
|
||||
|
||||
|
||||
-- love.image.newCompressedData
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.image.newCompressedData = function(test)
|
||||
test:assertObject(love.image.newCompressedData('resources/love.dxt1'))
|
||||
end
|
||||
|
||||
|
||||
-- love.image.newImageData
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.image.newImageData = function(test)
|
||||
test:assertObject(love.image.newImageData('resources/love.png'))
|
||||
test:assertObject(love.image.newImageData(16, 16, 'rgba8', nil))
|
||||
end
|
||||
@@ -0,0 +1,375 @@
|
||||
-- love.math
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
------------------------------------OBJECTS-------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- BezierCurve (love.math.newBezierCurve)
|
||||
love.test.math.BezierCurve = function(test)
|
||||
|
||||
-- create obj
|
||||
local curve = love.math.newBezierCurve(1, 1, 2, 2, 3, 1)
|
||||
local px, py = curve:getControlPoint(2)
|
||||
test:assertObject(curve)
|
||||
|
||||
-- check initial properties
|
||||
test:assertCoords({2, 2}, {px, py}, 'check point x/y')
|
||||
test:assertEquals(3, curve:getControlPointCount(), 'check 3 points')
|
||||
test:assertEquals(2, curve:getDegree(), 'check degree is points-1')
|
||||
|
||||
-- check some values on the curve
|
||||
test:assertEquals(1, curve:evaluate(0), 'check curve evaluation 0')
|
||||
test:assertRange(curve:evaluate(0.1), 1.2, 1.3, 'check curve evaluation 0.1')
|
||||
test:assertRange(curve:evaluate(0.2), 1.4, 1.5, 'check curve evaluation 0.2')
|
||||
test:assertRange(curve:evaluate(0.5), 2, 2.1, 'check curve evaluation 0.5')
|
||||
test:assertEquals(3, curve:evaluate(1), 'check curve evaluation 1')
|
||||
|
||||
-- check derivative
|
||||
local deriv = curve:getDerivative()
|
||||
test:assertObject(deriv)
|
||||
test:assertEquals(2, deriv:getControlPointCount(), 'check deriv points')
|
||||
test:assertRange(deriv:evaluate(0.1), 2, 2.1, 'check deriv evaluation 0.1')
|
||||
|
||||
-- check segment
|
||||
local segment = curve:getSegment(0, 0.5)
|
||||
test:assertObject(segment)
|
||||
test:assertEquals(3, segment:getControlPointCount(), 'check segment points')
|
||||
test:assertRange(segment:evaluate(0.1), 1, 1.1, 'check segment evaluation 0.1')
|
||||
|
||||
-- mess with control points
|
||||
curve:removeControlPoint(2)
|
||||
curve:insertControlPoint(4, 1, -1)
|
||||
curve:insertControlPoint(5, 3, -1)
|
||||
curve:insertControlPoint(6, 2, -1)
|
||||
curve:setControlPoint(2, 3, 2)
|
||||
test:assertEquals(5, curve:getControlPointCount(), 'check 3 points still')
|
||||
local px1, py1 = curve:getControlPoint(1)
|
||||
local px2, py2 = curve:getControlPoint(3)
|
||||
local px3, py3 = curve:getControlPoint(5)
|
||||
test:assertCoords({1, 1}, {px1, py1}, 'check modified point 1')
|
||||
test:assertCoords({5, 3}, {px2, py2}, 'check modified point 1')
|
||||
test:assertCoords({3, 1}, {px3, py3}, 'check modified point 1')
|
||||
|
||||
-- check render lists
|
||||
local coords1 = curve:render(5)
|
||||
local coords2 = curve:renderSegment(0, 0.1, 5)
|
||||
test:assertEquals(196, #coords1, 'check coords')
|
||||
test:assertEquals(20, #coords2, 'check segment coords')
|
||||
|
||||
-- check translation values
|
||||
px, py = curve:getControlPoint(2)
|
||||
test:assertCoords({3, 2}, {px, py}, 'check pretransform x/y')
|
||||
curve:rotate(90 * (math.pi/180), 0, 0)
|
||||
px, py = curve:getControlPoint(2)
|
||||
test:assertCoords({-2, 3}, {px, py}, 'check rotated x/y')
|
||||
curve:scale(2, 0, 0)
|
||||
px, py = curve:getControlPoint(2)
|
||||
test:assertCoords({-4, 6}, {px, py}, 'check scaled x/y')
|
||||
curve:translate(5, -5)
|
||||
px, py = curve:getControlPoint(2)
|
||||
test:assertCoords({1, 1}, {px, py}, 'check translated x/y')
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- RandomGenerator (love.math.RandomGenerator)
|
||||
-- @NOTE as this checks random numbers the chances this fails is very unlikely, but not 0...
|
||||
-- if you've managed to proc it congrats! your prize is to rerun the testsuite again
|
||||
love.test.math.RandomGenerator = function(test)
|
||||
|
||||
-- create object
|
||||
local rng1 = love.math.newRandomGenerator(3418323524, 20529293)
|
||||
test:assertObject(rng1)
|
||||
|
||||
-- check set properties
|
||||
local low, high = rng1:getSeed()
|
||||
test:assertEquals(3418323524, low, 'check seed low')
|
||||
test:assertEquals(20529293, high, 'check seed high')
|
||||
|
||||
-- check states
|
||||
local rng2 = love.math.newRandomGenerator(1448323524, 10329293)
|
||||
test:assertNotEquals(rng1:random(), rng2:random(), 'check not matching states')
|
||||
test:assertNotEquals(rng1:randomNormal(), rng2:randomNormal(), 'check not matching states')
|
||||
|
||||
-- check setting state works
|
||||
rng2:setState(rng1:getState())
|
||||
test:assertEquals(rng1:random(), rng2:random(), 'check now matching')
|
||||
|
||||
-- check overwriting seed works, should change output
|
||||
rng1:setSeed(os.time())
|
||||
test:assertNotEquals(rng1:random(), rng2:random(), 'check not matching states')
|
||||
test:assertNotEquals(rng1:randomNormal(), rng2:randomNormal(), 'check not matching states')
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- Transform (love.math.Transform)
|
||||
love.test.math.Transform = function(test)
|
||||
|
||||
-- create obj
|
||||
local transform = love.math.newTransform(0, 0, 0, 1, 1, 0, 0, 0, 0)
|
||||
test:assertObject(transform)
|
||||
|
||||
-- set some values and check the matrix and transformPoint values
|
||||
transform:translate(10, 8)
|
||||
transform:scale(2, 3)
|
||||
transform:rotate(90*(math.pi/180))
|
||||
transform:shear(1, 2)
|
||||
local px, py = transform:transformPoint(1, 1)
|
||||
test:assertCoords({4, 14}, {px, py}, 'check transformation methods')
|
||||
transform:reset()
|
||||
px, py = transform:transformPoint(1, 1)
|
||||
test:assertCoords({1, 1}, {px, py}, 'check reset')
|
||||
|
||||
-- apply a transform to another transform
|
||||
local transform2 = love.math.newTransform()
|
||||
transform2:translate(5, 3)
|
||||
transform:apply(transform2)
|
||||
px, py = transform:transformPoint(1, 1)
|
||||
test:assertCoords({6, 4}, {px, py}, 'check apply other transform')
|
||||
|
||||
-- check cloning a transform
|
||||
local transform3 = transform:clone()
|
||||
px, py = transform3:transformPoint(1, 1)
|
||||
test:assertCoords({6, 4}, {px, py}, 'check clone transform')
|
||||
|
||||
-- check inverse and inverseTransform
|
||||
transform:reset()
|
||||
transform:translate(-14, 6)
|
||||
local ipx, ipy = transform:inverseTransformPoint(0, 0)
|
||||
transform:inverse()
|
||||
px, py = transform:transformPoint(0, 0)
|
||||
test:assertCoords({-px, -py}, {ipx, ipy}, 'check inverse points transform')
|
||||
|
||||
-- check matrix manipulation
|
||||
transform:setTransformation(0, 0, 0, 1, 1, 0, 0, 0, 0)
|
||||
transform:translate(4, 4)
|
||||
local m1, m2, m3, m4, m5, m6, m7, m8,
|
||||
m9, m10, m11, m12, m13, m14, m15, m16 = transform:getMatrix()
|
||||
test:assertEquals(4, m4, 'check translate matrix x')
|
||||
test:assertEquals(4, m8, 'check translate matrix y')
|
||||
transform:setMatrix(m1, m2, m3, 3, m5, m6, m7, 1, m9, m10, m11, m12, m13, m14, m15, m16)
|
||||
px, py = transform:transformPoint(1, 1)
|
||||
test:assertCoords({4, 2}, {px, py}, 'check set matrix')
|
||||
|
||||
-- check affine vs non affine
|
||||
transform:reset()
|
||||
test:assertTrue(transform:isAffine2DTransform(), 'check affine 1')
|
||||
transform:translate(4, 3)
|
||||
test:assertTrue(transform:isAffine2DTransform(), 'check affine 2')
|
||||
transform:setMatrix(1, 3, 4, 5.5, 1, 4.5, 2, 1, 3.4, 5.1, 4.1, 13, 1, 1, 2, 3)
|
||||
test:assertFalse(transform:isAffine2DTransform(), 'check not affine')
|
||||
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
------------------------------------METHODS-------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- love.math.colorFromBytes
|
||||
love.test.math.colorFromBytes = function(test)
|
||||
-- check random value
|
||||
local r1, g1, b1, a1 = love.math.colorFromBytes(51, 51, 51, 51)
|
||||
test:assertEquals(r1, 0.2, 'check r from bytes')
|
||||
test:assertEquals(g1, 0.2, 'check g from bytes')
|
||||
test:assertEquals(b1, 0.2, 'check b from bytes')
|
||||
test:assertEquals(a1, 0.2, 'check a from bytes')
|
||||
-- check "max" value
|
||||
local r2, g2, b2, a2 = love.math.colorFromBytes(255, 255, 255, 255)
|
||||
test:assertEquals(r2, 1, 'check r from bytes')
|
||||
test:assertEquals(g2, 1, 'check g from bytes')
|
||||
test:assertEquals(b2, 1, 'check b from bytes')
|
||||
test:assertEquals(a2, 1, 'check a from bytes')
|
||||
-- check "min" value
|
||||
local r3, g3, b3, a3 = love.math.colorFromBytes(0, 0, 0, 0)
|
||||
test:assertEquals(r3, 0, 'check r from bytes')
|
||||
test:assertEquals(g3, 0, 'check g from bytes')
|
||||
test:assertEquals(b3, 0, 'check b from bytes')
|
||||
test:assertEquals(a3, 0, 'check a from bytes')
|
||||
end
|
||||
|
||||
|
||||
-- love.math.colorToBytes
|
||||
love.test.math.colorToBytes = function(test)
|
||||
-- check random value
|
||||
local r1, g1, b1, a1 = love.math.colorToBytes(0.2, 0.2, 0.2, 0.2)
|
||||
test:assertEquals(r1, 51, 'check bytes from r')
|
||||
test:assertEquals(g1, 51, 'check bytes from g')
|
||||
test:assertEquals(b1, 51, 'check bytes from b')
|
||||
test:assertEquals(a1, 51, 'check bytes from a')
|
||||
-- check "max" value
|
||||
local r2, g2, b2, a2 = love.math.colorToBytes(1, 1, 1, 1)
|
||||
test:assertEquals(r2, 255, 'check bytes from r')
|
||||
test:assertEquals(g2, 255, 'check bytes from g')
|
||||
test:assertEquals(b2, 255, 'check bytes from b')
|
||||
test:assertEquals(a2, 255, 'check bytes from a')
|
||||
-- check "min" value
|
||||
local r3, g3, b3, a3 = love.math.colorToBytes(0, 0, 0, 0)
|
||||
test:assertEquals(r3, 0, 'check bytes from r')
|
||||
test:assertEquals(g3, 0, 'check bytes from g')
|
||||
test:assertEquals(b3, 0, 'check bytes from b')
|
||||
test:assertEquals(a3, 0, 'check bytes from a')
|
||||
end
|
||||
|
||||
|
||||
-- love.math.gammaToLinear
|
||||
-- @NOTE I tried doing the same formula as the source from MathModule.cpp
|
||||
-- but get test failues due to slight differences
|
||||
love.test.math.gammaToLinear = function(test)
|
||||
local lr, lg, lb = love.math.gammaToLinear(1, 0.8, 0.02)
|
||||
--local eg = ((0.8 + 0.055) / 1.055)^2.4
|
||||
--local eb = 0.02 / 12.92
|
||||
test:assertGreaterEqual(0, lr, 'check gamma r to linear')
|
||||
test:assertGreaterEqual(0, lg, 'check gamma g to linear')
|
||||
test:assertGreaterEqual(0, lb, 'check gamma b to linear')
|
||||
end
|
||||
|
||||
|
||||
-- love.math.getRandomSeed
|
||||
-- @NOTE whenever i run this high is always 0, is that intended?
|
||||
love.test.math.getRandomSeed = function(test)
|
||||
local low, high = love.math.getRandomSeed()
|
||||
test:assertGreaterEqual(0, low, 'check random seed low')
|
||||
test:assertGreaterEqual(0, high, 'check random seed high')
|
||||
end
|
||||
|
||||
|
||||
-- love.math.getRandomState
|
||||
love.test.math.getRandomState = function(test)
|
||||
test:assertNotNil(love.math.getRandomState())
|
||||
end
|
||||
|
||||
|
||||
-- love.math.isConvex
|
||||
love.test.math.isConvex = function(test)
|
||||
local isconvex = love.math.isConvex({0, 0, 1, 0, 1, 1, 1, 0, 0, 0}) -- square
|
||||
local notconvex = love.math.isConvex({1, 2, 2, 4, 3, 4, 2, 1, 3, 1}) -- weird shape
|
||||
test:assertTrue(isconvex, 'check polygon convex')
|
||||
test:assertFalse(notconvex, 'check polygon not convex')
|
||||
end
|
||||
|
||||
|
||||
-- love.math.linearToGammer
|
||||
-- @NOTE I tried doing the same formula as the source from MathModule.cpp
|
||||
-- but get test failues due to slight differences
|
||||
love.test.math.linearToGamma = function(test)
|
||||
local gr, gg, gb = love.math.linearToGamma(1, 0.8, 0.001)
|
||||
--local eg = 1.055 * (0.8^1/2.4) - 0.055
|
||||
--local eb = 0.001 * 12.92
|
||||
test:assertGreaterEqual(0, gr, 'check linear r to gamme')
|
||||
test:assertGreaterEqual(0, gg, 'check linear g to gamme')
|
||||
test:assertGreaterEqual(0, gb, 'check linear b to gamme')
|
||||
end
|
||||
|
||||
|
||||
-- love.math.newBezierCurve
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.math.newBezierCurve = function(test)
|
||||
test:assertObject(love.math.newBezierCurve({0, 0, 0, 1, 1, 1, 2, 1}))
|
||||
end
|
||||
|
||||
|
||||
-- love.math.newRandomGenerator
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.math.newRandomGenerator = function(test)
|
||||
test:assertObject(love.math.newRandomGenerator())
|
||||
end
|
||||
|
||||
|
||||
-- love.math.newTransform
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.math.newTransform = function(test)
|
||||
test:assertObject(love.math.newTransform())
|
||||
end
|
||||
|
||||
|
||||
-- love.math.perlinNoise
|
||||
love.test.math.perlinNoise = function(test)
|
||||
-- check some noise values
|
||||
-- output should be consistent if given the same input
|
||||
local noise1 = love.math.perlinNoise(100)
|
||||
local noise2 = love.math.perlinNoise(1, 10)
|
||||
local noise3 = love.math.perlinNoise(1043, 31.123, 999)
|
||||
local noise4 = love.math.perlinNoise(99.222, 10067, 8, 1843)
|
||||
test:assertRange(noise1, 0.5, 0.51, 'check noise 1 dimension')
|
||||
test:assertRange(noise2, 0.5, 0.51, 'check noise 2 dimensions')
|
||||
test:assertRange(noise3, 0.56, 0.57, 'check noise 3 dimensions')
|
||||
test:assertRange(noise4, 0.52, 0.53, 'check noise 4 dimensions')
|
||||
end
|
||||
|
||||
|
||||
-- love.math.simplexNoise
|
||||
love.test.math.simplexNoise = function(test)
|
||||
-- check some noise values
|
||||
-- output should be consistent if given the same input
|
||||
local noise1 = love.math.simplexNoise(100)
|
||||
local noise2 = love.math.simplexNoise(1, 10)
|
||||
local noise3 = love.math.simplexNoise(1043, 31.123, 999)
|
||||
local noise4 = love.math.simplexNoise(99.222, 10067, 8, 1843)
|
||||
-- rounded to avoid floating point issues
|
||||
test:assertRange(noise1, 0.5, 0.51, 'check noise 1 dimension')
|
||||
test:assertRange(noise2, 0.47, 0.48, 'check noise 2 dimensions')
|
||||
test:assertRange(noise3, 0.26, 0.27, 'check noise 3 dimensions')
|
||||
test:assertRange(noise4, 0.53, 0.54, 'check noise 4 dimensions')
|
||||
end
|
||||
|
||||
|
||||
-- love.math.random
|
||||
love.test.math.random = function(test)
|
||||
-- check some random ranges
|
||||
test:assertRange(love.math.random(10), 1, 10, 'check within 1 - 10')
|
||||
test:assertRange(love.math.random(10), 1, 10, 'check within 1 - 10')
|
||||
test:assertRange(love.math.random(10), 1, 10, 'check within 1 - 10')
|
||||
test:assertRange(love.math.random(10), 1, 10, 'check within 1 - 10')
|
||||
test:assertRange(love.math.random(10), 1, 10, 'check within 1 - 10')
|
||||
test:assertRange(love.math.random(5, 100), 5, 100, 'check within 5 - 100')
|
||||
test:assertRange(love.math.random(5, 100), 5, 100, 'check within 5 - 100')
|
||||
test:assertRange(love.math.random(5, 100), 5, 100, 'check within 5 - 100')
|
||||
test:assertRange(love.math.random(5, 100), 5, 100, 'check within 5 - 100')
|
||||
test:assertRange(love.math.random(5, 100), 5, 100, 'check within 5 - 100')
|
||||
end
|
||||
|
||||
|
||||
-- love.math.randomNormal
|
||||
-- @NOTE i dont _really_ get the range expected based on stddev + mean
|
||||
-- so feel free to change to be more accurate
|
||||
love.test.math.randomNormal = function(test)
|
||||
test:assertRange(love.math.randomNormal(1, 0), -3, 3, 'check within -3 - 3')
|
||||
end
|
||||
|
||||
|
||||
-- love.math.setRandomSeed
|
||||
-- @NOTE same with getRandomSeed, high is always 0 when I tested it?
|
||||
love.test.math.setRandomSeed = function(test)
|
||||
love.math.setRandomSeed(9001)
|
||||
local low, high = love.math.getRandomSeed()
|
||||
test:assertEquals(9001, low, 'check seed low set')
|
||||
test:assertEquals(0, high, 'check seed high set')
|
||||
end
|
||||
|
||||
|
||||
-- love.math.setRandomState
|
||||
love.test.math.setRandomState = function(test)
|
||||
-- check setting state matches value returned
|
||||
local rs1 = love.math.getRandomState()
|
||||
love.math.setRandomState(rs1)
|
||||
local rs2 = love.math.getRandomState()
|
||||
test:assertEquals(rs1, rs2, 'check random state set')
|
||||
end
|
||||
|
||||
|
||||
-- love.math.triangulate
|
||||
love.test.math.triangulate = function(test)
|
||||
local triangles1 = love.math.triangulate({0, 0, 1, 0, 1, 1, 1, 0, 0, 0}) -- square
|
||||
local triangles2 = love.math.triangulate({1, 2, 2, 4, 3, 4, 2, 1, 3, 1}) -- weird shape
|
||||
test:assertEquals(3, #triangles1, 'check polygon triangles')
|
||||
test:assertEquals(3, #triangles2, 'check polygon triangles')
|
||||
end
|
||||
@@ -0,0 +1,824 @@
|
||||
-- love.physics
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
----------------------------------OBJECTS---------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- Body (love.physics.newBody)
|
||||
love.test.physics.Body = function(test)
|
||||
|
||||
-- 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 body active
|
||||
test:assertTrue(body1:isActive(), 'check active by def')
|
||||
|
||||
-- check body bullet
|
||||
test:assertFalse(body1:isBullet(), 'check not bullet by def')
|
||||
body1:setBullet(true)
|
||||
test:assertTrue(body1:isBullet(), 'check set bullet')
|
||||
|
||||
-- check fixed rotation
|
||||
test:assertFalse(body1:isFixedRotation(), 'check fix rot def')
|
||||
body1:setFixedRotation(true)
|
||||
test:assertTrue(body1:isFixedRotation(), 'check set fix rot')
|
||||
|
||||
-- check sleeping/waking
|
||||
test:assertTrue(body1:isSleepingAllowed(), 'check sleep def')
|
||||
body1:setSleepingAllowed(false)
|
||||
test:assertFalse(body1:isSleepingAllowed(), 'check set sleep')
|
||||
body1:setSleepingAllowed(true)
|
||||
world:update(1)
|
||||
test:assertFalse(body1:isAwake(), 'check fell asleep')
|
||||
body1:setSleepingAllowed(false)
|
||||
body1:setType('dynamic')
|
||||
test:assertTrue(body1:isAwake(), 'check waking up')
|
||||
|
||||
-- check touching
|
||||
test:assertFalse(body1:isTouching(body2))
|
||||
body2:setPosition(5, 5)
|
||||
world:update(1)
|
||||
test:assertTrue(body1:isTouching(body2))
|
||||
|
||||
-- check children lists
|
||||
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')
|
||||
|
||||
-- check local points
|
||||
local x, y = body1:getLocalCenter()
|
||||
test:assertRange(x, 5, 6, 'check local center x')
|
||||
test:assertRange(y, 5, 6, 'check local center y')
|
||||
local lx, ly = body1:getLocalPoint(10, 10)
|
||||
test:assertRange(lx, 10, 11, 'check local point x')
|
||||
test:assertRange(ly, 9, 10, 'check local point y')
|
||||
local lx1, ly1, lx2, ly2 = body1:getLocalPoints(0, 5, 5, 10)
|
||||
test:assertRange(lx1, 0, 1, 'check local points x 1')
|
||||
test:assertRange(ly1, 3, 4, 'check local points y 1')
|
||||
test:assertRange(lx2, 5, 6, 'check local points x 2')
|
||||
test:assertRange(ly2, 9, 10, 'check local points y 2')
|
||||
|
||||
-- check world points
|
||||
local wx, wy = body1:getWorldPoint(10.4, 9)
|
||||
test:assertRange(wx, 10, 11, 'check world point x')
|
||||
test:assertRange(wy, 10, 11, 'check world point y')
|
||||
local wx1, wy1, wx2, wy2 = body1:getWorldPoints(0.4, 4, 5.4, 9)
|
||||
test:assertRange(wx1, 0, 1, 'check world points x 1')
|
||||
test:assertRange(wy1, 5, 6, 'check world points y 1')
|
||||
test:assertRange(wx2, 5, 6, 'check world points x 2')
|
||||
test:assertRange(wy2, 10, 11, 'check world points y 2')
|
||||
|
||||
-- check angular damping + velocity
|
||||
test:assertEquals(0, body1:getAngularDamping(), 'check angular damping')
|
||||
test:assertEquals(0, body1:getAngularVelocity(), 'check angular velocity')
|
||||
|
||||
-- check world props
|
||||
test:assertObject(body1:getWorld())
|
||||
test:assertEquals(2, body1:getWorld():getBodyCount(), 'check world count')
|
||||
local cx, cy = body1:getWorldCenter()
|
||||
test:assertRange(cx, 4, 5, 'check world center x')
|
||||
test:assertRange(cy, 6, 7, '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')
|
||||
|
||||
-- check inertia
|
||||
test:assertRange(body1:getInertia(), 5, 6, 'check inertia')
|
||||
|
||||
-- check angle
|
||||
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')
|
||||
|
||||
-- check gravity scale
|
||||
test:assertEquals(1, body1:getGravityScale(), 'check def grav')
|
||||
body1:setGravityScale(2)
|
||||
test:assertEquals(2, body1:getGravityScale(), 'check change grav')
|
||||
|
||||
-- check damping
|
||||
test:assertEquals(0, body1:getLinearDamping(), 'check def lin damping')
|
||||
body1:setLinearDamping(0.1)
|
||||
test:assertRange(body1:getLinearDamping(), 0, 0.2, 'check change lin damping')
|
||||
|
||||
-- check velocity
|
||||
local x2, y2 = body1:getLinearVelocity()
|
||||
test:assertEquals(1, x2, 'check def lin velocity x')
|
||||
test:assertEquals(1, y2, 'check def lin velocity y')
|
||||
body1:setLinearVelocity(4, 5)
|
||||
local x3, y3 = body1:getLinearVelocity()
|
||||
test:assertEquals(4, x3, 'check change lin velocity x')
|
||||
test:assertEquals(5, y3, 'check change lin velocity y')
|
||||
|
||||
-- check mass
|
||||
test:assertRange(body1:getMass(), 0.1, 0.2, 'check def mass')
|
||||
body1:setMass(10)
|
||||
test:assertEquals(10, body1:getMass(), 'check change mass')
|
||||
body1:setMassData(3, 5, 10, 1)
|
||||
local x4, y4, mass4, inertia4 = body1:getMassData()
|
||||
test:assertEquals(3, x4, 'check mass data change x')
|
||||
test:assertEquals(5, y4, 'check mass data change y')
|
||||
test:assertEquals(10, mass4, 'check mass data change mass')
|
||||
test:assertRange(inertia4, 340, 341, 'check mass data change inertia')
|
||||
body1:resetMassData()
|
||||
local x5, y5, mass5, inertia5 = body1:getMassData()
|
||||
test:assertRange(x5, 5, 6, 'check mass data reset x')
|
||||
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')
|
||||
|
||||
-- check position
|
||||
local x6, y6 = body1:getPosition()
|
||||
test:assertRange(x6, -1, 0, 'check position x')
|
||||
test:assertRange(y6, 0, 1, 'check position y')
|
||||
body1:setPosition(10, 4)
|
||||
local x7, y7 = body1:getPosition()
|
||||
test:assertEquals(x7, 10, 'check set position x')
|
||||
test:assertEquals(y7, 4, 'check set position y')
|
||||
|
||||
-- check type
|
||||
test:assertEquals('dynamic', body1:getType(), 'check type match')
|
||||
body1:setType('kinematic')
|
||||
body1:setType('static')
|
||||
test:assertEquals('static', body1:getType(), 'check type change')
|
||||
|
||||
-- check userdata
|
||||
test:assertEquals(nil, body1:getUserData(), 'check user data')
|
||||
body1:setUserData({ love = 'cool' })
|
||||
test:assertEquals('cool', body1:getUserData().love, 'check set user data')
|
||||
|
||||
-- check x/y direct
|
||||
test:assertEquals(10, math.floor(body1:getX()), 'check get x')
|
||||
test:assertEquals(4, math.floor(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 angular impulse
|
||||
local vel = body2:getAngularVelocity()
|
||||
test:assertRange(vel, 0, 0, 'check velocity before')
|
||||
body2:applyAngularImpulse(10)
|
||||
local vel1 = body2:getAngularVelocity()
|
||||
test:assertRange(vel1, 5, 6, 'check velocity after 1')
|
||||
|
||||
-- apply standard force
|
||||
local ang1 = body2:getAngle()
|
||||
test:assertRange(ang1, 0.1, 0.2, 'check initial angle 1')
|
||||
body2:applyForce(2, 3)
|
||||
world:update(2)
|
||||
local vel2 = body2:getAngularVelocity()
|
||||
local ang2 = body2:getAngle()
|
||||
test:assertRange(ang2, -0.1, 0, 'check angle after 2')
|
||||
test:assertRange(vel2, 1, 2, 'check velocity after 2')
|
||||
|
||||
-- apply linear impulse
|
||||
body2:applyLinearImpulse(-4, -59)
|
||||
world:update(1)
|
||||
local ang3 = body2:getAngle()
|
||||
local vel3 = body2:getAngularVelocity()
|
||||
test:assertRange(ang3, -2, -1, 'check angle after 3')
|
||||
test:assertRange(vel3, 0, 1, 'check velocity after 3')
|
||||
|
||||
-- apply torque
|
||||
body2:applyTorque(4)
|
||||
world:update(2)
|
||||
local ang4 = body2:getAngle()
|
||||
local vel4 = body2:getAngularVelocity()
|
||||
test:assertRange(ang4, -1, 0, 'check angle after 4')
|
||||
test:assertRange(vel4, 0, 1, 'check velocity after 4')
|
||||
|
||||
-- check destroy
|
||||
test:assertFalse(body1:isDestroyed(), 'check not destroyed')
|
||||
body1:destroy()
|
||||
test:assertTrue(body1:isDestroyed(), 'check destroyed')
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- Contact (love.physics.World:getContacts)
|
||||
love.test.physics.Contact = function(test)
|
||||
|
||||
-- create a setup so we can access some contact objects
|
||||
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')
|
||||
|
||||
-- used to check for collisions + no. of collisions
|
||||
local collided = false
|
||||
local pass = 1
|
||||
|
||||
-- set callback for contact start
|
||||
world:setCallbacks(
|
||||
function(shape_a, shape_b, contact)
|
||||
collided = true
|
||||
|
||||
-- check contact object
|
||||
test:assertObject(contact)
|
||||
|
||||
-- check child indices
|
||||
local indexA, indexB = contact:getChildren()
|
||||
test:assertEquals(1, indexA, 'check child indice a')
|
||||
test:assertEquals(1, indexB, 'check child indice b')
|
||||
|
||||
-- check shapes match using userdata
|
||||
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')
|
||||
|
||||
-- check normal pos
|
||||
local nx, ny = contact:getNormal()
|
||||
test:assertEquals(1, nx, 'check normal x')
|
||||
test:assertEquals(0, ny, 'check normal y')
|
||||
|
||||
-- check actual pos
|
||||
local px1, py1, px2, py2 = contact:getPositions()
|
||||
test:assertRange(px1, 5, 6, 'check collide x 1')
|
||||
test:assertRange(py1, 5, 6, 'check collide y 1')
|
||||
test:assertRange(px2, 5, 6, 'check collide x 2')
|
||||
test:assertRange(py2, 5, 6, 'check collide y 2')
|
||||
|
||||
-- check touching
|
||||
test:assertTrue(contact:isTouching(), 'check touching')
|
||||
|
||||
-- check enabled (we pass through twice to test on/off)
|
||||
test:assertEquals(pass == 1, contact:isEnabled(), 'check enabled for pass ' .. tostring(pass))
|
||||
|
||||
-- check friction
|
||||
test:assertRange(contact:getFriction(), 0.2, 0.3, 'check def friction')
|
||||
contact:setFriction(0.1)
|
||||
test:assertRange(contact:getFriction(), 0.1, 0.2, 'check set friction')
|
||||
contact:resetFriction()
|
||||
test:assertRange(contact:getFriction(), 0.2, 0.3, 'check reset friction')
|
||||
|
||||
-- check restitution
|
||||
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
|
||||
)
|
||||
|
||||
-- check bodies collided
|
||||
world:update(1)
|
||||
test:assertTrue(collided, 'check bodies collided')
|
||||
|
||||
-- update again for enabled check
|
||||
world:update(1)
|
||||
test:assertEquals(2, pass, 'check ran twice')
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- Joint (love.physics.newDistanceJoint)
|
||||
love.test.physics.Joint = function(test)
|
||||
|
||||
-- make joint
|
||||
local world = love.physics.newWorld(1, 1, true)
|
||||
local body1 = love.physics.newBody(world, 10, 10, 'dynamic')
|
||||
local body2 = love.physics.newBody(world, 20, 20, 'dynamic')
|
||||
local joint = love.physics.newDistanceJoint(body1, body2, 10, 10, 20, 20, true)
|
||||
test:assertObject(joint)
|
||||
|
||||
-- check type
|
||||
test:assertEquals('distance', joint:getType(), 'check joint type')
|
||||
|
||||
-- check not destroyed
|
||||
test:assertFalse(joint:isDestroyed(), 'check not destroyed')
|
||||
|
||||
-- check reaction props (sometimes nil on linux runners)
|
||||
if joint:getReactionForce(1) ~= nil then
|
||||
test:assertEquals(0, joint:getReactionForce(1), 'check reaction force')
|
||||
end
|
||||
if joint:getReactionTorque(1) ~= nil then
|
||||
test:assertEquals(0, joint:getReactionTorque(1), 'check reaction torque')
|
||||
end
|
||||
|
||||
-- check body pointer
|
||||
local b1, b2 = joint:getBodies()
|
||||
test:assertEquals(body1:getX(), b1:getX(), 'check body 1')
|
||||
test:assertEquals(body2:getX(), b2:getX(), 'check body 2')
|
||||
|
||||
-- check joint anchors
|
||||
local x1, y1, x2, y2 = joint:getAnchors()
|
||||
test:assertRange(x1, 10, 11, 'check anchor x1')
|
||||
test:assertRange(y1, 10, 11, 'check anchor y1')
|
||||
test:assertRange(x2, 20, 21, 'check anchor x2')
|
||||
test:assertRange(y2, 20, 21, 'check anchor y2')
|
||||
test:assertTrue(joint:getCollideConnected(), 'check not colliding')
|
||||
|
||||
-- test userdata
|
||||
test:assertEquals(nil, joint:getUserData(), 'check no data by def')
|
||||
joint:setUserData('hello')
|
||||
test:assertEquals('hello', joint:getUserData(), 'check set userdata')
|
||||
|
||||
-- destroy
|
||||
joint:destroy()
|
||||
test:assertTrue(joint:isDestroyed(), 'check destroyed')
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- Shape (love.physics.newCircleShape)
|
||||
-- @NOTE in 12.0 fixtures have been merged into shapes
|
||||
love.test.physics.Shape = function(test)
|
||||
|
||||
-- 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 child count
|
||||
test:assertEquals(1, shape1:getChildCount(), 'check child count')
|
||||
|
||||
-- check radius
|
||||
test:assertRange(shape1:getRadius(), 0, 0.4, 'check radius')
|
||||
|
||||
-- check type match
|
||||
test:assertEquals('polygon', shape1:getType(), 'check rectangle type')
|
||||
|
||||
-- check body pointer
|
||||
test:assertEquals(0, shape1:getBody():getX(), 'check body link')
|
||||
|
||||
-- check category
|
||||
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')
|
||||
|
||||
-- check sensor prop
|
||||
test:assertFalse(shape1:isSensor(), 'check sensor def')
|
||||
shape1:setSensor(true)
|
||||
test:assertTrue(shape1:isSensor(), 'check set sensor')
|
||||
shape1:setSensor(false)
|
||||
|
||||
-- check not destroyed
|
||||
test:assertFalse(shape1:isDestroyed(), 'check not destroyed')
|
||||
|
||||
-- check user data
|
||||
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:assertRange(topLeftY, -0.3, -0.2, 'check bbox tl 2')
|
||||
test:assertEquals(bottomRightX, bottomRightY, 'check bbox br 1')
|
||||
test:assertRange(bottomRightX, 10.3, 10.4, 'check bbox br 2')
|
||||
|
||||
-- check density
|
||||
test:assertEquals(1, shape1:getDensity(), 'check def density')
|
||||
shape1:setDensity(5)
|
||||
test:assertEquals(5, shape1:getDensity(), 'check set density')
|
||||
|
||||
-- check mass
|
||||
local x1, y1, mass1, inertia1 = shape1:getMassData()
|
||||
test:assertRange(x1, 5, 5.1, 'check shape mass pos x')
|
||||
test:assertRange(y1, 5, 5.1, 'check shape mass pos y')
|
||||
test:assertRange(mass1, 0.5, 0.6, 'check mass at 1 density')
|
||||
test:assertRange(inertia1, 0, 0.1, 'check intertia at 1 density')
|
||||
local x2, y2, mass2, inertia2 = shape1:computeMass(1000)
|
||||
test:assertRange(mass2, 111, 112, 'check mass at 1000 density')
|
||||
test:assertRange(inertia2, 7407, 7408, 'check intertia at 1000 density')
|
||||
|
||||
-- check friction
|
||||
test:assertRange(shape1:getFriction(), 0.2, 0.3, 'check def friction')
|
||||
shape1:setFriction(1)
|
||||
test:assertEquals(1, shape1:getFriction(), 'check set friction')
|
||||
|
||||
-- check restitution
|
||||
test:assertEquals(0, shape1:getRestitution(), 'check def restitution')
|
||||
shape1:setRestitution(0.5)
|
||||
test:assertRange(shape1:getRestitution(), 0.5, 0.6, 'check set restitution')
|
||||
|
||||
-- check points
|
||||
local bodyp = love.physics.newBody(world, 0, 0, 'dynamic')
|
||||
local shape2 = love.physics.newRectangleShape(bodyp, 5, 5, 10, 10)
|
||||
test:assertTrue(shape2:testPoint(5, 5), 'check point 5,5')
|
||||
test:assertTrue(shape2:testPoint(10, 10, 0, 15, 15), 'check point 15,15 after translate 10,10')
|
||||
test:assertFalse(shape2:testPoint(5, 5, 90, 10, 10), 'check point 10,10 after translate 5,5,90')
|
||||
test:assertFalse(shape2:testPoint(10, 10, 90, 5, 5), 'check point 5,5 after translate 10,10,90')
|
||||
test:assertFalse(shape2:testPoint(15, 15), 'check point 15,15')
|
||||
|
||||
-- check ray cast
|
||||
local xn1, yn1, fraction1 = shape2:rayCast(-20, -20, 20, 20, 100, 0, 0, 0, 1)
|
||||
test:assertNotEquals(nil, xn1, 'check ray 1 x')
|
||||
test:assertNotEquals(nil, xn1, 'check ray 1 y')
|
||||
local xn2, yn2, fraction2 = shape2:rayCast(10, 10, -150, -150, 100, 0, 0, 0, 1)
|
||||
test:assertEquals(nil, xn2, 'check ray 2 x')
|
||||
test:assertEquals(nil, yn2, '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')
|
||||
|
||||
-- check destroyed
|
||||
shape1:destroy()
|
||||
test:assertTrue(shape1:isDestroyed(), 'check destroyed')
|
||||
shape2:destroy()
|
||||
|
||||
-- run some collision checks using filters, setup new shapes
|
||||
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 positive group do collide
|
||||
shape3:setGroupIndex(1)
|
||||
shape4:setGroupIndex(1)
|
||||
world:update(1)
|
||||
test:assertEquals(1, collisions, 'check positive group collide')
|
||||
|
||||
-- check negative group dont 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')
|
||||
|
||||
-- check masks do collide
|
||||
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')
|
||||
|
||||
-- check masks not colliding
|
||||
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
|
||||
|
||||
|
||||
-- World (love.physics.newWorld)
|
||||
love.test.physics.World = function(test)
|
||||
|
||||
-- create new world
|
||||
local world = love.physics.newWorld(0, 0, false)
|
||||
local body1 = love.physics.newBody(world, 0, 0, 'dynamic')
|
||||
local rectangle1 = love.physics.newRectangleShape(body1, 0, 0, 10, 10)
|
||||
test:assertObject(world)
|
||||
|
||||
-- check bodies in world
|
||||
test:assertEquals(1, #world:getBodies(), 'check 1 body')
|
||||
test:assertEquals(0, world:getBodies()[1]:getX(), 'check body prop x')
|
||||
test:assertEquals(0, world:getBodies()[1]:getY(), 'check body prop y')
|
||||
world:translateOrigin(-10, -10) -- check affects bodies
|
||||
test:assertRange(world:getBodies()[1]:getX(), 9, 11, 'check body prop change x')
|
||||
test:assertRange(world:getBodies()[1]:getY(), 9, 11, 'check body prop change y')
|
||||
test:assertEquals(1, world:getBodyCount(), 'check 1 body count')
|
||||
|
||||
-- check world status
|
||||
test:assertFalse(world:isLocked(), 'check not updating')
|
||||
test:assertFalse(world:isSleepingAllowed(), 'check no sleep (till brooklyn)')
|
||||
world:setSleepingAllowed(true)
|
||||
test:assertTrue(world:isSleepingAllowed(), 'check can sleep')
|
||||
|
||||
-- check world objects
|
||||
test:assertEquals(0, #world:getJoints(), 'check no joints')
|
||||
test:assertEquals(0, world:getJointCount(), 'check no joints count')
|
||||
test:assertEquals(0, world:getGravity(), 'check def gravity')
|
||||
test:assertEquals(0, #world:getContacts(), 'check no contacts')
|
||||
test:assertEquals(0, world:getContactCount(), 'check no contact count')
|
||||
|
||||
-- check callbacks are called
|
||||
local beginContact, endContact, preSolve, postSolve = world:getCallbacks()
|
||||
test:assertEquals(nil, beginContact, 'check no begin contact callback')
|
||||
test:assertEquals(nil, endContact, 'check no end contact callback')
|
||||
test:assertEquals(nil, preSolve, 'check no pre solve callback')
|
||||
test:assertEquals(nil, postSolve, 'check no post solve callback')
|
||||
local beginContactCheck = false
|
||||
local endContactCheck = false
|
||||
local preSolveCheck = false
|
||||
local postSolveCheck = false
|
||||
local collisions = 0
|
||||
world:setCallbacks(
|
||||
function() beginContactCheck = true; collisions = collisions + 1 end,
|
||||
function() endContactCheck = true end,
|
||||
function() preSolveCheck = true end,
|
||||
function() postSolveCheck = true end
|
||||
)
|
||||
|
||||
-- setup so we can collide stuff to call the callbacks
|
||||
local body2 = love.physics.newBody(world, 10, 10, 'dynamic')
|
||||
local rectangle2 = love.physics.newRectangleShape(body2, 0, 0, 10, 10)
|
||||
test:assertFalse(beginContactCheck, 'check world didnt update after adding body')
|
||||
world:update(1)
|
||||
test:assertTrue(beginContactCheck, 'check contact start')
|
||||
test:assertTrue(preSolveCheck, 'check pre solve')
|
||||
test:assertTrue(postSolveCheck, 'check post solve')
|
||||
body2:setPosition(100, 100)
|
||||
world:update(1)
|
||||
test:assertTrue(endContactCheck, 'check contact end')
|
||||
|
||||
-- check point checking
|
||||
local shapes = 0
|
||||
world:queryShapesInArea(0, 0, 10, 10, function(x)
|
||||
shapes = shapes + 1
|
||||
end)
|
||||
test:assertEquals(1, shapes, 'check shapes in area')
|
||||
|
||||
-- check raycast
|
||||
world:rayCast(0, 0, 200, 200, function(x)
|
||||
shapes = shapes + 1
|
||||
return 1
|
||||
end)
|
||||
test:assertEquals(3, shapes, 'check shapes in raycast')
|
||||
|
||||
-- change collision logic
|
||||
test:assertEquals(nil, world:getContactFilter(), 'check def filter')
|
||||
world:update(1)
|
||||
world:setContactFilter(function(s1, s2)
|
||||
return false -- nothing collides
|
||||
end)
|
||||
body2:setPosition(10, 10)
|
||||
world:update(1)
|
||||
test:assertEquals(1, collisions, 'check collision logic change')
|
||||
|
||||
-- check gravity
|
||||
world:setGravity(1, 1)
|
||||
test:assertEquals(1, world:getGravity(), 'check grav change')
|
||||
|
||||
-- check destruction
|
||||
test:assertFalse(world:isDestroyed(), 'check not destroyed')
|
||||
world:destroy()
|
||||
test:assertTrue(world:isDestroyed(), 'check world destroyed')
|
||||
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
------------------------------------METHODS-------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- love.physics.getDistance
|
||||
love.test.physics.getDistance = function(test)
|
||||
-- setup two fixtues to check
|
||||
local world = love.physics.newWorld(0, 0, false)
|
||||
local body = love.physics.newBody(world, 10, 10, 'static')
|
||||
local shape1 = love.physics.newEdgeShape(body, 0, 0, 5, 5)
|
||||
local shape2 = love.physics.newEdgeShape(body, 10, 10, 15, 15)
|
||||
-- check distance between them
|
||||
test:assertRange(love.physics.getDistance(shape1, shape2), 6, 7, 'check distance matches')
|
||||
end
|
||||
|
||||
|
||||
-- love.physics.getMeter
|
||||
love.test.physics.getMeter = function(test)
|
||||
-- check value set is returned
|
||||
love.physics.setMeter(30)
|
||||
test:assertEquals(30, love.physics.getMeter(), 'check meter matches')
|
||||
end
|
||||
|
||||
|
||||
-- love.physics.newBody
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.physics.newBody = function(test)
|
||||
local world = love.physics.newWorld(1, 1, true)
|
||||
local body = love.physics.newBody(world, 10, 10, 'static')
|
||||
test:assertObject(body)
|
||||
end
|
||||
|
||||
|
||||
-- love.physics.newChainShape
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.physics.newChainShape = function(test)
|
||||
local world = love.physics.newWorld(1, 1, true)
|
||||
local body = love.physics.newBody(world, 10, 10, 'static')
|
||||
test:assertObject(love.physics.newChainShape(body, true, 0, 0, 1, 0, 1, 1, 0, 1))
|
||||
end
|
||||
|
||||
|
||||
-- love.physics.newCircleShape
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.physics.newCircleShape = function(test)
|
||||
local world = love.physics.newWorld(1, 1, true)
|
||||
local body = love.physics.newBody(world, 10, 10, 'static')
|
||||
test:assertObject(love.physics.newCircleShape(body, 10))
|
||||
end
|
||||
|
||||
|
||||
-- love.physics.newDistanceJoint
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.physics.newDistanceJoint = function(test)
|
||||
local world = love.physics.newWorld(1, 1, true)
|
||||
local body1 = love.physics.newBody(world, 10, 10, 'static')
|
||||
local body2 = love.physics.newBody(world, 20, 20, 'static')
|
||||
local obj = love.physics.newDistanceJoint(body1, body2, 10, 10, 20, 20, true)
|
||||
test:assertObject(obj)
|
||||
end
|
||||
|
||||
|
||||
-- love.physics.newEdgeShape
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.physics.newEdgeShape = function(test)
|
||||
local world = love.physics.newWorld(1, 1, true)
|
||||
local body = love.physics.newBody(world, 10, 10, 'static')
|
||||
local obj = love.physics.newEdgeShape(body, 0, 0, 10, 10)
|
||||
test:assertObject(obj)
|
||||
end
|
||||
|
||||
|
||||
-- love.physics.newFrictionJoint
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.physics.newFrictionJoint = function(test)
|
||||
local world = love.physics.newWorld(1, 1, true)
|
||||
local body1 = love.physics.newBody(world, 10, 10, 'static')
|
||||
local body2 = love.physics.newBody(world, 20, 20, 'static')
|
||||
local obj = love.physics.newFrictionJoint(body1, body2, 15, 15, true)
|
||||
test:assertObject(obj)
|
||||
end
|
||||
|
||||
|
||||
-- love.physics.newGearJoint
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.physics.newGearJoint = function(test)
|
||||
local world = love.physics.newWorld(1, 1, true)
|
||||
local body1 = love.physics.newBody(world, 10, 10, 'dynamic')
|
||||
local body2 = love.physics.newBody(world, 20, 20, 'dynamic')
|
||||
local body3 = love.physics.newBody(world, 30, 30, 'dynamic')
|
||||
local body4 = love.physics.newBody(world, 40, 40, 'dynamic')
|
||||
local joint1 = love.physics.newPrismaticJoint(body1, body2, 10, 10, 20, 20, true)
|
||||
local joint2 = love.physics.newPrismaticJoint(body3, body4, 30, 30, 40, 40, true)
|
||||
local obj = love.physics.newGearJoint(joint1, joint2, 1, true)
|
||||
test:assertObject(obj)
|
||||
end
|
||||
|
||||
|
||||
-- love.physics.newMotorJoint
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.physics.newMotorJoint = function(test)
|
||||
local world = love.physics.newWorld(1, 1, true)
|
||||
local body1 = love.physics.newBody(world, 10, 10, 'static')
|
||||
local body2 = love.physics.newBody(world, 20, 20, 'static')
|
||||
local obj = love.physics.newMotorJoint(body1, body2, 1)
|
||||
test:assertObject(obj)
|
||||
end
|
||||
|
||||
|
||||
-- love.physics.newMouseJoint
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.physics.newMouseJoint = function(test)
|
||||
local world = love.physics.newWorld(1, 1, true)
|
||||
local body = love.physics.newBody(world, 10, 10, 'static')
|
||||
local obj = love.physics.newMouseJoint(body, 10, 10)
|
||||
test:assertObject(obj)
|
||||
end
|
||||
|
||||
|
||||
-- love.physics.newPolygonShape
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.physics.newPolygonShape = function(test)
|
||||
local world = love.physics.newWorld(1, 1, true)
|
||||
local body = love.physics.newBody(world, 10, 10, 'static')
|
||||
local obj = love.physics.newPolygonShape(body, {0, 0, 2, 3, 2, 1, 3, 1, 5, 1})
|
||||
test:assertObject(obj)
|
||||
end
|
||||
|
||||
|
||||
-- love.physics.newPrismaticJoint
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.physics.newPrismaticJoint = function(test)
|
||||
local world = love.physics.newWorld(1, 1, true)
|
||||
local body1 = love.physics.newBody(world, 10, 10, 'static')
|
||||
local body2 = love.physics.newBody(world, 20, 20, 'static')
|
||||
local obj = love.physics.newPrismaticJoint(body1, body2, 10, 10, 20, 20, true)
|
||||
test:assertObject(obj)
|
||||
end
|
||||
|
||||
|
||||
-- love.physics.newPulleyJoint
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.physics.newPulleyJoint = function(test)
|
||||
local world = love.physics.newWorld(1, 1, true)
|
||||
local body1 = love.physics.newBody(world, 10, 10, 'static')
|
||||
local body2 = love.physics.newBody(world, 20, 20, 'static')
|
||||
local obj = love.physics.newPulleyJoint(body1, body2, 10, 10, 20, 20, 15, 15, 25, 25, 1, true)
|
||||
test:assertObject(obj)
|
||||
end
|
||||
|
||||
|
||||
-- love.physics.newRectangleShape
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.physics.newRectangleShape = function(test)
|
||||
local world = love.physics.newWorld(1, 1, true)
|
||||
local body = love.physics.newBody(world, 10, 10, 'static')
|
||||
local shape1 = love.physics.newRectangleShape(body, 10, 20)
|
||||
local shape2 = love.physics.newRectangleShape(body, 10, 10, 40, 30, 10)
|
||||
test:assertObject(shape1)
|
||||
test:assertObject(shape2)
|
||||
end
|
||||
|
||||
|
||||
-- love.physics.newRevoluteJoint
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.physics.newRevoluteJoint = function(test)
|
||||
local world = love.physics.newWorld(1, 1, true)
|
||||
local body1 = love.physics.newBody(world, 10, 10, 'static')
|
||||
local body2 = love.physics.newBody(world, 20, 20, 'static')
|
||||
local obj = love.physics.newRevoluteJoint(body1, body2, 10, 10, true)
|
||||
test:assertObject(obj)
|
||||
end
|
||||
|
||||
|
||||
-- love.physics.newRopeJoint
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.physics.newRopeJoint = function(test)
|
||||
local world = love.physics.newWorld(1, 1, true)
|
||||
local body1 = love.physics.newBody(world, 10, 10, 'static')
|
||||
local body2 = love.physics.newBody(world, 20, 20, 'static')
|
||||
local obj = love.physics.newRopeJoint(body1, body2, 10, 10, 20, 20, 50, true)
|
||||
test:assertObject(obj)
|
||||
end
|
||||
|
||||
|
||||
-- love.physics.newWeldJoint
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.physics.newWeldJoint = function(test)
|
||||
local world = love.physics.newWorld(1, 1, true)
|
||||
local body1 = love.physics.newBody(world, 10, 10, 'static')
|
||||
local body2 = love.physics.newBody(world, 20, 20, 'static')
|
||||
local obj = love.physics.newWeldJoint(body1, body2, 10, 10, true)
|
||||
test:assertObject(obj)
|
||||
end
|
||||
|
||||
|
||||
-- love.physics.newWheelJoint
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.physics.newWheelJoint = function(test)
|
||||
local world = love.physics.newWorld(1, 1, true)
|
||||
local body1 = love.physics.newBody(world, 10, 10, 'static')
|
||||
local body2 = love.physics.newBody(world, 20, 20, 'static')
|
||||
local obj = love.physics.newWheelJoint(body1, body2, 10, 10, 5, 5, true)
|
||||
test:assertObject(obj)
|
||||
end
|
||||
|
||||
|
||||
-- love.physics.newWorld
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.physics.newWorld = function(test)
|
||||
local world = love.physics.newWorld(1, 1, true)
|
||||
test:assertObject(world)
|
||||
end
|
||||
|
||||
|
||||
-- love.physics.setMeter
|
||||
love.test.physics.setMeter = function(test)
|
||||
-- set initial meter
|
||||
local world = love.physics.newWorld(1, 1, true)
|
||||
love.physics.setMeter(30)
|
||||
local body = love.physics.newBody(world, 300, 300, "dynamic")
|
||||
-- check changing meter changes pos value relatively
|
||||
love.physics.setMeter(10)
|
||||
local x, y = body:getPosition()
|
||||
test:assertEquals(100, x, 'check pos x')
|
||||
test:assertEquals(100, y, 'check pos y')
|
||||
end
|
||||
@@ -0,0 +1,106 @@
|
||||
-- love.sound
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
------------------------------------OBJECTS-------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- Decoder (love.sound.newDecoder)
|
||||
love.test.sound.Decoder = function(test)
|
||||
|
||||
-- create obj
|
||||
local decoder = love.sound.newDecoder('resources/click.ogg')
|
||||
test:assertObject(decoder)
|
||||
|
||||
-- check bit depth
|
||||
test:assertMatch({8, 16}, decoder:getBitDepth(), 'check bit depth')
|
||||
|
||||
-- check channel count
|
||||
test:assertMatch({1, 2}, decoder:getChannelCount(), 'check channel count')
|
||||
|
||||
-- check duration
|
||||
test:assertRange(decoder:getDuration(), 0.06, 0.07, 'check duration')
|
||||
|
||||
-- check sample rate
|
||||
test:assertEquals(44100, decoder:getSampleRate(), 'check sample rate')
|
||||
|
||||
-- check makes sound data (test in method below)
|
||||
test:assertObject(decoder:decode())
|
||||
|
||||
-- check cloning sound
|
||||
local clone = decoder:clone()
|
||||
test:assertMatch({8, 16}, clone:getBitDepth(), 'check cloned bit depth')
|
||||
test:assertMatch({1, 2}, clone:getChannelCount(), 'check cloned channel count')
|
||||
test:assertRange(clone:getDuration(), 0.06, 0.07, 'check cloned duration')
|
||||
test:assertEquals(44100, clone:getSampleRate(), 'check cloned sample rate')
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- SoundData (love.sound.newSoundData)
|
||||
love.test.sound.SoundData = function(test)
|
||||
|
||||
-- create obj
|
||||
local sdata = love.sound.newSoundData('resources/click.ogg')
|
||||
test:assertObject(sdata)
|
||||
|
||||
-- check data size + string
|
||||
test:assertEquals(11708, sdata:getSize(), 'check size')
|
||||
test:assertNotNil(sdata:getString())
|
||||
|
||||
-- check bit depth
|
||||
test:assertMatch({8, 16}, sdata:getBitDepth(), 'check bit depth')
|
||||
|
||||
-- check channel count
|
||||
test:assertMatch({1, 2}, sdata:getChannelCount(), 'check channel count')
|
||||
|
||||
-- check duration
|
||||
test:assertRange(sdata:getDuration(), 0.06, 0.07, 'check duration')
|
||||
|
||||
-- check samples
|
||||
test:assertEquals(44100, sdata:getSampleRate(), 'check sample rate')
|
||||
test:assertEquals(2927, sdata:getSampleCount(), 'check sample count')
|
||||
|
||||
-- check cloning
|
||||
local clone = sdata:clone()
|
||||
test:assertEquals(11708, clone:getSize(), 'check clone size')
|
||||
test:assertNotNil(clone:getString())
|
||||
test:assertMatch({8, 16}, clone:getBitDepth(), 'check clone bit depth')
|
||||
test:assertMatch({1, 2}, clone:getChannelCount(), 'check clone channel count')
|
||||
test:assertRange(clone:getDuration(), 0.06, 0.07, 'check clone duration')
|
||||
test:assertEquals(44100, clone:getSampleRate(), 'check clone sample rate')
|
||||
test:assertEquals(2927, clone:getSampleCount(), 'check clone sample count')
|
||||
|
||||
-- check sample setting
|
||||
test:assertRange(sdata:getSample(0.001), -0.1, 0, 'check sample 1')
|
||||
test:assertRange(sdata:getSample(0.005), -0.1, 0, 'check sample 1')
|
||||
sdata:setSample(0.002, 1)
|
||||
test:assertEquals(1, sdata:getSample(0.002), 'check setting sample manually')
|
||||
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
------------------------------------METHODS-------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
-- love.sound.newDecoder
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.sound.newDecoder = function(test)
|
||||
test:assertObject(love.sound.newDecoder('resources/click.ogg'))
|
||||
end
|
||||
|
||||
|
||||
-- love.sound.newSoundData
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.sound.newSoundData = function(test)
|
||||
test:assertObject(love.sound.newSoundData('resources/click.ogg'))
|
||||
test:assertObject(love.sound.newSoundData(math.floor((1/32)*44100), 44100, 16, 1))
|
||||
end
|
||||
@@ -0,0 +1,83 @@
|
||||
-- love.system
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
----------------------------------METHODS---------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- love.system.getClipboardText
|
||||
love.test.system.getClipboardText = function(test)
|
||||
-- ignore if not using window
|
||||
if love.test.windowmode == false then
|
||||
return test:skipTest('clipboard only available in window mode')
|
||||
end
|
||||
-- check clipboard value is set
|
||||
love.system.setClipboardText('helloworld')
|
||||
test:assertEquals('helloworld', love.system.getClipboardText(), 'check clipboard match')
|
||||
end
|
||||
|
||||
|
||||
-- love.system.getOS
|
||||
love.test.system.getOS = function(test)
|
||||
-- check os is in documented values
|
||||
local os = love.system.getOS()
|
||||
local options = {'OS X', 'Windows', 'Linux', 'Android', 'iOS'}
|
||||
test:assertMatch(options, os, 'check value matches')
|
||||
end
|
||||
|
||||
|
||||
-- love.system.getPowerInfo
|
||||
love.test.system.getPowerInfo = function(test)
|
||||
-- check battery state is one of the documented states
|
||||
local state, percent, seconds = love.system.getPowerInfo()
|
||||
local states = {'unknown', 'battery', 'nobattery', 'charging', 'charged'}
|
||||
test:assertMatch(states, state, 'check value matches')
|
||||
-- if percent/seconds check within expected range
|
||||
if percent ~= nil then
|
||||
test:assertRange(percent, 0, 100, 'check battery percent within range')
|
||||
end
|
||||
if seconds ~= nil then
|
||||
test:assertNotNil(seconds)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- love.system.getProcessorCount
|
||||
love.test.system.getProcessorCount = function(test)
|
||||
test:assertNotNil(love.system.getProcessorCount()) -- youd hope right
|
||||
end
|
||||
|
||||
|
||||
-- love.system.hasBackgroundMusic
|
||||
love.test.system.hasBackgroundMusic = function(test)
|
||||
test:assertNotNil(love.system.hasBackgroundMusic())
|
||||
end
|
||||
|
||||
|
||||
-- love.system.openURL
|
||||
love.test.system.openURL = function(test)
|
||||
test:skipTest('cant test this worked')
|
||||
--test:assertNotEquals(nil, love.system.openURL('https://love2d.org'), 'check open URL')
|
||||
end
|
||||
|
||||
|
||||
-- love.system.getClipboardText
|
||||
love.test.system.setClipboardText = function(test)
|
||||
-- ignore if not using window
|
||||
if love.test.windowmode == false then
|
||||
return test:skipTest('clipboard only available in window mode')
|
||||
end
|
||||
-- check value returned is what was set
|
||||
love.system.setClipboardText('helloworld')
|
||||
test:assertEquals('helloworld', love.system.getClipboardText(), 'check set text')
|
||||
end
|
||||
|
||||
|
||||
-- love.system.vibrate
|
||||
-- @NOTE cant really test this
|
||||
love.test.system.vibrate = function(test)
|
||||
test:skipTest('cant test this worked')
|
||||
end
|
||||
@@ -0,0 +1,137 @@
|
||||
-- love.thread
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
----------------------------------OBJECTS---------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- Channel (love.thread.newChannel)
|
||||
love.test.thread.Channel = function(test)
|
||||
|
||||
-- create channel
|
||||
local channel = love.thread.getChannel('test')
|
||||
test:assertObject(channel)
|
||||
|
||||
-- setup thread to use
|
||||
local threadcode1 = [[
|
||||
require("love.timer")
|
||||
love.timer.sleep(0.1)
|
||||
love.thread.getChannel('test'):push('hello world')
|
||||
love.timer.sleep(0.1)
|
||||
love.thread.getChannel('test'):push('me again')
|
||||
]]
|
||||
local thread1 = love.thread.newThread(threadcode1)
|
||||
thread1:start()
|
||||
|
||||
-- check message sent from thread to channel
|
||||
local msg1 = channel:demand()
|
||||
test:assertEquals('hello world', msg1, 'check 1st message was sent')
|
||||
thread1:wait()
|
||||
test:assertEquals(1, channel:getCount(), 'check still another message')
|
||||
test:assertEquals('me again', channel:peek(), 'check 2nd message pending')
|
||||
local msg2 = channel:pop()
|
||||
test:assertEquals('me again', msg2, 'check 2nd message was sent')
|
||||
channel:clear()
|
||||
|
||||
-- setup another thread for some ping pong
|
||||
local threadcode2 = [[
|
||||
local function setChannel(channel, value)
|
||||
channel:clear()
|
||||
return channel:push(value)
|
||||
end
|
||||
local channel = love.thread.getChannel('test')
|
||||
local waiting = true
|
||||
local sent = nil
|
||||
while waiting == true do
|
||||
if sent == nil then
|
||||
sent = channel:performAtomic(setChannel, 'ping')
|
||||
end
|
||||
if channel:hasRead(sent) then
|
||||
local msg = channel:demand()
|
||||
if msg == 'pong' then
|
||||
channel:push(msg)
|
||||
waiting = false
|
||||
end
|
||||
end
|
||||
end
|
||||
]]
|
||||
|
||||
-- first we run a thread that will send 1 ping
|
||||
local thread2 = love.thread.newThread(threadcode2)
|
||||
thread2:start()
|
||||
|
||||
-- we wait for that ping to be sent and then send a pong back
|
||||
local msg3 = channel:demand()
|
||||
test:assertEquals('ping', msg3, 'check message recieved 1')
|
||||
|
||||
-- thread should be waiting for us, and checking is the ping was read
|
||||
channel:supply('pong', 1)
|
||||
|
||||
-- if it was then it should send back our pong and thread should die
|
||||
thread2:wait()
|
||||
local msg4 = channel:pop()
|
||||
test:assertEquals('pong', msg4, 'check message recieved 2')
|
||||
test:assertEquals(0, channel:getCount())
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- Thread (love.thread.newThread)
|
||||
love.test.thread.Thread = function(test)
|
||||
|
||||
-- create thread
|
||||
local threadcode = [[
|
||||
local b = 0
|
||||
for a=1,100000 do
|
||||
b = b + a
|
||||
end
|
||||
]]
|
||||
local thread = love.thread.newThread(threadcode)
|
||||
test:assertObject(thread)
|
||||
|
||||
-- check thread runs
|
||||
thread:start()
|
||||
test:assertTrue(thread:isRunning(), 'check started')
|
||||
thread:wait()
|
||||
test:assertFalse(thread:isRunning(), 'check finished')
|
||||
test:assertEquals(nil, thread:getError(), 'check no errors')
|
||||
|
||||
-- check an invalid thread
|
||||
local badthreadcode = 'local b = 0\nreturn b + "string" .. 10'
|
||||
local badthread = love.thread.newThread(badthreadcode)
|
||||
badthread:start()
|
||||
badthread:wait()
|
||||
test:assertNotNil(badthread:getError())
|
||||
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
----------------------------------METHODS---------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- love.thread.getChannel
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.thread.getChannel = function(test)
|
||||
test:assertObject(love.thread.getChannel('test'))
|
||||
end
|
||||
|
||||
|
||||
-- love.thread.newChannel
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.thread.newChannel = function(test)
|
||||
test:assertObject(love.thread.newChannel())
|
||||
end
|
||||
|
||||
|
||||
-- love.thread.newThread
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.thread.newThread = function(test)
|
||||
test:assertObject(love.thread.newThread('classes/TestSuite.lua'))
|
||||
end
|
||||
@@ -0,0 +1,52 @@
|
||||
-- love.timer
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
----------------------------------METHODS---------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- love.timer.getAverageDelta
|
||||
-- @NOTE not sure if you could reliably get a specific delta?
|
||||
love.test.timer.getAverageDelta = function(test)
|
||||
test:assertNotNil(love.timer.getAverageDelta())
|
||||
end
|
||||
|
||||
-- love.timer.getDelta
|
||||
-- @NOTE not sure if you could reliably get a specific delta?
|
||||
love.test.timer.getDelta = function(test)
|
||||
test:assertNotNil(love.timer.getDelta())
|
||||
end
|
||||
|
||||
|
||||
-- love.timer.getFPS
|
||||
-- @NOTE not sure if you could reliably get a specific FPS?
|
||||
love.test.timer.getFPS = function(test)
|
||||
test:assertNotNil(love.timer.getFPS())
|
||||
end
|
||||
|
||||
|
||||
-- love.timer.getTime
|
||||
love.test.timer.getTime = function(test)
|
||||
local starttime = love.timer.getTime()
|
||||
love.timer.sleep(1)
|
||||
local endtime = love.timer.getTime() - starttime
|
||||
test:assertRange(endtime, 1, 2, 'check 1s passes')
|
||||
end
|
||||
|
||||
|
||||
-- love.timer.sleep
|
||||
love.test.timer.sleep = function(test)
|
||||
local starttime = love.timer.getTime()
|
||||
love.timer.sleep(1)
|
||||
test:assertRange(love.timer.getTime() - starttime, 1, 2, 'check 1s passes')
|
||||
end
|
||||
|
||||
|
||||
-- love.timer.step
|
||||
-- @NOTE not sure if you could reliably get a specific step val?
|
||||
love.test.timer.step = function(test)
|
||||
test:assertNotNil(love.timer.step())
|
||||
end
|
||||
@@ -0,0 +1,46 @@
|
||||
-- love.video
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
----------------------------------OBJECTS---------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- VideoStream (love.thread.newVideoStream)
|
||||
love.test.video.VideoStream = function(test)
|
||||
|
||||
-- create obj
|
||||
local video = love.video.newVideoStream('resources/sample.ogv')
|
||||
test:assertObject(video)
|
||||
|
||||
-- check def properties
|
||||
test:assertEquals('resources/sample.ogv', video:getFilename(), 'check filename')
|
||||
test:assertFalse(video:isPlaying(), 'check not playing by def')
|
||||
|
||||
-- check playing and pausing states
|
||||
video:play()
|
||||
test:assertTrue(video:isPlaying(), 'check now playing')
|
||||
video:seek(0.3)
|
||||
test:assertRange(video:tell(), 0.3, 0.4, 'check seek/tell')
|
||||
video:rewind()
|
||||
test:assertEquals(0, video:tell(), 'check rewind')
|
||||
video:pause()
|
||||
test:assertFalse(video:isPlaying(), 'check paused')
|
||||
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
----------------------------------METHODS---------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- love.video.newVideoStream
|
||||
-- @NOTE this is just basic nil checking, objs have their own test method
|
||||
love.test.video.newVideoStream = function(test)
|
||||
test:assertObject(love.video.newVideoStream('resources/sample.ogv'))
|
||||
end
|
||||
@@ -0,0 +1,371 @@
|
||||
-- love.window
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
----------------------------------METHODS---------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- love.window.close
|
||||
love.test.window.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')
|
||||
love.window.updateMode(360, 240) -- reset
|
||||
active = love.graphics.isActive()
|
||||
test:assertTrue(active, 'check window active again')
|
||||
end
|
||||
|
||||
-- love.window.fromPixels
|
||||
love.test.window.fromPixels = function(test)
|
||||
-- check dpi/pixel ratio as expected
|
||||
local dpi = love.window.getDPIScale()
|
||||
local pixels = love.window.fromPixels(100)
|
||||
test:assertEquals(100/dpi, pixels, 'check dpi ratio')
|
||||
end
|
||||
|
||||
|
||||
-- love.window.getDPIScale
|
||||
-- @NOTE dependent on hardware so best can do is not nil
|
||||
love.test.window.getDPIScale = function(test)
|
||||
test:assertNotNil(test)
|
||||
end
|
||||
|
||||
|
||||
-- love.window.getDesktopDimensions
|
||||
-- @NOTE dependent on hardware so best can do is not nil
|
||||
love.test.window.getDesktopDimensions = function(test)
|
||||
local w, h = love.window.getDesktopDimensions()
|
||||
test:assertNotNil(w)
|
||||
test:assertNotNil(h)
|
||||
end
|
||||
|
||||
|
||||
-- love.window.getDisplayCount
|
||||
-- @NOTE cant wait for the test suite to be run headless and fail here
|
||||
love.test.window.getDisplayCount = function(test)
|
||||
test:assertGreaterEqual(1, love.window.getDisplayCount(), 'check 1 display')
|
||||
end
|
||||
|
||||
|
||||
-- love.window.getDisplayName
|
||||
-- @NOTE dependent on hardware so best can do is not nil
|
||||
love.test.window.getDisplayName = function(test)
|
||||
test:assertNotNil(love.window.getDisplayName(1))
|
||||
end
|
||||
|
||||
|
||||
-- love.window.getDisplayOrientation
|
||||
-- @NOTE dependent on hardware so best can do is not nil
|
||||
love.test.window.getDisplayOrientation = function(test)
|
||||
test:assertNotNil(love.window.getDisplayOrientation(1))
|
||||
end
|
||||
|
||||
|
||||
-- love.window.getFullscreen
|
||||
love.test.window.getFullscreen = function(test)
|
||||
-- check not fullscreen to start
|
||||
test:assertFalse(love.window.getFullscreen(), 'check not fullscreen')
|
||||
love.window.setFullscreen(true)
|
||||
-- check now fullscreen
|
||||
test:assertTrue(love.window.getFullscreen(), 'check now fullscreen')
|
||||
love.window.setFullscreen(false) -- reset
|
||||
end
|
||||
|
||||
|
||||
-- love.window.getFullscreenModes
|
||||
-- @NOTE dependent on hardware so best can do is not nil
|
||||
love.test.window.getFullscreenModes = function(test)
|
||||
test:assertNotNil(love.window.getFullscreenModes(1))
|
||||
end
|
||||
|
||||
|
||||
-- love.window.getIcon
|
||||
love.test.window.getIcon = function(test)
|
||||
-- check icon nil by default if not set
|
||||
test:assertEquals(nil, love.window.getIcon(), 'check nil by default')
|
||||
local icon = love.image.newImageData('resources/love.png')
|
||||
-- check getting icon not nil after setting
|
||||
love.window.setIcon(icon)
|
||||
test:assertNotNil(love.window.getIcon())
|
||||
end
|
||||
|
||||
|
||||
-- love.window.getMode
|
||||
-- @NOTE could prob add more checks on the flags here based on conf.lua
|
||||
love.test.window.getMode = function(test)
|
||||
local w, h, flags = love.window.getMode()
|
||||
test:assertEquals(360, w, 'check w')
|
||||
test:assertEquals(240, h, 'check h')
|
||||
test:assertFalse(flags["fullscreen"], 'check fullscreen')
|
||||
end
|
||||
|
||||
|
||||
-- love.window.getPosition
|
||||
-- @NOTE anything we could check display index agaisn't in getPosition return?
|
||||
love.test.window.getPosition = function(test)
|
||||
love.window.setPosition(100, 100, 1)
|
||||
local x, y, _ = love.window.getPosition()
|
||||
test:assertEquals(100, x, 'check position x')
|
||||
test:assertEquals(100, y, 'check position y')
|
||||
end
|
||||
|
||||
|
||||
-- love.window.getSafeArea
|
||||
-- @NOTE dependent on hardware so best can do is not nil
|
||||
love.test.window.getSafeArea = function(test)
|
||||
local x, y, w, h = love.window.getSafeArea()
|
||||
test:assertNotNil(x)
|
||||
test:assertNotNil(y)
|
||||
test:assertNotNil(w)
|
||||
test:assertNotNil(h)
|
||||
end
|
||||
|
||||
|
||||
-- love.window.getTitle
|
||||
love.test.window.getTitle = function(test)
|
||||
-- check title returned is what was set
|
||||
love.window.setTitle('love.testing')
|
||||
test:assertEquals('love.testing', love.window.getTitle(), 'check title match')
|
||||
love.window.setTitle('love.test')
|
||||
end
|
||||
|
||||
|
||||
-- love.window.getVSync
|
||||
love.test.window.getVSync = function(test)
|
||||
test:assertNotNil(love.window.getVSync())
|
||||
end
|
||||
|
||||
|
||||
-- love.window.hasFocus
|
||||
-- @NOTE cant really test as cant force focus
|
||||
love.test.window.hasFocus = function(test)
|
||||
test:assertNotNil(love.window.hasFocus())
|
||||
end
|
||||
|
||||
|
||||
-- love.window.hasMouseFocus
|
||||
-- @NOTE cant really test as cant force focus
|
||||
love.test.window.hasMouseFocus = function(test)
|
||||
test:assertNotNil(love.window.hasMouseFocus())
|
||||
end
|
||||
|
||||
|
||||
-- love.window.isDisplaySleepEnabled
|
||||
love.test.window.isDisplaySleepEnabled = function(test)
|
||||
test:assertNotNil(love.window.isDisplaySleepEnabled())
|
||||
-- check disabled
|
||||
love.window.setDisplaySleepEnabled(false)
|
||||
test:assertFalse(love.window.isDisplaySleepEnabled(), 'check sleep disabled')
|
||||
-- check enabled
|
||||
love.window.setDisplaySleepEnabled(true)
|
||||
test:assertTrue(love.window.isDisplaySleepEnabled(), 'check sleep enabled')
|
||||
end
|
||||
|
||||
|
||||
-- love.window.isMaximized
|
||||
love.test.window.isMaximized = function(test)
|
||||
test:assertFalse(love.window.isMaximized(), 'check window not maximized')
|
||||
love.window.maximize()
|
||||
test:waitFrames(10)
|
||||
-- on MACOS maximize wont get recognised immedietely so wait a few frames
|
||||
test:assertTrue(love.window.isMaximized(), 'check window now maximized')
|
||||
love.window.restore()
|
||||
end
|
||||
|
||||
|
||||
-- love.window.isMinimized
|
||||
love.test.window.isMinimized = function(test)
|
||||
-- check not minimized to start
|
||||
test:assertFalse(love.window.isMinimized(), 'check window not minimized')
|
||||
-- try to minimize
|
||||
love.window.minimize()
|
||||
test:waitFrames(10)
|
||||
-- on linux minimize won't get recognized immediately, so wait a few frames
|
||||
test:assertTrue(love.window.isMinimized(), 'check window minimized')
|
||||
love.window.restore()
|
||||
end
|
||||
|
||||
|
||||
-- love.window.isOpen
|
||||
love.test.window.isOpen = function(test)
|
||||
-- check open initially
|
||||
test:assertTrue(love.window.isOpen(), 'check window open')
|
||||
-- try closing
|
||||
love.window.close()
|
||||
test:assertFalse(love.window.isOpen(), 'check window closed')
|
||||
love.window.updateMode(360, 240) -- reset
|
||||
end
|
||||
|
||||
|
||||
-- love.window.isVisible
|
||||
love.test.window.isVisible = function(test)
|
||||
-- check visible initially
|
||||
test:assertTrue(love.window.isVisible(), 'check window visible')
|
||||
-- check closing makes window not visible
|
||||
love.window.close()
|
||||
test:assertFalse(love.window.isVisible(), 'check window not visible')
|
||||
love.window.updateMode(360, 240) -- reset
|
||||
end
|
||||
|
||||
|
||||
-- love.window.maximize
|
||||
love.test.window.maximize = function(test)
|
||||
test:assertFalse(love.window.isMaximized(), 'check window not maximized')
|
||||
-- check maximizing is set
|
||||
love.window.maximize()
|
||||
test:waitFrames(10)
|
||||
-- on macos we need to wait a few frames
|
||||
test:assertTrue(love.window.isMaximized(), 'check window maximized')
|
||||
love.window.restore()
|
||||
end
|
||||
|
||||
|
||||
-- love.window.minimize
|
||||
love.test.window.minimize = function(test)
|
||||
test:assertFalse(love.window.isMinimized(), 'check window not minimized')
|
||||
-- check minimizing is set
|
||||
love.window.minimize()
|
||||
test:waitFrames(10)
|
||||
-- on linux we need to wait a few frames
|
||||
test:assertTrue(love.window.isMinimized(), 'check window maximized')
|
||||
love.window.restore()
|
||||
end
|
||||
|
||||
|
||||
-- love.window.requestAttention
|
||||
love.test.window.requestAttention = function(test)
|
||||
test:skipTest('cant test this worked')
|
||||
end
|
||||
|
||||
|
||||
-- love.window.restore
|
||||
love.test.window.restore = function(test)
|
||||
-- check minimized to start
|
||||
love.window.minimize()
|
||||
test:waitFrames(10)
|
||||
love.window.restore()
|
||||
test:waitFrames(10)
|
||||
-- check restoring the state of the window
|
||||
test:assertFalse(love.window.isMinimized(), 'check window restored')
|
||||
end
|
||||
|
||||
|
||||
-- love.window.setDisplaySleepEnabled
|
||||
love.test.window.setDisplaySleepEnabled = function(test)
|
||||
-- check disabling sleep
|
||||
love.window.setDisplaySleepEnabled(false)
|
||||
test:assertFalse(love.window.isDisplaySleepEnabled(), 'check sleep disabled')
|
||||
-- check setting it back to enabled
|
||||
love.window.setDisplaySleepEnabled(true)
|
||||
test:assertTrue(love.window.isDisplaySleepEnabled(), 'check sleep enabled')
|
||||
end
|
||||
|
||||
|
||||
-- love.window.setFullscreen
|
||||
love.test.window.setFullscreen = function(test)
|
||||
-- check fullscreen is set
|
||||
love.window.setFullscreen(true)
|
||||
test:assertTrue(love.window.getFullscreen(), 'check fullscreen')
|
||||
-- check setting back to normal
|
||||
love.window.setFullscreen(false)
|
||||
test:assertFalse(love.window.getFullscreen(), 'check not fullscreen')
|
||||
end
|
||||
|
||||
|
||||
-- love.window.setIcon
|
||||
-- @NOTE could check the image data itself?
|
||||
love.test.window.setIcon = function(test)
|
||||
-- check setting an icon returns the val
|
||||
local icon = love.image.newImageData('resources/love.png')
|
||||
love.window.setIcon(icon)
|
||||
test:assertNotEquals(nil, love.window.getIcon(), 'check icon not nil')
|
||||
end
|
||||
|
||||
|
||||
-- love.window.setMode
|
||||
-- @NOTE same as getMode could be checking more flag properties
|
||||
love.test.window.setMode = function(test)
|
||||
-- set window mode
|
||||
love.window.setMode(512, 512, {
|
||||
fullscreen = false,
|
||||
resizable = false
|
||||
})
|
||||
-- check what we set is returned
|
||||
local width, height, flags = love.window.getMode()
|
||||
test:assertEquals(512, width, 'check window w match')
|
||||
test:assertEquals(512, height, 'check window h match')
|
||||
test:assertFalse(flags["fullscreen"], 'check window not fullscreen')
|
||||
test:assertFalse(flags["resizable"], 'check window not resizeable')
|
||||
love.window.setMode(360, 240, {
|
||||
fullscreen = false,
|
||||
resizable = true
|
||||
})
|
||||
end
|
||||
|
||||
-- love.window.setPosition
|
||||
love.test.window.setPosition = function(test)
|
||||
-- check position is returned
|
||||
love.window.setPosition(100, 100, 1)
|
||||
test:waitFrames(10)
|
||||
local x, y, _ = love.window.getPosition()
|
||||
test:assertEquals(100, x, 'check position x')
|
||||
test:assertEquals(100, y, 'check position y')
|
||||
end
|
||||
|
||||
|
||||
-- love.window.setTitle
|
||||
love.test.window.setTitle = function(test)
|
||||
-- check setting title val is returned
|
||||
love.window.setTitle('love.testing')
|
||||
test:assertEquals('love.testing', love.window.getTitle(), 'check title matches')
|
||||
love.window.setTitle('love.test')
|
||||
end
|
||||
|
||||
|
||||
-- love.window.setVSync
|
||||
love.test.window.setVSync = function(test)
|
||||
love.window.setVSync(0)
|
||||
test:assertNotNil(love.window.getVSync())
|
||||
end
|
||||
|
||||
|
||||
-- love.window.showMessageBox
|
||||
-- @NOTE if running headless would need to skip anyway cos can't press it
|
||||
love.test.window.showMessageBox = function(test)
|
||||
test:skipTest('cant test this worked')
|
||||
end
|
||||
|
||||
|
||||
-- love.window.toPixels
|
||||
love.test.window.toPixels = function(test)
|
||||
-- check dpi/pixel ratio is as expected
|
||||
local dpi = love.window.getDPIScale()
|
||||
local pixels = love.window.toPixels(50)
|
||||
test:assertEquals(50*dpi, pixels, 'check dpi ratio')
|
||||
end
|
||||
|
||||
|
||||
-- love.window.updateMode
|
||||
love.test.window.updateMode = function(test)
|
||||
-- set initial mode
|
||||
love.window.setMode(512, 512, {
|
||||
fullscreen = false,
|
||||
resizable = false
|
||||
})
|
||||
-- update mode with some props but not others
|
||||
love.window.updateMode(360, 240, nil)
|
||||
-- check only changed values changed
|
||||
local width, height, flags = love.window.getMode()
|
||||
test:assertEquals(360, width, 'check window w match')
|
||||
test:assertEquals(240, height, 'check window h match')
|
||||
test:assertFalse(flags["fullscreen"], 'check window not fullscreen')
|
||||
test:assertFalse(flags["resizable"], 'check window not resizeable')
|
||||
love.window.setMode(360, 240, { -- reset
|
||||
fullscreen = false,
|
||||
resizable = true
|
||||
})
|
||||
end
|
||||