Delete the test suite.

This commit is contained in:
EliteMasterEric
2025-12-26 14:48:14 -05:00
committed by Cameron Taylor
parent 1d2a47aea0
commit e248562592
58 changed files with 0 additions and 7021 deletions
-7
View File
@@ -1,7 +0,0 @@
bin/
# auto-generated
source/TestSuite.hx
.temp/
report/
build/
-7
View File
@@ -1,7 +0,0 @@
version=2.3.5
src=source
bin=bin
report=report
hxml=test.hxml
classPaths=../../source
coveragePackages=funkin
-13
View File
@@ -1,13 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Lime",
"type": "lime",
"request": "launch"
}
]
}
-56
View File
@@ -1,56 +0,0 @@
Flixel Unit Tests
-----------------
This is a unit test project using [munit](https://github.com/massiveinteractive/MassiveUnit). It's good practice to add tests for fixed bugs or new features.
TODO Make sure the unit tests are automatically run on GitHub Actions.
There's a 1:1 mapping between `.hx` files in `source/` and the unit test project - tests for `funkin.Conductor` go into `funkin.ConductorTest` etc.
### Building
Run one of the `test-*.hxml` files in this directory to run the tests on that specific target, e.g. `haxe test-cpp.hxml`. Currently supported are:
- `web` (HTML5)
- `cpp` (Native)
Alternatively, this can be done from within Visual Studio Code - (`F1` -> `Tasks: Run Task` -> Choose the target to test).
#### Adding Tests
- Run `haxelib run munit create com.FooBarTest -for com.Foo`
- Use `@:allow(full.package.name.ClassName)` to allow a test class to call private functions.
- Use `mockatoo.Mockatoo.mock(ClassName)` to mock a class. See [Mockatoo docs](https://github.com/misprintt/mockatoo).
#### Functions
- `@Before` functions are named `before()`
- Each `@Test` function starts with `test` and describes what exactly it tests. This can lead to long function names like `FlxEmitter#testStartShouldNotReviveMembers()` and serves as self-documentation.
- Another thing that helps with self-documentation is adding a comment for tests that are related an issue on GitHub.
```haxe
@Test // #1203
function testColorWithAlphaComparison()
```
### `FunkinTest` base class
Test classes extend `FunkinTest`, which is a base class with some utility functions for testing.
### `step()`
`step()` advances the `FlxGame` exactly one step. This is useful for tests that depend on game time advancing / `FlxGame#step()` being executed, such as physics of `add()`ed objects, state switches, or just time passing for tweens or timers.
There are two parameters:
- `steps` - specifies the amount of steps to advance (defaults to 1)
- `callback` - an optional callback function that is executed after each step
### `testDestroy()`
`testDestroy()` tests whether an `IFlxDestroyable` can safely be `destroy()`ed more than once (null reference errors are fairly common here). For this, `destroyable` has to be set during `before()` of the test class.
### Null Safety
Append each test class with `@:nullSafety` to prevent crash bugs while developing.
Note that `Assert.isNotNull(target)` is considered a vlid
@@ -1,47 +0,0 @@
{
"version": "1.0.0",
"name": "SHOULD FAIL TO PARSE",
"titleAsset": "",
"props": [
{
"assetPath": "storymenu/props/gf",
"scale": 1.0,
"danceEvery": 2,
"offsets": [80, 80],
"animations": [
{
"name": "danceLeft",
"prefix": "idle0",
"frameIndices": [30, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
},
{
"name": "danceRight",
"prefix": "idle0",
"frameIndices": [
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29
]
}
]
},
{
"assetPath": "storymenu/props/bf",
"scale": 1.0,
"danceEvery": 2,
"offsets": [150, 80],
"animations": [
{
"name": "idle",
"prefix": "idle0",
"frameRate": 24
},
{
"name": "confirm",
"prefix": "confirm0",
"frameRate": 24
}
]
}
],
"background": "#F9CF51",
"songs": ["tutorial"]
}
@@ -1,47 +0,0 @@
{
"version": "1.0.0",
"name": "TEACHING TIME",
"titleAsset": "storymenu/titles/tutorial",
"props": [
{
"assetPath": "storymenu/props/gf",
"scale": 1.0,
"danceEvery": 2,
"offsets": [80, 80],
"animations": [
{
"name": "danceLeft",
"prefix": "idle0",
"frameIndices": [30, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
},
{
"name": "danceRight",
"prefix": "idle0",
"frameIndices": [
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29
]
}
]
},
{
"assetPath": "storymenu/props/bf",
"scale": 1.0,
"danceEvery": 2,
"offsets": [150, 80],
"animations": [
{
"name": "idle",
"prefix": "idle0",
"frameRate": 24
},
{
"name": "confirm",
"prefix": "confirm0",
"frameRate": 24
}
]
}
],
"background": "#F9CF51",
"songs": ["tutorial"]
}
@@ -1,6 +0,0 @@
{
"version": "1.0.0",
"id": "blablabla",
"name": "blablabla API",
"data": []
}
@@ -1,15 +0,0 @@
{
"version": "1.0.0",
"id": "fizzbuzz",
"name": "nodejs-express-mongoose-demo",
"data": [
{
"foo": "bar",
"bar": "foo"
},
{
"foo": "baz",
"bar": "baz"
}
]
}
@@ -1,5 +0,0 @@
{
"version": "0.1.0",
"id": 1,
"name": "My First App"
}
@@ -1,4 +0,0 @@
{
"version": "3.0.0",
"info": "stuff"
}
@@ -1,59 +0,0 @@
{
"version": "1.0.0",
"name": "Funkin'",
"author": "PhantomArcade",
"fallback": null,
"assets": {
"note": {
"assetPath": "shared:arrows",
"scale": 1.0,
"isPixel": false,
"data": {
"left": { "prefix": "noteLeft" },
"down": { "prefix": "noteDown" },
"up": { "prefix": "noteUp" },
"right": { "prefix": "noteRight" }
}
},
"noteStrumline": {
"assetPath": "shared:arrows",
"scale": 1.0,
"offsets": [28, 32],
"isPixel": false,
"data": {
"leftStatic": { "prefix": "staticLeft0" },
"leftPress": { "prefix": "pressedLeft0" },
"leftConfirm": { "prefix": "confirmLeft0" },
"leftConfirmHold": { "prefix": "confirmLeft0" },
"downStatic": { "prefix": "staticDown0" },
"downPress": { "prefix": "pressedDown0" },
"downConfirm": { "prefix": "confirmDown0" },
"downConfirmHold": { "prefix": "confirmDown0" },
"upStatic": { "prefix": "staticUp0" },
"upPress": { "prefix": "pressedUp0" },
"upConfirm": { "prefix": "confirmUp0" },
"upConfirmHold": { "prefix": "confirmUp0" },
"rightStatic": { "prefix": "staticRight0" },
"rightPress": { "prefix": "pressedRight0" },
"rightConfirm": { "prefix": "confirmRight0" },
"rightConfirmHold": { "prefix": "confirmRight0" }
}
},
"holdNote": {
"assetPath": "NOTE_hold_assets",
"data": {}
},
"noteSplash": {
"assetPath": "",
"data": {
"enabled": true
}
},
"holdNoteCover": {
"assetPath": "",
"data": {
"enabled": true
}
}
}
}
@@ -1,18 +0,0 @@
{
"version": "1.0.0",
"name": "Test2",
"author": "Eric",
"fallback": "funkin",
"assets": {
"note": {
"assetPath": "shared:coolstuff",
"scale": 1.8,
"data": {
"left": { "prefix": "noteLeft1" },
"down": { "prefix": "noteDown3" },
"up": { "prefix": "noteUp2" },
"right": { "prefix": "noteRight4" }
}
}
}
}
@@ -1,15 +0,0 @@
{
"version": "2.0.0",
"songName": "Bopeebo",
"artist": "Kawai Sprite",
"timeFormat": "ms",
"timeChanges": [{ "t": 0, "bpm": 100, "n": 4, "d": 4, "bt": [4, 4, 4, 4] }],
"playData": {
"songVariations": [],
"difficulties": ["easy", "normal", "hard"],
"playableChars": { "bf": { "g": "gf", "o": "dad" } },
"stage": "mainStage",
"noteSkin": "Normal"
},
"generatedBy": "MasterEric (by hand)"
}
File diff suppressed because it is too large Load Diff
@@ -1,15 +0,0 @@
{
"version": "2.0.0",
"songName": "Bopeebo",
"artist": "Kawai Sprite",
"timeFormat": "ms",
"timeChanges": [{ "t": 0, "bpm": 100, "n": 4, "d": 4, "bt": [4, 4, 4, 4] }],
"playData": {
"songVariations": [],
"difficulties": ["easy", "normal", "hard"],
"playableChars": { "bf": { "g": "gf", "o": "dad" } },
"stage": "mainStage",
"noteSkin": "Normal"
},
"generatedBy": "MasterEric (by hand)"
}
-103
View File
@@ -1,103 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<project
xmlns="http://lime.software/project/1.0.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://lime.software/project/1.0.2 http://lime.software/xsd/project-1.0.2.xsd">
<meta title="FunkinUnitTests" version="1.0.0" />
<app file="TestMain" main="TestMain" />
<!-- Test sources -->
<source path="source" />
<!-- Funkin' sources -->
<source path="../../source" />
<!-- Funkin' dependencies -->
<haxelib name="lime" /> <!-- Game engine -->
<haxelib name="openfl" /> <!-- Game engine -->
<haxelib name="flixel" /> <!-- Game engine -->
<haxelib name="flixel-addons" /> <!-- Additional utilities for Flixel -->
<haxelib name="hscript" /> <!-- Scripting -->
<haxelib name="flixel-ui" /> <!-- UI framework (deprecate this? -->
<haxelib name="haxeui-core" /> <!-- UI framework -->
<haxelib name="haxeui-flixel" /> <!-- Integrate HaxeUI with Flixel -->
<haxelib name="polymod" /> <!-- Modding framework -->
<haxelib name="flxanimate" /> <!-- Texture atlas rendering -->
<haxelib name="hxvlc" /> <!-- Video playback -->
<haxelib name="thx.semver" /> <!-- Semantic version handling -->
<haxelib name="json2object" /> <!-- JSON parsing -->
<!-- Test dependencies -->
<haxelib name="munit" /> <!-- Unit test execution -->
<haxelib name="mcover" /> <!-- Code coverage -->
<haxelib name="mockatoo" /> <!-- Mocking -->
<haxelib name="hamcrest" /> <!-- Assertions/matching -->
<!-- This macro allows addition of new functionality to existing Flixel. -->
<haxeflag name="--macro" value="addMetadata('@:build(funkin.util.macro.FlxMacro.buildFlxBasic())', 'flixel.FlxBasic')" />
<!-- Macros to satisfy null safety (null safety can't check nested functions, so assertions must be inlined) -->
<haxeflag name="--macro" value="addMetadata('@:build(funkin.util.macro.InlineMacro.makeInline(\'fail\', true))', 'massive.munit.Assert')" />
<haxeflag name="--macro" value="addMetadata('@:build(funkin.util.macro.InlineMacro.makeInline(\'isNotNull\', true))', 'massive.munit.Assert')" />
<!-- Assets -->
<assets path="assets/preload" rename="assets" exclude="*.ogg" if="web" />
<assets path="assets/preload" rename="assets" exclude="*.mp3" unless="web" />
<assets path="assets/shared" library="shared" exclude="*.fla|*.ogg" if="web" />
<assets path="assets/shared" library="shared" exclude="*.fla|*.mp3" unless="web" />
<library name="shared" preload="true" />
<!--
<assets path="assets/songs" library="songs" exclude="*.fla|*.ogg" if="web" />
<assets path="assets/songs" library="songs" exclude="*.fla|*.mp3" unless="web" />
<assets path="assets/tutorial" library="tutorial" exclude="*.fla|*.ogg" if="web" />
<assets path="assets/tutorial" library="tutorial" exclude="*.fla|*.mp3" unless="web" />
<assets path="assets/week1" library="week1" exclude="*.fla|*.ogg" if="web" />
<assets path="assets/week1" library="week1" exclude="*.fla|*.mp3" unless="web" />
<assets path="assets/week2" library="week2" exclude="*.fla|*.ogg" if="web" />
<assets path="assets/week2" library="week2" exclude="*.fla|*.mp3" unless="web" />
<assets path="assets/week3" library="week3" exclude="*.fla|*.ogg" if="web" />
<assets path="assets/week3" library="week3" exclude="*.fla|*.mp3" unless="web" />
<assets path="assets/week4" library="week4" exclude="*.fla|*.ogg" if="web" />
<assets path="assets/week4" library="week4" exclude="*.fla|*.mp3" unless="web" />
<assets path="assets/week5" library="week5" exclude="*.fla|*.ogg" if="web" />
<assets path="assets/week5" library="week5" exclude="*.fla|*.mp3" unless="web" />
<assets path="assets/week6" library="week6" exclude="*.fla|*.ogg" if="web" />
<assets path="assets/week6" library="week6" exclude="*.fla|*.mp3" unless="web" />
<assets path="assets/week7" library="week7" exclude="*.fla|*.ogg" if="web" />
<assets path="assets/week7" library="week7" exclude="*.fla|*.mp3" unless="web" />
<assets path="assets/weekend1" library="weekend1" exclude="*.fla|*.ogg" if="web" />
<assets path="assets/weekend1" library="weekend1" exclude="*.fla|*.mp3" unless="web" />
<library name="songs" preload="true" />
<library name="tutorial" preload="true" />
<library name="week1" preload="true" />
<library name="week2" preload="true" />
<library name="week3" preload="true" />
<library name="week4" preload="true" />
<library name="week5" preload="true" />
<library name="week6" preload="true" />
<library name="week7" preload="true" />
<library name="weekend1" preload="true" />
-->
<!-- Test defines -->
<set name="no-custom-backend" />
<set name="unit-test" />
<haxedef name="FLX_UNIT_TEST" />
<haxedef name="FLX_RECORD" />
<!-- Clean up the output -->
<!--
<haxedef name="echo-traces" />
-->
<haxedef name="ignore-inline" />
<haxeflag name="-w" value="-WDeprecated" />
<!-- Manually set up code coverage (because munit report and lime test are mutually exclusive) -->
<haxeflag name="--macro" value="mcover.MCover.coverage(['funkin'],['../../source', 'source/'],[''])" />
<haxelib name="mcover" />
<haxedef name="MCOVER" />
<haxedef name="safeMode"/>
<haxedef name="HXCPP_CHECK_POINTER" />
<haxedef name="HXCPP_STACK_LINE" />
<haxedef name="HXCPP_STACK_TRACE" />
</project>
-4
View File
@@ -1,4 +0,0 @@
#!/bin/bash
cd ./report/
genhtml -o ./html/ ./lcov.info
-180
View File
@@ -1,180 +0,0 @@
package;
import flixel.math.FlxPoint;
import flixel.math.FlxRect;
import haxe.PosInfos;
import massive.munit.Assert;
using flixel.util.FlxArrayUtil;
/**
* @see https://github.com/HaxeFlixel/flixel/tree/dev/tests/unit
*/
@:nullSafety
class FunkinAssert
{
/**
* Assert if `expected` is within `margin` of `actual`, and fail if not.
* Useful for comparting Float values.
*
* @param expected The expected value of the test.
* @param actual The actual value of the test.
* @param margin The allowed margin of error between the expected and actual values.
* @param info Info on the position this function was called from. Magic value, passed automatically.
*/
public static function areNear(expected:Float, ?actual:Float, margin:Float = 0.001, ?info:PosInfos):Void
{
if (actual == null) Assert.fail('Value [$actual] is null, and cannot be compared to [$expected]', info);
if (areNearHelper(expected, actual)) Assert.assertionCount++;
else
Assert.fail('Value [$actual] is not within [$margin] of [$expected]', info);
}
public static function rectsNear(expected:FlxRect, ?actual:FlxRect, margin:Float = 0.001, ?info:PosInfos):Void
{
if (actual == null) Assert.fail('Value [$actual] is null, and cannot be compared to [$expected]', info);
var areNear = areNearHelper(expected.x, actual.x, margin)
&& areNearHelper(expected.y, actual.y, margin)
&& areNearHelper(expected.width, actual.width, margin)
&& areNearHelper(expected.height, actual.height, margin);
if (areNear) Assert.assertionCount++;
else
Assert.fail('Value [$actual] is not within [$margin] of [$expected]', info);
}
static function areNearHelper(expected:Float, actual:Float, margin:Float = 0.001):Bool
{
return actual >= expected - margin && actual <= expected + margin;
}
public static function arraysEqual<T>(expected:Array<T>, ?actual:Array<T>, ?info:PosInfos):Void
{
if (actual == null) Assert.fail('Value [$actual] is null, and cannot be compared to [$expected]', info);
if (expected.equals(actual)) Assert.assertionCount++;
else
Assert.fail('\nExpected\n ${expected}\nbut was\n ${actual}\n', info);
}
public static function arraysNotEqual<T>(expected:Array<T>, ?actual:Array<T>, ?info:PosInfos):Void
{
if (actual == null) Assert.fail('Value [$actual] is null, and cannot be compared to [$expected]', info);
if (!expected.equals(actual)) Assert.assertionCount++;
else
Assert.fail('\nValue\n ${actual}\nwas equal to\n ${expected}\n', info);
}
public static function pointsEqual(expected:FlxPoint, ?actual:FlxPoint, ?msg:String, ?info:PosInfos)
{
if (actual == null) Assert.fail('Value [$actual] is null, and cannot be compared to [$expected]', info);
if (expected.equals(actual)) Assert.assertionCount++;
else if (msg != null) Assert.fail(msg, info);
else
Assert.fail("Value [" + actual + "] was not equal to expected value [" + expected + "]", info);
}
public static function pointsNotEqual(expected:FlxPoint, ?actual:FlxPoint, ?msg:String, ?info:PosInfos)
{
if (actual == null) Assert.fail('Value [$actual] is null, and cannot be compared to [$expected]', info);
if (!expected.equals(actual)) Assert.assertionCount++;
else if (msg != null) Assert.fail(msg, info);
else
Assert.fail("Value [" + actual + "] was equal to value [" + expected + "]", info);
}
/**
* Execute `targetFunc`, expecting it to throw an exception.
* If it doesn't, or if the exception doesn't validate against the provided `predicate`, fail.
*/
public static function validateThrows(targetFunc:Void->Void, predicate:Dynamic->Bool, ?info:PosInfos)
{
try
{
targetFunc();
Assert.fail("Expected exception to be thrown, got no failure.", info);
}
catch (e:Dynamic)
{
if (predicate(e))
{
Assert.assertionCount++;
}
else
{
Assert.fail('Expected exception to match predicate, but failed (got ${e})', info);
}
}
}
/**
* Execute `targetFunc`, expecting it to throw a `json2object.Error.CustomFunctionException` with a message matching `expected`.
* I made this its own function since it's the most common specific use case of `validateThrows`.
*/
public static function validateThrowsJ2OCustom(targetFunc:Void->Void, expected:String, ?info:PosInfos)
{
var predicate:Dynamic->Bool = function(err:Dynamic):Bool {
if (!Std.isOfType(err, json2object.Error)) Assert.fail('Expected error of type json2object.Error, got ${Type.typeof(err)}');
switch (err)
{
case json2object.Error.CustomFunctionException(msg, pos):
if (msg != expected) Assert.fail('Expected message [${expected}], got [${msg}].');
default:
Assert.fail('Expected error of type CustomFunctionException, got [${err}].');
}
return true;
};
validateThrows(targetFunc, predicate, info);
}
static var capturedTraces:Array<String> = [];
public static function initAssertTrace():Void
{
var oldTrace = haxe.Log.trace;
haxe.Log.trace = function(v:Dynamic, ?infos:haxe.PosInfos) {
onTrace(v, infos);
// oldTrace(v, infos);
};
}
public static function clearTraces():Void
{
capturedTraces = [];
}
@:nullSafety(Off) // Why isn't haxe.std null-safe?
static function onTrace(v:Dynamic, ?infos:haxe.PosInfos)
{
// var str:String = haxe.Log.formatOutput(v, infos);
var str:String = Std.string(v);
capturedTraces.push(str);
#if (sys && echo_traces)
Sys.println('[TESTLOG] $str');
#end
}
/**
* Check the first string that was traced and validate it.
* @param expected
*/
public static inline function assertTrace(expected:String):Void
{
var actual:Null<String> = capturedTraces.shift();
Assert.isNotNull(actual);
Assert.areEqual(expected, actual);
}
/**
* Check the first string that was traced and validate it.
* @param expected
*/
public static inline function assertLastTrace(expected:String):Void
{
var actual:Null<String> = capturedTraces.pop();
Assert.isNotNull(actual);
Assert.areEqual(expected, actual);
}
}
-105
View File
@@ -1,105 +0,0 @@
package;
import openfl.errors.Error;
import flixel.FlxG;
import flixel.FlxState;
import flixel.tweens.FlxTween;
import flixel.util.FlxDestroyUtil.IFlxDestroyable;
import massive.munit.Assert;
/**
* @see https://github.com/HaxeFlixel/flixel/tree/dev/tests/unit
*/
@:nullSafety
class FunkinTest
{
public static final MS_PER_STEP:Float = 1.0 / 60.0 * 1000;
// approx. amount of ticks at 60 fps
static inline var TICKS_PER_FRAME:UInt = 25;
static var totalSteps:UInt = 0;
var destroyable:Null<IFlxDestroyable> = null;
public function new() {}
@After
@:access(flixel)
function after()
{
// Redefine how the game gets the time during tests.
FlxG.game.getTimer = function() {
return totalSteps * TICKS_PER_FRAME;
}
// make sure we have the same starting conditions for each test
resetGame();
}
/**
* Advance the game simulation.
* @param steps The amount to advance the game by.
* @param callback A function to call after each step.
*/
@:access(flixel)
function step(steps:UInt = 1, ?callback:Void->Void)
{
for (i in 0...steps)
{
FlxG.game.step();
if (callback != null) callback();
totalSteps++;
}
}
function resetGame()
{
FlxG.resetGame();
step();
}
function switchState(nextState:FlxState)
{
FlxG.switchState(nextState);
step();
}
function resetState()
{
FlxG.resetState();
step();
}
@Test
public function testAssert()
{
Assert.areEqual(4, 2 + 2);
}
@Test
function testDestroy()
{
if (destroyable == null)
{
return;
}
try
{
destroyable.destroy();
destroyable.destroy();
}
catch (e:Error)
{
Assert.fail(e.message);
}
}
function finishTween(tween:FlxTween)
{
while (!tween.finished)
{
step();
}
}
}
-57
View File
@@ -1,57 +0,0 @@
package;
import massive.munit.util.Timer;
import massive.munit.Assert;
import massive.munit.async.AsyncFactory;
import funkin.util.DateUtil;
@:nullSafety
class MockTest extends FunkinTest
{
public function new()
{
super();
}
@BeforeClass
public function beforeClass() {}
@AfterClass
public function afterClass() {}
@Before
public function setup() {}
@After
public function tearDown() {}
@Test
public function testMock()
{
// Test that mocking works.
var mockSprite = Mockatoo.mock(flixel.FlxSprite);
var mockAnim = Mockatoo.mock(flixel.animation.FlxAnimationController);
mockSprite.animation = mockAnim;
var animData:funkin.data.animation.AnimationData =
{
name: "testAnim",
prefix: "blablabla"
};
mockSprite.animation.addByPrefix("testAnim", "blablabla", 24, false, false, false);
// Verify that the method was called once.
// If not, a VerificationException will be thrown and the test will fail.
mockAnim.addByPrefix("testAnim", "blablabla", 24, false, false, false).verify(times(1));
FunkinAssert.validateThrows(function() {
// Attempt to verify the method was called.
// This should FAIL, since we didn't call the method.
mockAnim.addByPrefix("testAnim", "blablabla", 24, false, false, false).verify(times(1));
}, function(err) {
return Std.isOfType(err, mockatoo.exception.VerificationException);
});
}
}
-94
View File
@@ -1,94 +0,0 @@
package;
import openfl.Lib;
import flixel.FlxGame;
import flixel.FlxState;
import massive.munit.TestRunner;
import massive.munit.client.HTTPClient;
import massive.munit.client.SummaryReportClient;
import funkin.util.logging.CrashHandler;
import funkin.util.FileUtil;
/**
* Auto generated Test Application.
* Refer to munit command line tool for more information (haxelib run munit)
*/
@:nullSafety
class TestMain
{
/**
* If true, include a report with each ignored test and their descriptions.
*/
static final INCLUDE_IGNORED_REPORT:Bool = false;
static final COVERAGE_FOLDER:String = "../../../report";
static function main()
{
new TestMain();
}
public function new()
{
try
{
CrashHandler.initialize();
// Flixel was not designed for unit testing so we can only have one instance for now.
Lib.current.stage.addChild(new FlxGame(640, 480, FlxState, 60, 60, true));
var suites = new Array<Class<massive.munit.TestSuite>>();
suites.push(TestSuite);
#if MCOVER
// Print individual test results alongside coverage results for each test class,
// as well as a final coverage report for the entire test suite.
var innerClient = new massive.munit.client.RichPrintClient(INCLUDE_IGNORED_REPORT);
var client = new mcover.coverage.munit.client.MCoverPrintClient(innerClient);
// Print final test results alongside detailed coverage results for the test suite.
var httpClient = new HTTPClient(new mcover.coverage.munit.client.MCoverSummaryReportClient());
// NOTE: You can also create a custom ICoverageTestResultClient implementation
// Output coverage in LCOV format.
FileUtil.createDirIfNotExists(COVERAGE_FOLDER);
mcover.coverage.MCoverage.getLogger().addClient(new mcover.coverage.client.LcovPrintClient("Funkin' Coverage Report", '${COVERAGE_FOLDER}/lcov.info'));
#else
// Print individual test results.
var client = new massive.munit.client.RichPrintClient(INCLUDE_IGNORED_REPORT);
// Print final test suite results.
var httpClient = new HTTPClient(new SummaryReportClient());
#end
var runner = new TestRunner(client);
runner.addResultClient(httpClient);
runner.completionHandler = completionHandler;
runner.run(suites);
}
catch (e)
{
trace('UNCAUGHT EXCEPTION');
trace(e);
}
}
/**
* updates the background color and closes the current browser
* for flash and html targets (useful for continuos integration servers)
*/
function completionHandler(successful:Bool):Void
{
try
{
#if flash
openfl.external.ExternalInterface.call("testResult", successful);
#elseif js
js.Lib.eval("testResult(" + successful + ");");
#elseif sys
Sys.exit(successful ? 0 : 1);
#end
}
// if run from outside browser can get error which we can ignore
catch (e:Dynamic) {}
}
}
-30
View File
@@ -1,30 +0,0 @@
package funkin.play;
import massive.munit.util.Timer;
import massive.munit.Assert;
import massive.munit.async.AsyncFactory;
import funkin.play.PlayState;
@:access(funkin.play.PlayState)
class Template extends FunkinTest
{
public function new()
{
super();
}
@BeforeClass
public function beforeClass() {}
@AfterClass
public function afterClass() {}
@Before
public function setup() {}
@After
public function tearDown() {}
@Test
public function test() {}
}
-107
View File
@@ -1,107 +0,0 @@
package flixel;
import massive.munit.Assert;
@:access(flixel.FlxG)
class FlxGTest extends FunkinTest
{
@Test function testVERSIONNull():Void
Assert.isNotNull(FlxG.VERSION);
@Test function testGameNull():Void
Assert.isNotNull(FlxG.game);
@Test function testStageNull():Void
Assert.isNotNull(FlxG.stage);
@Test function testStateNull():Void
Assert.isNotNull(FlxG.state);
@Test function testWorldBoundsNull():Void
Assert.isNotNull(FlxG.worldBounds);
@Test function testSaveNull():Void
Assert.isNotNull(FlxG.save);
#if FLX_MOUSE
@Test function testMouseNull():Void
Assert.isNotNull(FlxG.mouse);
#end
#if FLX_TOUCH
@Test function testTouchNull():Void
Assert.isNotNull(FlxG.touches);
#end
#if FLX_POINTER_INPUT
@Test function testSwipesNull():Void
Assert.isNotNull(FlxG.swipes);
#end
#if FLX_KEYBOARD
@Test function testKeysNull():Void
Assert.isNotNull(FlxG.keys);
#end
#if FLX_GAMEPAD
@Test function testGamepadsNull():Void
Assert.isNotNull(FlxG.gamepads);
#end
#if android
@Test function testAndroidNull():Void
Assert.isNotNull(FlxG.android);
#end
#if js
@Test function testHtml5Null():Void
Assert.isNotNull(FlxG.html5);
#end
@Test function testInputsNull():Void
Assert.isNotNull(FlxG.inputs);
@Test function testConsoleNull():Void
Assert.isNotNull(FlxG.console);
@Test function testLogNull():Void
Assert.isNotNull(FlxG.log);
@Test function testWatchNull():Void
Assert.isNotNull(FlxG.watch);
@Test function testDebuggerNull():Void
Assert.isNotNull(FlxG.debugger);
@Test function testVcrNull():Void
Assert.isNotNull(FlxG.vcr);
@Test function testBitmapNull():Void
Assert.isNotNull(FlxG.bitmap);
@Test function testCamerasNull():Void
Assert.isNotNull(FlxG.cameras);
@Test function testPluginsNull():Void
Assert.isNotNull(FlxG.plugins);
#if FLX_SOUND_SYSTEM
@Test function testSoundNull():Void
Assert.isNotNull(FlxG.sound);
#end
@Test function testScaleModeNull():Void
Assert.isNotNull(FlxG.scaleMode);
@Test
function testDefaultWidth():Void
{
Assert.areEqual(640, FlxG.width);
}
@Test
function testDefaultHeight():Void
{
Assert.areEqual(480, FlxG.height);
}
}
-509
View File
@@ -1,509 +0,0 @@
package funkin;
import flixel.FlxG;
import flixel.FlxState;
import funkin.Conductor;
import funkin.data.song.SongData.SongTimeChange;
import funkin.util.Constants;
import massive.munit.Assert;
@:nullSafety
@:access(funkin.Conductor)
class ConductorTest extends FunkinTest
{
var conductorState:Null<ConductorState> = null;
@Before
function before()
{
FunkinAssert.initAssertTrace();
resetGame();
// The ConductorState will advance the conductor when step() is called.
FlxG.switchState(conductorState = new ConductorState());
Conductor.reset();
}
@Test
function testDefaultValues():Void
{
// NOTE: Expected value comes first.
Assert.areEqual([], Conductor.instance.timeChanges);
Assert.areEqual(null, Conductor.instance.currentTimeChange);
Assert.areEqual(0, Conductor.instance.songPosition);
Assert.areEqual(Constants.DEFAULT_BPM, Conductor.instance.bpm);
Assert.areEqual(null, Conductor.instance.bpmOverride);
Assert.areEqual(600, Conductor.instance.beatLengthMs);
Assert.areEqual(4, Conductor.instance.timeSignatureNumerator);
Assert.areEqual(4, Conductor.instance.timeSignatureDenominator);
Assert.areEqual(0, Conductor.instance.currentBeat);
Assert.areEqual(0, Conductor.instance.currentStep);
Assert.areEqual(0.0, Conductor.instance.currentStepTime);
Assert.areEqual(150, Conductor.instance.stepLengthMs);
}
/**
* Tests implementation of `update()`, and how it affects
* `currentBeat`, `currentStep`, `currentStepTime`, and the `beatHit` and `stepHit` signals.
*/
@Test
function testUpdate():Void
{
var currentConductorState:Null<ConductorState> = conductorState;
Assert.isNotNull(currentConductorState);
Assert.areEqual(0, Conductor.instance.songPosition);
step(); // 1
var BPM_100_STEP_TIME = 1 / 9;
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 1, Conductor.instance.songPosition);
Assert.areEqual(0, Conductor.instance.currentBeat);
Assert.areEqual(0, Conductor.instance.currentStep);
FunkinAssert.areNear(1 / 9, Conductor.instance.currentStepTime);
step(7); // 8
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 8, Conductor.instance.songPosition);
Assert.areEqual(0, Conductor.instance.currentBeat);
Assert.areEqual(0, Conductor.instance.currentStep);
FunkinAssert.areNear(8 / 9, Conductor.instance.currentStepTime);
Assert.areEqual(0, currentConductorState.beatsHit);
Assert.areEqual(0, currentConductorState.stepsHit);
step(); // 9
Assert.areEqual(0, currentConductorState.beatsHit);
Assert.areEqual(1, currentConductorState.stepsHit);
currentConductorState.beatsHit = 0;
currentConductorState.stepsHit = 0;
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 9, Conductor.instance.songPosition);
Assert.areEqual(0, Conductor.instance.currentBeat);
Assert.areEqual(1, Conductor.instance.currentStep);
FunkinAssert.areNear(1.0, Conductor.instance.currentStepTime);
step(35 - 9); // 35
Assert.areEqual(0, currentConductorState.beatsHit);
Assert.areEqual(2, currentConductorState.stepsHit);
currentConductorState.beatsHit = 0;
currentConductorState.stepsHit = 0;
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 35, Conductor.instance.songPosition);
Assert.areEqual(0, Conductor.instance.currentBeat);
Assert.areEqual(3, Conductor.instance.currentStep);
FunkinAssert.areNear(3.0 + 8 / 9, Conductor.instance.currentStepTime);
step(); // 36
Assert.areEqual(1, currentConductorState.beatsHit);
Assert.areEqual(1, currentConductorState.stepsHit);
currentConductorState.beatsHit = 0;
currentConductorState.stepsHit = 0;
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 36, Conductor.instance.songPosition);
Assert.areEqual(1, Conductor.instance.currentBeat);
Assert.areEqual(4, Conductor.instance.currentStep);
FunkinAssert.areNear(4.0, Conductor.instance.currentStepTime);
step(50 - 36); // 50
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 50, Conductor.instance.songPosition);
Assert.areEqual(1, Conductor.instance.currentBeat);
Assert.areEqual(5, Conductor.instance.currentStep);
FunkinAssert.areNear(5.555555, Conductor.instance.currentStepTime);
step(49); // 99
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 99, Conductor.instance.songPosition);
Assert.areEqual(2, Conductor.instance.currentBeat);
Assert.areEqual(11, Conductor.instance.currentStep);
FunkinAssert.areNear(11.0, Conductor.instance.currentStepTime);
step(1); // 100
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 100, Conductor.instance.songPosition);
Assert.areEqual(2, Conductor.instance.currentBeat);
Assert.areEqual(11, Conductor.instance.currentStep);
FunkinAssert.areNear(11.111111, Conductor.instance.currentStepTime);
}
@Test
function testUpdateForcedBPM():Void
{
Conductor.instance.forceBPM(60);
Assert.areEqual(0, Conductor.instance.songPosition);
// 60 beats per minute = 1 beat per second
// 1 beat per second = 1/60 beats per frame = 4/60 steps per frame
step(); // Advances time 1/60 of 1 second.
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 1, Conductor.instance.songPosition);
Assert.areEqual(0, Conductor.instance.currentBeat);
Assert.areEqual(0, Conductor.instance.currentStep);
FunkinAssert.areNear(4 / 60, Conductor.instance.currentStepTime); // 1/60 of 1 beat = 4/60 of 1 step
step(14 - 1); // 14
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 14, Conductor.instance.songPosition);
Assert.areEqual(0, Conductor.instance.currentBeat);
Assert.areEqual(0, Conductor.instance.currentStep);
FunkinAssert.areNear(1.0 - 4 / 60, Conductor.instance.currentStepTime); // 1/60 of 1 beat = 4/60 of 1 step
step(); // 15
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 15, Conductor.instance.songPosition);
Assert.areEqual(0, Conductor.instance.currentBeat);
Assert.areEqual(1, Conductor.instance.currentStep);
FunkinAssert.areNear(1.0, Conductor.instance.currentStepTime); // 1/60 of 1 beat = 4/60 of 1 step
step(45 - 1); // 59
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 59, Conductor.instance.songPosition);
Assert.areEqual(0, Conductor.instance.currentBeat);
Assert.areEqual(3, Conductor.instance.currentStep);
FunkinAssert.areNear(4.0 - 4 / 60, Conductor.instance.currentStepTime);
step(); // 60
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 60, Conductor.instance.songPosition);
Assert.areEqual(1, Conductor.instance.currentBeat);
Assert.areEqual(4, Conductor.instance.currentStep);
FunkinAssert.areNear(4.0, Conductor.instance.currentStepTime);
step(); // 61
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 61, Conductor.instance.songPosition);
Assert.areEqual(1, Conductor.instance.currentBeat);
Assert.areEqual(4, Conductor.instance.currentStep);
FunkinAssert.areNear(4.0 + 4 / 60, Conductor.instance.currentStepTime);
}
@Test
function testSingleTimeChange():Void
{
// Start the song with a BPM of 120.
var songTimeChanges:Array<SongTimeChange> = [new SongTimeChange(0, 120)];
Conductor.instance.mapTimeChanges(songTimeChanges);
// All should be at 0.
FunkinAssert.areNear(0, Conductor.instance.songPosition);
Assert.areEqual(0, Conductor.instance.currentBeat);
Assert.areEqual(0, Conductor.instance.currentStep);
FunkinAssert.areNear(0.0, Conductor.instance.currentStepTime); // 2/120 of 1 beat = 8/120 of 1 step
// 120 beats per minute = 2 beat per second
// 2 beat per second = 2/60 beats per frame = 16/120 steps per frame
step(); // Advances time 1/60 of 1 second.
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 1, Conductor.instance.songPosition);
Assert.areEqual(0, Conductor.instance.currentBeat);
Assert.areEqual(0, Conductor.instance.currentStep);
FunkinAssert.areNear(16 / 120, Conductor.instance.currentStepTime); // 2/120 of 1 beat = 8/120 of 1 step
step(15 - 1); // 15
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 15, Conductor.instance.songPosition);
Assert.areEqual(0, Conductor.instance.currentBeat);
Assert.areEqual(2, Conductor.instance.currentStep);
FunkinAssert.areNear(2.0, Conductor.instance.currentStepTime); // 2/60 of 1 beat = 8/60 of 1 step
step(45 - 1); // 59
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 59, Conductor.instance.songPosition);
Assert.areEqual(1, Conductor.instance.currentBeat);
Assert.areEqual(7, Conductor.instance.currentStep);
FunkinAssert.areNear(7.0 + 104 / 120, Conductor.instance.currentStepTime);
step(); // 60
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 60, Conductor.instance.songPosition);
Assert.areEqual(2, Conductor.instance.currentBeat);
Assert.areEqual(8, Conductor.instance.currentStep);
FunkinAssert.areNear(8.0, Conductor.instance.currentStepTime);
step(); // 61
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 61, Conductor.instance.songPosition);
Assert.areEqual(2, Conductor.instance.currentBeat);
Assert.areEqual(8, Conductor.instance.currentStep);
FunkinAssert.areNear(8.0 + 8 / 60, Conductor.instance.currentStepTime);
}
@Test
function testDoubleTimeChange():Void
{
// Start the song with a BPM of 120.
var songTimeChanges:Array<SongTimeChange> = [new SongTimeChange(0, 120), new SongTimeChange(3000, 90)];
Conductor.instance.mapTimeChanges(songTimeChanges);
// All should be at 0.
FunkinAssert.areNear(0, Conductor.instance.songPosition);
Assert.areEqual(0, Conductor.instance.currentBeat);
Assert.areEqual(0, Conductor.instance.currentStep);
FunkinAssert.areNear(0.0, Conductor.instance.currentStepTime); // 2/120 of 1 beat = 8/120 of 1 step
// 120 beats per minute = 2 beat per second
// 2 beat per second = 2/60 beats per frame = 16/120 steps per frame
step(); // Advances time 1/60 of 1 second.
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 1, Conductor.instance.songPosition);
Assert.areEqual(0, Conductor.instance.currentBeat);
Assert.areEqual(0, Conductor.instance.currentStep);
FunkinAssert.areNear(16 / 120, Conductor.instance.currentStepTime); // 4/120 of 1 beat = 16/120 of 1 step
step(60 - 1 - 1); // 59
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 59, Conductor.instance.songPosition);
Assert.areEqual(1, Conductor.instance.currentBeat);
Assert.areEqual(7, Conductor.instance.currentStep);
FunkinAssert.areNear(7.0 + 104 / 120, Conductor.instance.currentStepTime);
step(); // 60
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 60, Conductor.instance.songPosition);
Assert.areEqual(2, Conductor.instance.currentBeat);
Assert.areEqual(8, Conductor.instance.currentStep);
FunkinAssert.areNear(8.0, Conductor.instance.currentStepTime);
step(); // 61
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 61, Conductor.instance.songPosition);
Assert.areEqual(2, Conductor.instance.currentBeat);
Assert.areEqual(8, Conductor.instance.currentStep);
FunkinAssert.areNear(8.0 + 8 / 60, Conductor.instance.currentStepTime);
step(179 - 61); // 179
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 179, Conductor.instance.songPosition);
Assert.areEqual(5, Conductor.instance.currentBeat);
Assert.areEqual(23, Conductor.instance.currentStep);
FunkinAssert.areNear(23.0 + 52 / 60, Conductor.instance.currentStepTime);
step(); // 180 (3 seconds)
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 180, Conductor.instance.songPosition);
Assert.areEqual(6, Conductor.instance.currentBeat);
Assert.areEqual(24, Conductor.instance.currentStep);
FunkinAssert.areNear(24.0, Conductor.instance.currentStepTime);
step(); // 181 (3 + 1/60 seconds)
// BPM has switched to 90!
// 90 beats per minute = 1.5 beat per second
// 1.5 beat per second = 1.5/60 beats per frame = 3/120 beats per frame
// = 12/120 steps per frame
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 181, Conductor.instance.songPosition);
Assert.areEqual(6, Conductor.instance.currentBeat);
Assert.areEqual(24, Conductor.instance.currentStep);
FunkinAssert.areNear(24.0 + 12 / 120, Conductor.instance.currentStepTime);
step(59); // 240 (4 seconds)
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 240, Conductor.instance.songPosition);
Assert.areEqual(7, Conductor.instance.currentBeat);
Assert.areEqual(30, Conductor.instance.currentStep);
FunkinAssert.areNear(30.0, Conductor.instance.currentStepTime);
step(); // 241 (4 + 1/60 seconds)
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 241, Conductor.instance.songPosition);
Assert.areEqual(7, Conductor.instance.currentBeat);
Assert.areEqual(30, Conductor.instance.currentStep);
FunkinAssert.areNear(30.0 + 12 / 120, Conductor.instance.currentStepTime);
}
@Test
function testTripleTimeChange():Void
{
// Start the song with a BPM of 120, then move to 90, then move to 180.
var songTimeChanges:Array<SongTimeChange> = [
new SongTimeChange(0, 120),
new SongTimeChange(3000, 90),
new SongTimeChange(6000, 180)
];
Conductor.instance.mapTimeChanges(songTimeChanges);
// Verify time changes.
Assert.areEqual(3, Conductor.instance.timeChanges.length);
FunkinAssert.areNear(0, Conductor.instance.timeChanges[0].beatTime);
FunkinAssert.areNear(6, Conductor.instance.timeChanges[1].beatTime);
FunkinAssert.areNear(10.5, Conductor.instance.timeChanges[2].beatTime);
// All should be at 0.
FunkinAssert.areNear(0, Conductor.instance.songPosition);
Assert.areEqual(0, Conductor.instance.currentBeat);
Assert.areEqual(0, Conductor.instance.currentStep);
FunkinAssert.areNear(0.0, Conductor.instance.currentStepTime); // 2/120 of 1 beat = 8/120 of 1 step
// 120 beats per minute = 2 beat per second
// 2 beat per second = 2/60 beats per frame = 16/120 steps per frame
step(); // Advances time 1/60 of 1 second.
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 1, Conductor.instance.songPosition);
Assert.areEqual(0, Conductor.instance.currentBeat);
Assert.areEqual(0, Conductor.instance.currentStep);
FunkinAssert.areNear(16 / 120, Conductor.instance.currentStepTime); // 4/120 of 1 beat = 16/120 of 1 step
step(60 - 1 - 1); // 59
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 59, Conductor.instance.songPosition);
Assert.areEqual(1, Conductor.instance.currentBeat);
Assert.areEqual(7, Conductor.instance.currentStep);
FunkinAssert.areNear(7 + 104 / 120, Conductor.instance.currentStepTime);
step(); // 60
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 60, Conductor.instance.songPosition);
Assert.areEqual(2, Conductor.instance.currentBeat);
Assert.areEqual(8, Conductor.instance.currentStep);
FunkinAssert.areNear(8.0, Conductor.instance.currentStepTime);
step(); // 61
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 61, Conductor.instance.songPosition);
Assert.areEqual(2, Conductor.instance.currentBeat);
Assert.areEqual(8, Conductor.instance.currentStep);
FunkinAssert.areNear(8.0 + 8 / 60, Conductor.instance.currentStepTime);
step(179 - 61); // 179
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 179, Conductor.instance.songPosition);
Assert.areEqual(5, Conductor.instance.currentBeat);
Assert.areEqual(23, Conductor.instance.currentStep);
FunkinAssert.areNear(23.0 + 52 / 60, Conductor.instance.currentStepTime);
step(); // 180 (3 seconds)
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 180, Conductor.instance.songPosition);
Assert.areEqual(6, Conductor.instance.currentBeat);
Assert.areEqual(24, Conductor.instance.currentStep); // 23.999 => 24
FunkinAssert.areNear(24.0, Conductor.instance.currentStepTime);
step(); // 181 (3 + 1/60 seconds)
// BPM has switched to 90!
// 90 beats per minute = 1.5 beat per second
// 1.5 beat per second = 1.5/60 beats per frame = 3/120 beats per frame
// = 12/120 steps per frame
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 181, Conductor.instance.songPosition);
Assert.areEqual(6, Conductor.instance.currentBeat);
Assert.areEqual(24, Conductor.instance.currentStep);
FunkinAssert.areNear(24.0 + 12 / 120, Conductor.instance.currentStepTime);
step(60 - 1 - 1); // 240 (4 seconds)
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 239, Conductor.instance.songPosition);
Assert.areEqual(7, Conductor.instance.currentBeat);
Assert.areEqual(29, Conductor.instance.currentStep);
FunkinAssert.areNear(29.0 + 108 / 120, Conductor.instance.currentStepTime);
step(); // 240 (4 seconds)
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 240, Conductor.instance.songPosition);
Assert.areEqual(7, Conductor.instance.currentBeat);
Assert.areEqual(30, Conductor.instance.currentStep);
FunkinAssert.areNear(30.0, Conductor.instance.currentStepTime);
step(); // 241 (4 + 1/60 seconds)
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 241, Conductor.instance.songPosition);
Assert.areEqual(7, Conductor.instance.currentBeat);
Assert.areEqual(30, Conductor.instance.currentStep);
FunkinAssert.areNear(30.0 + 12 / 120, Conductor.instance.currentStepTime);
step(359 - 241); // 359 (5 + 59/60 seconds)
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 359, Conductor.instance.songPosition);
Assert.areEqual(10, Conductor.instance.currentBeat);
Assert.areEqual(41, Conductor.instance.currentStep);
FunkinAssert.areNear(41 + 108 / 120, Conductor.instance.currentStepTime);
step(); // 360
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 360, Conductor.instance.songPosition);
Assert.areEqual(10, Conductor.instance.currentBeat);
Assert.areEqual(42, Conductor.instance.currentStep); // 41.999
FunkinAssert.areNear(42.0, Conductor.instance.currentStepTime);
step(); // 361
// BPM has switched to 180!
// 180 beats per minute = 3 beat per second
// 3 beat per second = 3/60 beats per frame
// = 12/60 steps per frame
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 361, Conductor.instance.songPosition);
Assert.areEqual(10, Conductor.instance.currentBeat);
Assert.areEqual(42, Conductor.instance.currentStep);
FunkinAssert.areNear(42.0 + 12 / 60, Conductor.instance.currentStepTime);
step(); // 362
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 362, Conductor.instance.songPosition);
Assert.areEqual(10, Conductor.instance.currentBeat);
Assert.areEqual(42, Conductor.instance.currentStep);
FunkinAssert.areNear(42.0 + 24 / 60, Conductor.instance.currentStepTime);
step(3); // 365
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 365, Conductor.instance.songPosition);
Assert.areEqual(10, Conductor.instance.currentBeat);
Assert.areEqual(43, Conductor.instance.currentStep); // 42.999 => 42
FunkinAssert.areNear(43.0, Conductor.instance.currentStepTime);
}
}
class ConductorState extends FlxState
{
public var beatsHit:Int = 0;
public var stepsHit:Int = 0;
public function new()
{
super();
}
function beatHit():Void
{
beatsHit += 1;
}
function stepHit():Void
{
stepsHit += 1;
}
public override function create():Void
{
super.create();
Conductor.beatHit.add(this.beatHit);
Conductor.stepHit.add(this.stepHit);
}
public override function destroy():Void
{
super.destroy();
Conductor.beatHit.remove(this.beatHit);
Conductor.stepHit.remove(this.stepHit);
}
public override function update(elapsed:Float)
{
super.update(elapsed);
// On each step, increment the Conductor as though the song was playing.
Conductor.instance.update(Conductor.instance.songPosition + elapsed * Constants.MS_PER_SEC);
}
}
@@ -1,238 +0,0 @@
package funkin.data;
import massive.munit.util.Timer;
import massive.munit.Assert;
import massive.munit.async.AsyncFactory;
import funkin.data.BaseRegistry;
import funkin.util.SortUtil;
import funkin.util.VersionUtil;
@:nullSafety
@:access(funkin.data.BaseRegistry)
class BaseRegistryTest extends FunkinTest
{
public function new()
{
super();
}
@BeforeClass
public function beforeClass()
{
FunkinAssert.initAssertTrace();
}
@AfterClass
public function afterClass() {}
@Before
public function setup() {}
@After
public function tearDown() {}
@Test
public function testMyTypeRegistry()
{
// This shouldn't crash.
MyTypeRegistry.instance.loadEntries();
// Ensure all entries were loaded.
var entryList = MyTypeRegistry.instance.listEntryIds();
entryList.sort(SortUtil.alphabetically);
Assert.areEqual(entryList, [
"blablabla",
"fizzbuzz",
"foobar",
// "junk"
]);
// Ensure this one is not in the list.
Assert.areEqual(entryList.indexOf("junk"), -1);
// Ensure blablabla got parsed correctly.
var blablabla = MyTypeRegistry.instance.fetchEntry("blablabla");
Assert.isNotNull(blablabla);
Assert.areEqual(blablabla.id, "blablabla");
Assert.areEqual(blablabla._data.version, "1.0.0");
Assert.areEqual(blablabla._data.name, "blablabla API");
}
}
typedef MyTypeData =
{
/**
* The version number of the data schema.
* When making changes to the note style data format, this should be incremented,
* and a migration function should be added to handle old versions.
*/
@:default(funkin.data.BaseRegistryTest.MyTypeRegistry.DATA_VERSION)
var version:String;
var id:String;
var name:String;
var data:Array<MySubTypeData>;
}
typedef MySubTypeData =
{
var foo:String;
var bar:String;
};
typedef MyTypeData_v0_1_x =
{
var version:String;
var id:Int;
var name:String;
};
class MyType implements IRegistryEntry<MyTypeData>
{
/**
* The ID of the mytype.
*/
public final id:String;
/**
* Mytype data as parsed from the JSON file.
*/
public final _data:MyTypeData;
/**
* @param id The ID of the JSON file to parse.
*/
public function new(id:String)
{
this.id = id;
_data = _fetchData(id);
if (_data == null)
{
throw 'Could not parse mytype data for id: $id';
}
}
public function destroy():Void {}
public function toString():String
{
return 'MyType($id)';
}
static function _fetchData(id:String):Null<MyTypeData>
{
return MyTypeRegistry.instance.parseEntryDataWithMigration(id, MyTypeRegistry.instance.fetchEntryVersion(id));
}
public function getSubData():Array<MySubTypeData>
{
return _data.data;
}
}
class MyTypeRegistry extends BaseRegistry<MyType, MyTypeData>
{
/**
* The current version string for the note style data format.
* Handle breaking changes by incrementing this value
* and adding migration to the `migrateMyTypeData()` function.
*/
public static final DATA_VERSION:String = "1.0.0";
public static final instance:MyTypeRegistry = new MyTypeRegistry();
public function new()
{
super('MYTYPE', 'mytype');
}
/**
* Read, parse, and validate the JSON data and produce the corresponding data object.
*/
public function parseEntryData(id:String):Null<MyTypeData>
{
// JsonParser does not take type parameters,
// otherwise this function would be in BaseRegistry.
var parser = new json2object.JsonParser<MyTypeData>();
parser.ignoreUnknownVariables = false;
switch (loadEntryFile(id))
{
case {fileName: fileName, contents: contents}:
parser.fromJson(contents, fileName);
default:
return null;
}
if (parser.errors.length > 0)
{
printErrors(parser.errors, id);
return null;
}
return parser.value;
}
/**
* Read, parse, and validate the JSON data and produce the corresponding data object.
*/
public function parseEntryData_v0_1_x(id:String):Null<MyTypeData>
{
// JsonParser does not take type parameters,
// otherwise this function would be in BaseRegistry.
var parser = new json2object.JsonParser<MyTypeData_v0_1_x>();
parser.ignoreUnknownVariables = false;
switch (loadEntryFile(id))
{
case {fileName: fileName, contents: contents}:
parser.fromJson(contents, fileName);
default:
return null;
}
if (parser.errors.length > 0)
{
printErrors(parser.errors, id);
return null;
}
var oldData:MyTypeData_v0_1_x = parser.value;
return migrateData_v0_1_x(oldData);
}
function migrateData_v0_1_x(input:MyTypeData_v0_1_x):MyTypeData
{
return {
version: DATA_VERSION,
id: '${input.id}',
name: input.name,
data: []
};
}
public override function parseEntryDataWithMigration(id:String, version:thx.semver.Version):Null<MyTypeData>
{
if (VersionUtil.validateVersion(version, "0.1.x"))
{
trace('Migrating mytype data from ${version} to ${DATA_VERSION}');
return parseEntryData_v0_1_x(id);
}
else
{
trace('Parsing mytype data with version ${version}');
return super.parseEntryDataWithMigration(id, version);
}
}
function createScriptedEntry(clsName:String):MyType
{
return null;
}
function getScriptedClassNames():Array<String>
{
return [];
}
}
@@ -1,148 +0,0 @@
package funkin.data.story.level;
import funkin.data.story.level.LevelRegistry;
import funkin.ui.story.Level;
import massive.munit.Assert;
import massive.munit.async.AsyncFactory;
import massive.munit.util.Timer;
@:nullSafety
@:access(funkin.ui.story.Level)
@:access(funkin.data.story.level.LevelRegistry)
class LevelRegistryTest extends FunkinTest
{
public function new()
{
super();
}
@BeforeClass
public function beforeClass():Void
{
LevelRegistry.instance.loadEntries();
}
@AfterClass
public function afterClass():Void {}
@Before
public function setup():Void {}
@After
public function tearDown():Void {}
@Test
public function testValid():Void
{
Assert.isNotNull(LevelRegistry.instance);
}
@Test
public function testParseEntryData():Void
{
var result:Null<LevelData> = LevelRegistry.instance.parseEntryData("test");
Assert.isNotNull(result);
Assert.areEqual("1.0.0", result.version);
Assert.areEqual("TEACHING TIME", result.name);
Assert.areEqual("storymenu/titles/tutorial", result.titleAsset);
Assert.areEqual(2, result.props.length);
Assert.areEqual("storymenu/props/gf", result.props[0].assetPath);
Assert.areEqual(1.0, result.props[0].scale);
Assert.areEqual(2, result.props[0].danceEvery);
Assert.areEqual([80, 80], result.props[0].offsets);
var anims = result.props[0].animations;
Assert.isNotNull(anims);
Assert.areEqual(2, anims.length);
var anim0 = anims[0];
Assert.isNotNull(anim0);
Assert.areEqual("danceLeft", anim0.name);
Assert.areEqual("idle0", anim0.prefix);
Assert.areEqual([30, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], anim0.frameIndices);
var anim1 = anims[1];
Assert.isNotNull(anim1);
Assert.areEqual("danceRight", anim1.name);
Assert.areEqual("idle0", anim1.prefix);
Assert.areEqual([15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], anim1.frameIndices);
Assert.areEqual("storymenu/props/bf", result.props[1].assetPath);
Assert.areEqual(1.0, result.props[1].scale);
Assert.areEqual(2, result.props[1].danceEvery);
Assert.areEqual([150, 80], result.props[1].offsets);
anims = result.props[1].animations;
Assert.isNotNull(anims);
Assert.areEqual(2, anims.length);
anim0 = anims[0];
Assert.isNotNull(anim0);
Assert.areEqual("idle", anim0.name);
Assert.areEqual("idle0", anim0.prefix);
Assert.areEqual(24, anim0.frameRate);
anim1 = anims[1];
Assert.isNotNull(anim1);
Assert.areEqual("confirm", anim1.name);
Assert.areEqual("confirm0", anim1.prefix);
Assert.areEqual(24, anim1.frameRate);
Assert.areEqual("#F9CF51", result.background);
Assert.areEqual(["tutorial"], result.songs);
}
@Test
public function testCreateEntry():Void
{
var result:Null<Level> = LevelRegistry.instance.createEntry("test");
Assert.isNotNull(result);
Assert.areEqual("Level(test)", result.toString());
Assert.areEqual("TEACHING TIME", result.getTitle());
Assert.areEqual(true, result.isUnlocked());
Assert.areEqual(true, result.isVisible());
}
@Test
public function testFetchEntry():Void
{
var result:Null<Level> = LevelRegistry.instance.fetchEntry("test");
Assert.isNotNull(result);
Assert.areEqual("Level(test)", result.toString());
Assert.areEqual("TEACHING TIME", result.getTitle());
Assert.areEqual(true, result.isUnlocked());
Assert.areEqual(true, result.isVisible());
}
@Test
public function testCreateEntryBlankPath():Void
{
// Using @:jcustomparse, `titleAsset` has a validation function that ensures it is not blank.
// This test makes sure that the validation function is being called, and that the error
// results in the level failing to parse.
FunkinAssert.validateThrows(function() {
var result:Null<Level> = LevelRegistry.instance.createEntry("blankpathtest");
}, function(err) {
return err == "Could not parse level data for id: blankpathtest";
});
}
@Test
public function testFetchBadEntry():Void
{
var result:Null<Level> = LevelRegistry.instance.fetchEntry("blablabla");
Assert.isNull(result);
var result2:Null<Level> = LevelRegistry.instance.fetchEntry("blankpathtest");
Assert.isNull(result2);
}
}
@@ -1,100 +0,0 @@
package funkin.data.notestyle;
import funkin.data.notestyle.NoteStyleRegistry;
import funkin.play.notes.notestyle.NoteStyle;
import massive.munit.Assert;
import massive.munit.async.AsyncFactory;
import massive.munit.util.Timer;
@:nullSafety
@:access(funkin.play.notes.notestyle.NoteStyle)
@:access(funkin.data.notestyle.NoteStyleRegistry)
class NoteStyleRegistryTest extends FunkinTest
{
public function new()
{
super();
}
@BeforeClass
public function beforeClass():Void
{
NoteStyleRegistry.instance.loadEntries();
}
@AfterClass
public function afterClass():Void {}
@Before
public function setup():Void {}
@After
public function tearDown():Void {}
@Test
public function testValid():Void
{
Assert.isNotNull(NoteStyleRegistry.instance);
}
@Test
public function testParseEntryData():Void
{
var result:Null<NoteStyleData> = NoteStyleRegistry.instance.parseEntryData("test2");
Assert.isNotNull(result);
Assert.areEqual(result.version, "1.0.0");
Assert.areEqual(result.name, "Test2");
Assert.areEqual(result.author, "Eric");
Assert.areEqual(result.fallback, "funkin");
Assert.isNotNull(result.assets);
var note:Null<NoteStyleData.NoteStyleAssetData<NoteStyleData.NoteStyleData_Note>> = result.assets.note;
Assert.isNotNull(note);
Assert.areEqual(note.assetPath, "shared:coolstuff");
Assert.areEqual(note.scale, 1.8);
Assert.areEqual(note.data.left.prefix, "noteLeft1");
Assert.areEqual(note.data.down.prefix, "noteDown3");
Assert.areEqual(note.data.up.prefix, "noteUp2");
Assert.areEqual(note.data.right.prefix, "noteRight4");
}
@Test
public function testFetchEntry():Void
{
var result:Null<NoteStyle> = NoteStyleRegistry.instance.fetchEntry("test2");
Assert.isNotNull(result);
Assert.areEqual(result.toString(), "NoteStyle(test2)");
Assert.areEqual(result.getName(), "Test2");
Assert.areEqual(result.getAuthor(), "Eric");
Assert.areEqual(result.getFallbackID(), "funkin");
}
@Test
public function testFetchBadEntry():Void
{
var result:Null<NoteStyle> = NoteStyleRegistry.instance.fetchEntry("blablabla");
Assert.isNull(result);
}
@Test
public function testFetchDefault():Void
{
var nsrMock = Mockatoo.mock(NoteStyleRegistry);
nsrMock.fetchDefault().callsRealMethod();
// Perform the call.
nsrMock.fetchDefault();
// Verify the underlying call.
nsrMock.fetchEntry(Constants.DEFAULT_NOTE_STYLE).verify(times(1));
}
}
@@ -1,133 +0,0 @@
package funkin.data.song;
import funkin.data.song.SongData;
import funkin.data.song.SongRegistry;
import funkin.play.song.Song;
import massive.munit.Assert;
import massive.munit.async.AsyncFactory;
import massive.munit.util.Timer;
@:nullSafety
@:access(funkin.play.song.Song)
@:access(funkin.data.song.SongRegistry)
class SongRegistryTest extends FunkinTest
{
public function new()
{
super();
}
@BeforeClass
public function beforeClass():Void
{
FunkinAssert.initAssertTrace();
SongRegistry.instance.loadEntries();
}
@AfterClass
public function afterClass():Void {}
@Before
public function setup():Void {}
@After
public function tearDown():Void {}
@Test
public function testValid():Void
{
Assert.isNotNull(SongRegistry.instance);
}
@Test
public function testParseMetadata():Void
{
var result:Null<SongData.SongMetadata> = SongRegistry.instance.parseEntryMetadata("bopeebo");
Assert.isNotNull(result);
var expectedVersion:thx.semver.Version = "2.0.0";
Assert.areEqual(expectedVersion, result.version);
Assert.areEqual("Bopeebo", result.songName);
Assert.areEqual("Kawai Sprite", result.artist);
Assert.areEqual(SongData.SongTimeFormat.MILLISECONDS, result.timeFormat);
Assert.areEqual("MasterEric (by hand)", result.generatedBy);
}
@Test
public function testParseChartData():Void
{
var result:Null<SongData.SongChartData> = SongRegistry.instance.parseEntryChartData("bopeebo");
Assert.isNotNull(result);
var expectedVersion:thx.semver.Version = "2.0.0";
Assert.areEqual(expectedVersion, result.version);
}
/**
* A test validating an error is thrown when attempting to parse chart data as metadata.
*/
@Test
public function testParseMetadataSwapped():Void
{
// Arrange
FunkinAssert.clearTraces();
// Act
var result:Null<SongData.SongMetadata> = SongRegistry.instance.parseEntryMetadata("bopeebo-swapped");
// Assert
Assert.isNull(result);
FunkinAssert.assertTrace("[SONG] Failed to parse entry data: bopeebo-swapped");
FunkinAssert.assertTrace(" Unknown variable \"scrollSpeed\"");
FunkinAssert.assertTrace(" at assets/data/songs/bopeebo-swapped/bopeebo-swapped-metadata.json:3");
FunkinAssert.assertTrace(" Unknown variable \"events\"");
FunkinAssert.assertTrace(" at assets/data/songs/bopeebo-swapped/bopeebo-swapped-metadata.json:7");
FunkinAssert.assertTrace(" Unknown variable \"notes\"");
FunkinAssert.assertTrace(" at assets/data/songs/bopeebo-swapped/bopeebo-swapped-metadata.json:185");
FunkinAssert.assertTrace(" Uninitialized variable \"songName\"");
FunkinAssert.assertTrace(" at assets/data/songs/bopeebo-swapped/bopeebo-swapped-metadata.json:1738");
FunkinAssert.assertTrace(" Uninitialized variable \"timeFormat\"");
FunkinAssert.assertTrace(" at assets/data/songs/bopeebo-swapped/bopeebo-swapped-metadata.json:1738");
FunkinAssert.assertTrace(" Uninitialized variable \"timeChanges\"");
FunkinAssert.assertTrace(" at assets/data/songs/bopeebo-swapped/bopeebo-swapped-metadata.json:1738");
FunkinAssert.assertTrace(" Uninitialized variable \"playData\"");
FunkinAssert.assertTrace(" at assets/data/songs/bopeebo-swapped/bopeebo-swapped-metadata.json:1738");
FunkinAssert.assertTrace(" Uninitialized variable \"artist\"");
FunkinAssert.assertTrace(" at assets/data/songs/bopeebo-swapped/bopeebo-swapped-metadata.json:1738");
}
/**
* A test validating an error is thrown when attempting to parse metadata as chart data.
*/
@Test
public function testParseChartDataSwapped():Void
{
// Arrange
FunkinAssert.clearTraces();
// Act
var result:Null<SongData.SongChartData> = SongRegistry.instance.parseEntryChartData("bopeebo-swapped");
// Assert
Assert.isNull(result);
FunkinAssert.assertTrace("[SONG] Failed to parse entry data: bopeebo-swapped");
FunkinAssert.assertTrace(" Unknown variable \"songName\"");
FunkinAssert.assertTrace(" at assets/data/songs/bopeebo-swapped/bopeebo-swapped-chart.json:3");
FunkinAssert.assertTrace(" Unknown variable \"artist\"");
FunkinAssert.assertTrace(" at assets/data/songs/bopeebo-swapped/bopeebo-swapped-chart.json:4");
FunkinAssert.assertTrace(" Unknown variable \"timeFormat\"");
FunkinAssert.assertTrace(" at assets/data/songs/bopeebo-swapped/bopeebo-swapped-chart.json:5");
FunkinAssert.assertTrace(" Unknown variable \"timeChanges\"");
FunkinAssert.assertTrace(" at assets/data/songs/bopeebo-swapped/bopeebo-swapped-chart.json:6");
FunkinAssert.assertTrace(" Unknown variable \"playData\"");
FunkinAssert.assertTrace(" at assets/data/songs/bopeebo-swapped/bopeebo-swapped-chart.json:7");
FunkinAssert.assertTrace(" Uninitialized variable \"notes\"");
FunkinAssert.assertTrace(" at assets/data/songs/bopeebo-swapped/bopeebo-swapped-chart.json:15");
FunkinAssert.assertTrace(" Uninitialized variable \"events\"");
FunkinAssert.assertTrace(" at assets/data/songs/bopeebo-swapped/bopeebo-swapped-chart.json:15");
FunkinAssert.assertTrace(" Uninitialized variable \"scrollSpeed\"");
FunkinAssert.assertTrace(" at assets/data/songs/bopeebo-swapped/bopeebo-swapped-chart.json:15");
}
}
@@ -1,209 +0,0 @@
package funkin.play.notes.notestyle;
import flixel.util.FlxSort;
import funkin.util.SortUtil;
import flixel.graphics.FlxGraphic;
import flixel.graphics.frames.FlxFrame;
import flixel.graphics.frames.FlxFramesCollection;
import massive.munit.util.Timer;
import massive.munit.Assert;
import massive.munit.async.AsyncFactory;
import funkin.data.notestyle.NoteStyleRegistry;
import funkin.play.notes.notestyle.NoteStyle;
import flixel.animation.FlxAnimationController;
import flixel.math.FlxPoint;
@:access(funkin.play.notes.notestyle.NoteStyle)
class NoteStyleTest extends FunkinTest
{
public function new()
{
super();
}
@BeforeClass
public function beforeClass()
{
NoteStyleRegistry.instance.loadEntries();
}
@AfterClass
public function afterClass() {}
@Before
public function setup() {}
@After
public function tearDown() {}
@Test
public function testBuildNoteSprite()
{
var target:Null<NoteStyle> = NoteStyleRegistry.instance.fetchEntry("funkin");
Assert.isNotNull(target);
// Arrange
var mockNoteSprite = Mockatoo.mock(NoteSprite);
var mockAnim = Mockatoo.mock(FlxAnimationController);
var scale = new FlxPoint(1, 1); // handle sprite.scale.x on the mock
mockNoteSprite.animation = mockAnim; // Tell the mock to forward calls to the animation controller mock.
mockNoteSprite.scale.returns(scale); // Redirect this final variable to a local variable.
mockNoteSprite.antialiasing.callsRealMethod(); // Tell the mock to treat this like a normal property.
mockNoteSprite.frames.callsRealMethod(); // Tell the mock to treat this like a normal property.
// Act
target.buildNoteSprite(mockNoteSprite);
var expectedGraphic:FlxGraphic = FlxG.bitmap.add("shared:assets/shared/images/arrows.png");
// Assert
Assert.isNotNull(mockNoteSprite.frames);
mockNoteSprite.frames.frames.sort(SortUtil.byFrameName);
var frameCount:Int = mockNoteSprite.frames.frames.length;
Assert.areEqual(24, frameCount);
// Validate each frame.
for (i in 0...frameCount)
{
var currentFrame:FlxFrame = mockNoteSprite.frames.frames[i];
switch (i)
{
case 0:
Assert.areEqual("confirmDown0001", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 1:
Assert.areEqual("confirmDown0002", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 2:
Assert.areEqual("confirmLeft0001", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 3:
Assert.areEqual("confirmLeft0002", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 4:
Assert.areEqual("confirmRight0001", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 5:
Assert.areEqual("confirmRight0002", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 6:
Assert.areEqual("confirmUp0001", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 7:
Assert.areEqual("confirmUp0002", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 8:
Assert.areEqual("noteDown0001", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 9:
Assert.areEqual("noteLeft0001", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 10:
Assert.areEqual("noteRight0001", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 11:
Assert.areEqual("noteUp0001", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 12:
Assert.areEqual("pressedDown0001", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 13:
Assert.areEqual("pressedDown0002", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 14:
Assert.areEqual("pressedLeft0001", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 15:
Assert.areEqual("pressedLeft0002", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 16:
Assert.areEqual("pressedRight0001", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 17:
Assert.areEqual("pressedRight0002", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 18:
Assert.areEqual("pressedUp0001", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 19:
Assert.areEqual("pressedUp0002", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 20:
Assert.areEqual("staticDown0001", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 21:
Assert.areEqual("staticLeft0001", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 22:
Assert.areEqual("staticRight0001", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
case 23:
Assert.areEqual("staticUp0001", currentFrame.name);
Assert.areEqual(expectedGraphic, currentFrame.parent);
default:
Assert.fail('Got unexpected frame number ${i}');
}
}
// Verify animations were applied.
@:privateAccess {
mockAnim.addByPrefix('purpleScroll', 'noteLeft', 24, false, false, false).verify(times(1));
mockAnim.addByPrefix('blueScroll', 'noteDown', 24, false, false, false).verify(times(1));
mockAnim.addByPrefix('greenScroll', 'noteUp', 24, false, false, false).verify(times(1));
mockAnim.addByPrefix('redScroll', 'noteRight', 24, false, false, false).verify(times(1));
mockAnim.destroyAnimations().verify(times(1));
mockAnim.set_frameIndex(0).verify(times(1));
// Verify there were no other functions called.
mockAnim.verifyZeroInteractions();
}
// Verify sprite was initialized.
@:privateAccess {
mockNoteSprite.set_graphic(expectedGraphic).verify(times(1));
mockNoteSprite.graphicLoaded().verify(times(1));
mockNoteSprite.set_antialiasing(true).verify(times(1));
mockNoteSprite.set_frames(mockNoteSprite.frames).verify(times(1));
mockNoteSprite.set_frame(mockNoteSprite.frames.frames[21]).verify(times(1));
mockNoteSprite.resetHelpers().verify(times(1));
Assert.areEqual(1, mockNoteSprite.scale.x);
Assert.areEqual(1, mockNoteSprite.scale.y);
// Verify there were no other functions called.
mockNoteSprite.verifyZeroInteractions();
}
}
@Test
public function testFallbackBehavior()
{
var target1:Null<NoteStyle> = NoteStyleRegistry.instance.fetchEntry("funkin");
var target2:Null<NoteStyle> = NoteStyleRegistry.instance.fetchEntry("test2");
Assert.isNotNull(target1);
Assert.isNotNull(target2);
Assert.areEqual("funkin", target1.id);
Assert.areEqual("test2", target2.id);
Assert.areEqual("Funkin'", target1.getName());
Assert.areEqual("Test2", target2.getName());
Assert.isNull(target1.getFallbackID());
Assert.areEqual(target1.id, target2.getFallbackID());
// Overridden fields are different.
Assert.areEqual("arrows", target1.getNoteAssetPath(false));
Assert.areEqual("coolstuff", target2.getNoteAssetPath(false));
Assert.areEqual("shared:arrows", target1.getNoteAssetPath(true));
Assert.areEqual("shared:coolstuff", target2.getNoteAssetPath(true));
// Unspecified fields use the fallback.
// Should NOT return null!
Assert.areEqual("assets/images/NOTE_hold_assets.png", target1.getHoldNoteAssetPath(false));
Assert.areEqual("assets/images/NOTE_hold_assets.png", target2.getHoldNoteAssetPath(false));
Assert.areEqual("NOTE_hold_assets", target1.getHoldNoteAssetPath(true));
}
}
@@ -1,138 +0,0 @@
package funkin.util;
import flixel.math.FlxPoint;
import massive.munit.util.Timer;
import massive.munit.Assert;
import massive.munit.async.AsyncFactory;
import funkin.util.BezierUtil;
@:nullSafety
@:access(funkin.util.BezierUtil)
class BezierUtilTest extends FunkinTest
{
public function new()
{
super();
}
@BeforeClass
public function beforeClass() {}
@AfterClass
public function afterClass() {}
@Before
public function setup() {}
@After
public function tearDown() {}
@Test
public function testBezier2()
{
var point1:FlxPoint = FlxPoint.get(1, 1);
var point2:FlxPoint = FlxPoint.get(2, 2);
var result:FlxPoint = BezierUtil.bezier2(0.5, point1, point2);
Assert.areEqual(result.x, 1.5);
Assert.areEqual(result.y, 1.5);
result = BezierUtil.bezier2(0.25, point1, point2);
Assert.areEqual(result.x, 1.25);
Assert.areEqual(result.y, 1.25);
result = BezierUtil.bezier2(0.75, point1, point2);
Assert.areEqual(result.x, 1.75);
Assert.areEqual(result.y, 1.75);
}
@Test
public function testBezier3()
{
var point1:FlxPoint = FlxPoint.get(1, 1);
var point2:FlxPoint = FlxPoint.get(2, 2);
var point3:FlxPoint = FlxPoint.get(3, 3);
var result:FlxPoint = BezierUtil.bezier3(0.5, point1, point2, point3);
Assert.areEqual(result.x, 2);
Assert.areEqual(result.y, 2);
result = BezierUtil.bezier3(0.25, point1, point2, point3);
Assert.areEqual(result.x, 1.5);
Assert.areEqual(result.y, 1.5);
result = BezierUtil.bezier3(0.75, point1, point2, point3);
Assert.areEqual(result.x, 2.5);
Assert.areEqual(result.y, 2.5);
result = BezierUtil.bezier3(0.5, point1, point2, point3);
Assert.areEqual(result.x, 2);
Assert.areEqual(result.y, 2);
result = BezierUtil.bezier3(0.6, point1, point2, point3);
Assert.areEqual(result.x, 2.2);
Assert.areEqual(result.y, 2.2);
}
@Test
public function testBezier4()
{
var point1:FlxPoint = FlxPoint.get(1, 1);
var point2:FlxPoint = FlxPoint.get(2, 2);
var point3:FlxPoint = FlxPoint.get(3, 3);
var point4:FlxPoint = FlxPoint.get(4, 4);
var result:FlxPoint = BezierUtil.bezier4(0.5, point1, point2, point3, point4);
Assert.areEqual(result.x, 2.5);
Assert.areEqual(result.y, 2.5);
result = BezierUtil.bezier4(0.25, point1, point2, point3, point4);
Assert.areEqual(result.x, 1.75);
Assert.areEqual(result.y, 1.75);
result = BezierUtil.bezier4(0.75, point1, point2, point3, point4);
Assert.areEqual(result.x, 3.25);
Assert.areEqual(result.y, 3.25);
}
@Test
public function testBezier5()
{
var point1:FlxPoint = FlxPoint.get(1, 1);
var point2:FlxPoint = FlxPoint.get(2, 2);
var point3:FlxPoint = FlxPoint.get(3, 3);
var point4:FlxPoint = FlxPoint.get(4, 4);
var point5:FlxPoint = FlxPoint.get(5, 5);
var result:FlxPoint = BezierUtil.bezier5(0.5, point1, point2, point3, point4, point5);
Assert.areEqual(result.x, 3);
Assert.areEqual(result.y, 3);
result = BezierUtil.bezier5(0.25, point1, point2, point3, point4, point5);
Assert.areEqual(result.x, 2);
Assert.areEqual(result.y, 2);
result = BezierUtil.bezier5(0.75, point1, point2, point3, point4, point5);
Assert.areEqual(result.x, 4);
Assert.areEqual(result.y, 4);
result = BezierUtil.bezier5(0.5, point1, point2, point3, point4, point5);
Assert.areEqual(result.x, 3);
Assert.areEqual(result.y, 3);
}
}
@@ -1,72 +0,0 @@
package funkin.util;
import massive.munit.util.Timer;
import massive.munit.Assert;
import massive.munit.async.AsyncFactory;
import funkin.util.ClipboardUtil;
@:nullSafety
@:access(funkin.util.ClipboardUtil)
class ClipboardUtilTest extends FunkinTest
{
public function new()
{
super();
}
@BeforeClass
public function beforeClass() {}
@AfterClass
public function afterClass() {}
@Before
public function setup() {}
@After
public function tearDown() {}
@Test
public function testGetSetClipboard()
{
var testString = "test string";
ClipboardUtil.setClipboard(testString);
var clipboardString = ClipboardUtil.getClipboard();
Assert.areEqual(testString, clipboardString);
}
@Ignore("This test doesn't work, Lime issue?")
@Test
public function testAddRemoveListener()
{
ClipboardUtil.addListener(onClipboardChange);
var testString = "test string";
ClipboardUtil.setClipboard(testString);
var clipboardString = ClipboardUtil.getClipboard();
Assert.areEqual(testString, clipboardString);
step();
// TODO: Fix issue where this test fails
Assert.areEqual(1, count);
ClipboardUtil.removeListener(onClipboardChange);
var testString2 = "test string 2";
ClipboardUtil.setClipboard(testString2);
var clipboardString2 = ClipboardUtil.getClipboard();
Assert.areEqual(testString2, clipboardString2);
Assert.areEqual(1, count);
}
var count:Int = 0;
function onClipboardChange()
{
count += 1;
}
}
@@ -1,36 +0,0 @@
package funkin.util;
import massive.munit.util.Timer;
import massive.munit.Assert;
import massive.munit.async.AsyncFactory;
import funkin.util.DateUtil;
@:nullSafety
@:access(funkin.util.DateUtil)
class DateUtilTest extends FunkinTest
{
public function new()
{
super();
}
@BeforeClass
public function beforeClass() {}
@AfterClass
public function afterClass() {}
@Before
public function setup() {}
@After
public function tearDown() {}
@Test
public function testGenerateTimestamp()
{
var date:Date = new Date(2020, 10 - 1, 31, 3, 0, 0);
var timestamp:String = DateUtil.generateTimestamp(date);
Assert.areEqual("2020-10-31-03-00-00", timestamp);
}
}
@@ -1,88 +0,0 @@
package funkin.util;
import haxe.io.Bytes;
import massive.munit.util.Timer;
import massive.munit.Assert;
import massive.munit.async.AsyncFactory;
import funkin.util.SerializerUtil;
typedef FooBar =
{
a:Int,
b:Int,
c:Int
};
@:nullSafety
@:access(funkin.util.SerializerUtil)
class SerializerUtilTest extends FunkinTest
{
public function new()
{
super();
}
@BeforeClass
public function beforeClass() {}
@AfterClass
public function afterClass() {}
@Before
public function setup() {}
@After
public function tearDown() {}
@Test
public function testToJSON()
{
var object = {a: 1, b: 2, c: 3};
var json = SerializerUtil.toJSON(object);
Assert.areEqual('{' + '\n\t"a": 1,' + '\n\t"b": 2,' + '\n\t"c": 3' + '\n}', json);
}
@Test
public function testFromJSON()
{
var json = '{' + '\n\t"a": 1,' + '\n\t"b": 2,' + '\n\t"c": 3' + '\n}';
var object = SerializerUtil.fromJSON(json);
Assert.areEqual(1, object.a);
Assert.areEqual(2, object.b);
Assert.areEqual(3, object.c);
}
@Test
public function testFromJSONBytes()
{
var json = '{' + '\n\t"a": 1,' + '\n\t"b": 2,' + '\n\t"c": 3' + '\n}';
var bytes = Bytes.ofString(json);
var object = SerializerUtil.fromJSONBytes(bytes);
Assert.areEqual(1, object.a);
Assert.areEqual(2, object.b);
Assert.areEqual(3, object.c);
}
@Test
public function testReplacer()
{
var version:thx.semver.Version = '1.0.0-beta';
Assert.areEqual(1, version.major);
Assert.areEqual(0, version.minor);
Assert.areEqual(0, version.patch);
Assert.areEqual(true, version.hasPre);
Assert.areEqual('beta', version.pre);
// Assert.areEqual(false, version.hasBuild);
Assert.areEqual('', version.build);
var formatted = SerializerUtil.replacer('version', version);
Assert.areEqual('1.0.0-beta', formatted);
var test2 = SerializerUtil.toJSON({version: version});
Assert.areEqual('{' + '\n\t"version": "1.0.0-beta"' + '\n}', test2);
}
}
@@ -1,64 +0,0 @@
package funkin.util;
import flixel.FlxObject;
import flixel.FlxSprite;
import flixel.util.FlxSort;
import funkin.data.song.SongData.SongNoteData;
import massive.munit.util.Timer;
import massive.munit.Assert;
import massive.munit.async.AsyncFactory;
import funkin.util.SortUtil;
@:nullSafety
@:access(funkin.util.SortUtil)
class SortUtilTest extends FunkinTest
{
public function new()
{
super();
}
@BeforeClass
public function beforeClass() {}
@AfterClass
public function afterClass() {}
@Before
public function setup() {}
@After
public function tearDown() {}
@Test
public function testAlphabetically()
{
var arr:Array<String> = ["b", "a", "c"];
arr.sort(SortUtil.alphabetically);
Assert.areEqual(["a", "b", "c"], arr);
}
@Test
public function testByZIndex()
{
var arr:Array<FlxObject> = [new FlxSprite(), new FlxObject(), new FlxSprite()];
arr[0].zIndex = 2000;
arr[1].zIndex = 1000;
arr[2].zIndex = 3000;
arr.sort(SortUtil.byZIndex.bind(FlxSort.ASCENDING));
Assert.areEqual(1000, arr[0].zIndex);
Assert.areEqual(2000, arr[1].zIndex);
Assert.areEqual(3000, arr[2].zIndex);
arr.sort(SortUtil.byZIndex.bind(FlxSort.DESCENDING));
Assert.areEqual(3000, arr[0].zIndex);
Assert.areEqual(2000, arr[1].zIndex);
Assert.areEqual(1000, arr[2].zIndex);
}
}
@@ -1,82 +0,0 @@
package funkin.util;
import massive.munit.util.Timer;
import massive.munit.Assert;
import massive.munit.async.AsyncFactory;
import funkin.util.VersionUtil;
@:access(funkin.util.VersionUtil)
class VersionUtilTest extends FunkinTest
{
public function new()
{
super();
}
@BeforeClass
public function beforeClass() {}
@AfterClass
public function afterClass() {}
@Before
public function setup() {}
@After
public function tearDown() {}
@Test
public function testValidateVersionStr()
{
Assert.areEqual(true, VersionUtil.validateVersionStr("1.0.0", "1.0.0"));
Assert.areEqual(false, VersionUtil.validateVersionStr("ehe", "test"));
}
@Test
public function testValidateVersion()
{
var version:thx.semver.Version = "1.0.0"; // implicit cast
var versionRule:thx.semver.VersionRule = "1.0.0"; // implicit cast
Assert.areEqual(true, VersionUtil.validateVersion(version, versionRule));
var versionRule2:thx.semver.VersionRule = ">=3.1.0"; // implicit cast
var version1:thx.semver.Version = "3.0.0";
var version2:thx.semver.Version = "3.1.1";
var version3:thx.semver.Version = "4.2.0";
Assert.areEqual(false, VersionUtil.validateVersion(version1, versionRule2));
Assert.areEqual(true, VersionUtil.validateVersion(version2, versionRule2));
Assert.areEqual(true, VersionUtil.validateVersion(version3, versionRule2));
}
@Test
public function testGetVersionFromJSON()
{
var jsonStr:String = "{ \"version\": \"3.1.0\" }";
var version:Null<thx.semver.Version> = VersionUtil.getVersionFromJSON(jsonStr);
Assert.isNotNull(version);
Assert.areEqual("3.1.0", version.toString());
}
@Test
public function testGetVersionFromJSONBad()
{
var jsonStr:String = "{ \"version\": \"bleh\" }";
Assert.throws(String, function() {
var version:Null<thx.semver.Version> = VersionUtil.getVersionFromJSON(jsonStr);
});
var jsonStr2:String = "{ \"blah\": \"3.1.0\" }";
var version2:Null<thx.semver.Version> = VersionUtil.getVersionFromJSON(jsonStr2);
Assert.isNull(version2);
}
}
@@ -1,42 +0,0 @@
package funkin.util.assets;
import massive.munit.util.Timer;
import massive.munit.Assert;
import massive.munit.async.AsyncFactory;
import funkin.util.assets.DataAssets;
@:nullSafety
@:access(funkin.util.assets.DataAssets)
class DataAssetsTest extends FunkinTest
{
public function new()
{
super();
}
@BeforeClass
public function beforeClass() {}
@AfterClass
public function afterClass() {}
@Before
public function setup() {}
@After
public function tearDown() {}
@Test
public function testBuildDataPath()
{
Assert.areEqual('assets/data/test.json', DataAssets.buildDataPath('test.json'));
}
@Test
public function listDataFilesInPath()
{
var expected = ['blablabla', 'test1', 'test2'];
Assert.areEqual(expected, DataAssets.listDataFilesInPath('test/'));
}
}
@@ -1,119 +0,0 @@
package funkin.util.assets;
import funkin.util.assets.FlxAnimationUtil;
import flixel.animation.FlxAnimationController;
import funkin.data.animation.AnimationData;
import massive.munit.util.Timer;
import massive.munit.Assert;
import massive.munit.async.AsyncFactory;
import funkin.util.DateUtil;
import flixel.FlxSprite;
@:nullSafety
@:access(funkin.util.assets.FlxAnimationUtil)
class FlxAnimationUtilTest extends FunkinTest
{
public function new()
{
super();
}
@BeforeClass
public function beforeClass() {}
@AfterClass
public function afterClass() {}
@Before
public function setup() {}
@After
public function tearDown() {}
@Test
public function testAddAtlasAnimation()
{
// Build a mock child class of FlxSprite
var mockSprite = Mockatoo.mock(FlxSprite);
var mockAnim = Mockatoo.mock(FlxAnimationController);
mockSprite.animation = mockAnim;
var animData:AnimationData =
{
name: "testAnim",
prefix: "blablabla"
};
FlxAnimationUtil.addAtlasAnimation(mockSprite, animData);
// Verify that the method was called once.
// If not, a VerificationException will be thrown and the test will fail.
mockAnim.addByPrefix("testAnim", "blablabla", 24, false, false, false).verify(times(1));
// Verify there were no other functions called.
mockAnim.verifyZeroInteractions();
mockSprite.verifyZeroInteractions();
var animData2:AnimationData =
{
name: "testAnim2",
prefix: "blablabla2",
frameIndices: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
frameRate: 12,
flipX: true,
flipY: true,
looped: true
};
FlxAnimationUtil.addAtlasAnimation(mockSprite, animData2);
try
{
mockAnim.addByIndices("testAnim2", "blablabla2", cast anyIterator, "", 12, true, true, true).verify(times(1));
}
catch (e)
{
trace('CAUGHT EXCEPTION');
trace(e);
}
mockAnim.verifyZeroInteractions();
mockSprite.verifyZeroInteractions();
}
@Test
public function testAddAtlasAnimations()
{
// Build a mock child class of FlxSprite
var mockSprite = Mockatoo.mock(FlxSprite);
var mockAnim = Mockatoo.mock(FlxAnimationController);
mockSprite.animation = mockAnim;
var animData:Array<AnimationData> = [
{
name: "testAnim",
prefix: "blablabla"
},
{
name: "testAnim2",
prefix: "blablabla2"
},
{
name: "testAnim3",
prefix: "blablabla3"
}
];
FlxAnimationUtil.addAtlasAnimations(mockSprite, animData);
// Verify that the method was called once.
// If not, a VerificationException will be thrown and the test will fail.
mockAnim.addByPrefix("testAnim", "blablabla", 24, false, false, false).verify(times(1));
mockAnim.addByPrefix("testAnim2", "blablabla2", 24, false, false, false).verify(times(1));
mockAnim.addByPrefix("testAnim3", "blablabla3", 24, false, false, false).verify(times(1));
// Verify there were no other functions called.
mockAnim.verifyZeroInteractions();
mockSprite.verifyZeroInteractions();
}
}
@@ -1,189 +0,0 @@
package funkin.util.tools;
import massive.munit.util.Timer;
import massive.munit.Assert;
import massive.munit.async.AsyncFactory;
import funkin.util.tools.ArrayTools;
@:nullSafety
@:access(funkin.util.tools.ArrayTools)
class ArraySortToolsTest extends FunkinTest
{
public function new()
{
super();
}
@BeforeClass
public function beforeClass() {}
@AfterClass
public function afterClass() {}
@Before
public function setup() {}
@After
public function tearDown() {}
@Test
public function testMergeSort()
{
var testArray:Array<Int> = [5, 4, 3, 2, 1];
function compare(a:Int, b:Int)
{
return a - b;
}
ArraySortTools.mergeSort(testArray, compare);
Assert.areEqual(testArray[0], 1);
Assert.areEqual(testArray[1], 2);
Assert.areEqual(testArray[2], 3);
Assert.areEqual(testArray[3], 4);
Assert.areEqual(testArray[4], 5);
var testArray2:Array<Int> = [9, 6, 3, 12];
ArraySortTools.mergeSort(testArray2, compare);
Assert.areEqual(testArray2[0], 3);
Assert.areEqual(testArray2[1], 6);
Assert.areEqual(testArray2[2], 9);
Assert.areEqual(testArray2[3], 12);
// Just make sure these don't crash.
ArraySortTools.mergeSort([], compare);
}
@Test
@:nullSafety(Off)
public function testMergeSortNull()
{
var testArray:Array<Int> = [5, 4, 3, 2, 1];
function compare(a:Int, b:Int)
{
return a - b;
}
// Just make sure these don't crash.
ArraySortTools.mergeSort(null, compare);
ArraySortTools.mergeSort([], null);
ArraySortTools.mergeSort(null, null);
// Make sure these throw an exception.
FunkinAssert.validateThrows(function() {
ArraySortTools.mergeSort(testArray, null);
}, function(err) {
return err == 'No comparison function provided.';
});
}
@Test
public function testQuickSort()
{
var testArray:Array<Int> = [5, 4, 3, 2, 1];
function compare(a:Int, b:Int)
{
return a - b;
}
ArraySortTools.quickSort(testArray, compare);
Assert.areEqual(testArray[0], 1);
Assert.areEqual(testArray[1], 2);
Assert.areEqual(testArray[2], 3);
Assert.areEqual(testArray[3], 4);
Assert.areEqual(testArray[4], 5);
var testArray2:Array<Int> = [9, 6, 3, 12];
ArraySortTools.quickSort(testArray2, compare);
Assert.areEqual(testArray2[0], 3);
Assert.areEqual(testArray2[1], 6);
Assert.areEqual(testArray2[2], 9);
Assert.areEqual(testArray2[3], 12);
}
@Test
@:nullSafety(Off)
public function testQuickSortNull()
{
var testArray:Array<Int> = [5, 4, 3, 2, 1];
function compare(a:Int, b:Int)
{
return a - b;
}
// Just make sure these don't crash.
ArraySortTools.quickSort([], compare);
ArraySortTools.quickSort(null, compare);
ArraySortTools.quickSort([], null);
ArraySortTools.quickSort(null, null);
// Make sure these throw an exception.
FunkinAssert.validateThrows(function() {
ArraySortTools.quickSort(testArray, null);
}, function(err) {
return err == 'No comparison function provided.';
});
}
@Test
public function testInsertionSort()
{
var testArray:Array<Int> = [5, 4, 3, 2, 1];
function compare(a:Int, b:Int)
{
return a - b;
}
ArraySortTools.insertionSort(testArray, compare);
Assert.areEqual(testArray[0], 1);
Assert.areEqual(testArray[1], 2);
Assert.areEqual(testArray[2], 3);
Assert.areEqual(testArray[3], 4);
Assert.areEqual(testArray[4], 5);
var testArray2:Array<Int> = [9, 6, 3, 12];
ArraySortTools.insertionSort(testArray2, compare);
Assert.areEqual(testArray2[0], 3);
Assert.areEqual(testArray2[1], 6);
Assert.areEqual(testArray2[2], 9);
Assert.areEqual(testArray2[3], 12);
}
@Test
@:nullSafety(Off)
public function testInsertionSortNull()
{
var testArray:Array<Int> = [5, 4, 3, 2, 1];
function compare(a:Int, b:Int)
{
return a - b;
}
// Just make sure these don't crash.
ArraySortTools.insertionSort([], compare);
ArraySortTools.insertionSort(null, compare);
ArraySortTools.insertionSort([], null);
ArraySortTools.insertionSort(null, null);
// Make sure these throw an exception.
FunkinAssert.validateThrows(function() {
ArraySortTools.insertionSort(testArray, null);
}, function(err) {
return err == 'No comparison function provided.';
});
}
}
@@ -1,66 +0,0 @@
package funkin.util.tools;
import massive.munit.util.Timer;
import massive.munit.Assert;
import massive.munit.async.AsyncFactory;
import funkin.util.tools.ArrayTools;
@:nullSafety
@:access(funkin.util.tools.ArrayTools)
class ArrayToolsTest extends FunkinTest
{
public function new()
{
super();
}
@BeforeClass
public function beforeClass() {}
@AfterClass
public function afterClass() {}
@Before
public function setup() {}
@After
public function tearDown() {}
@Test
public function testUnique()
{
var testArray:Array<Int> = [1, 2, 3, 4, 5, 6, 10, 7, 8, 9, 3, 4, 5, 6, 11, 7, 8];
var uniqueArray:Array<Int> = ArrayTools.unique(testArray);
Assert.areEqual(uniqueArray.length, 11);
// Array order doesn't change
Assert.areEqual(uniqueArray[0], 1);
Assert.areEqual(uniqueArray[1], 2);
Assert.areEqual(uniqueArray[2], 3);
Assert.areEqual(uniqueArray[3], 4);
Assert.areEqual(uniqueArray[4], 5);
Assert.areEqual(uniqueArray[5], 6);
Assert.areEqual(uniqueArray[6], 10);
Assert.areEqual(uniqueArray[7], 7);
Assert.areEqual(uniqueArray[8], 8);
Assert.areEqual(uniqueArray[9], 9);
Assert.areEqual(uniqueArray[10], 11);
}
@Test
public function testFind()
{
function predicate(a:String):Bool
{
return a.startsWith("Hello");
}
var testArray:Array<String> = ["Foo", "Bar", "HelloWorld", "Baz", "HelloTest"];
var result = ArrayTools.find(testArray, predicate);
Assert.areEqual(result, "HelloWorld");
}
}
@@ -1,60 +0,0 @@
package funkin.util.tools;
import massive.munit.util.Timer;
import massive.munit.Assert;
import massive.munit.async.AsyncFactory;
import funkin.util.tools.IteratorTools;
@:nullSafety
@:access(funkin.util.tools.IteratorTools)
class IteratorToolsTest extends FunkinTest
{
public function new()
{
super();
}
@BeforeClass
public function beforeClass() {}
@AfterClass
public function afterClass() {}
@Before
public function setup() {}
@After
public function tearDown() {}
@Test
public function testArray()
{
var iter = new MyStringIterator("HelloWorld");
var arr = IteratorTools.array(iter);
Assert.areEqual(["H", "e", "l", "l", "o", "W", "o", "r", "l", "d"], arr);
}
}
class MyStringIterator
{
var s:String;
var i:Int;
public function new(s:String)
{
this.s = s;
i = 0;
}
public function hasNext()
{
return i < s.length;
}
public function next()
{
return s.charAt(i++);
}
}
@@ -1,56 +0,0 @@
package funkin.util.tools;
import massive.munit.util.Timer;
import massive.munit.Assert;
import massive.munit.async.AsyncFactory;
import funkin.util.tools.MapTools;
@:nullSafety
@:access(funkin.util.tools.MapTools)
class MapToolsTest extends FunkinTest
{
public function new()
{
super();
}
@BeforeClass
public function beforeClass() {}
@AfterClass
public function afterClass() {}
@Before
public function setup() {}
@After
public function tearDown() {}
@Test
public function testSize()
{
var testMap:Map<String, String> = ["key1" => "value1", "key2" => "value2", "key3" => "value3"];
Assert.areEqual(3, MapTools.size(testMap));
}
@Test
public function testValues()
{
var testMap:Map<String, String> = ["key1" => "value1", "key2" => "value2", "key3" => "value3"];
var result:Array<String> = MapTools.values(testMap);
result.sort(SortUtil.alphabetically);
Assert.areEqual(["value1", "value2", "value3"], result);
}
@Test
public function testKeyValues()
{
var testMap:Map<String, String> = ["key1" => "value1", "key2" => "value2", "key3" => "value3"];
var result:Array<String> = MapTools.keyValues(testMap);
result.sort(SortUtil.alphabetically);
Assert.areEqual(["key1", "key2", "key3"], result);
}
}
@@ -1,60 +0,0 @@
package funkin.util.tools;
import massive.munit.util.Timer;
import massive.munit.Assert;
import massive.munit.async.AsyncFactory;
import funkin.util.tools.StringTools;
@:nullSafety
@:access(funkin.util.tools.StringTools)
class StringToolsTest extends FunkinTest
{
public function new()
{
super();
}
@BeforeClass
public function beforeClass() {}
@AfterClass
public function afterClass() {}
@Before
public function setup() {}
@After
public function tearDown() {}
@Test
public function testToTitleCase()
{
var input = "hello world";
Assert.areEqual("Hello World", StringTools.toTitleCase(input));
}
@Test
public function testToLowerKebabCase()
{
var input = "hello world";
Assert.areEqual("hello-world", StringTools.toLowerKebabCase(input));
}
@Test
public function testToUpperKebabCase()
{
var input = "hello world";
Assert.areEqual("HELLO-WORLD", StringTools.toUpperKebabCase(input));
}
@Test
public function testParseJSON()
{
var input = "{ \"hello\": \"world\" }";
Assert.areEqual({hello: "world"}, StringTools.parseJSON(input));
}
}
-21
View File
@@ -1,21 +0,0 @@
#if !macro
// Only import these when we aren't in a macro.
import funkin.util.Constants;
import funkin.Paths;
import flixel.FlxG; // This one in particular causes a compile error if you're using macros.
// These are great.
using Lambda;
using StringTools;
using funkin.util.tools.ArrayTools;
using funkin.util.tools.ArraySortTools;
using funkin.util.tools.IteratorTools;
using funkin.util.tools.MapTools;
using funkin.util.tools.StringTools;
#end
// Testing-specific
// Mocking
import mockatoo.Mockatoo.*;
using mockatoo.Mockatoo;
-3
View File
@@ -1,3 +0,0 @@
#!/bin/bash
haxe test-cpp.hxml
-3
View File
@@ -1,3 +0,0 @@
#!/bin/bash
haxe test-web.hxml
-3
View File
@@ -1,3 +0,0 @@
#!/bin/zsh
haxe test-cpp.hxml
-3
View File
@@ -1,3 +0,0 @@
#!/bin/zsh
haxe test-web.hxml
-3
View File
@@ -1,3 +0,0 @@
REM Launches the unit tests for the native target on Windows.
haxe test-cpp.hxml
-3
View File
@@ -1,3 +0,0 @@
REM Launches the unit tests for the native target on Windows.
haxe test-web.hxml
-6
View File
@@ -1,6 +0,0 @@
# Updates TestSuite.hx to include all tests
-cmd haxelib run munit gen
# Actually performs the tests
# Lime is used for compatibility reasons, and build flags in `project.xml` ensure coverage is enabled
-cmd haxelib run lime test cpp -debug
-5
View File
@@ -1,5 +0,0 @@
# Update the test runner classes
# TODO: This just opens the browser and doesn't do anything?
-cmd haxelib run munit gen
-cmd haxelib run lime build html5
-cmd haxelib run lime test html5
-32
View File
@@ -1,32 +0,0 @@
## CPP
--next
-main TestMain
-cpp build/cpp_test
# Funkin' deps
-lib lime
-lib openfl
-lib flixel
-lib flixel-addons
-lib flixel-ui
-lib hscript
-lib polymod
-lib haxeui-core
-lib haxeui-flixel
-lib flxanimate
-lib hxvlc
-lib thx.semver
-lib json2object
-lib tink_json
# Test deps
-lib munit
-lib hamcrest
-lib mcover
-lib mockatoo
# Class paths
-cp source
-cp ../../source
# Flixel macros
--remap flash:openfl
--macro flixel.system.macros.FlxDefines.run()
# Funkin' macros
--macro addMetadata('@:build(funkin.util.macro.FlxMacro.buildFlxBasic())', 'flixel.FlxBasic')
-60
View File
@@ -1,60 +0,0 @@
## CPP
--next
--verbose
--debug
-main TestMain
-cpp build/cpp_test
# Funkin' deps
-lib lime
-lib openfl
-lib flixel
-lib flixel-addons
-lib flixel-ui
-lib hscript
-lib polymod
-lib haxeui-core
-lib haxeui-flixel
-lib flxanimate
-lib hxvlc
-lib thx.semver
-lib json2object
-lib tink_json
# Test deps
-lib munit
-lib hamcrest
-lib mcover
-lib mockatoo
# Class paths
-cp source
-cp ../../source
# Flixel macros
--remap flash:openfl
--macro flixel.system.macros.FlxDefines.run()
# Funkin' macros
--macro addMetadata('@:build(funkin.util.macro.FlxMacro.buildFlxBasic())', 'flixel.FlxBasic')
## JavaScript HTML5
--next
-js build/js_test.js
# Funkin' deps
-lib lime
-lib openfl
-lib flixel
-lib flixel-addons
-lib hscript
-lib flixel-ui
-lib haxeui-core
-lib haxeui-flixel
-lib polymod
-lib flxanimate
-lib hxvlc
-lib thx.semver
-lib json2object
-lib tink_json
# Test deps
-lib munit
-lib hamcrest
# Class paths
-cp source
-cp ../../source