mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-23 08:07:54 -05:00
Merge remote-tracking branch 'origin/master' into bugfix/chart-editor-playbar-buttons
This commit is contained in:
commit
71e1fccce1
43 changed files with 623 additions and 153 deletions
8
.github/actions/setup-haxeshit/action.yml
vendored
8
.github/actions/setup-haxeshit/action.yml
vendored
|
@ -10,14 +10,6 @@ runs:
|
|||
run: |
|
||||
haxelib config
|
||||
shell: bash
|
||||
- name: Restore/create existing haxelib cache for faster downloads
|
||||
uses: actions/cache@v3
|
||||
id: cache-haxelib-windows
|
||||
with:
|
||||
# wha?
|
||||
key: cache-haxelib-${{ runner.os }}-${{ hashFiles('**/hmm.json')}}
|
||||
path: |
|
||||
.haxelib/
|
||||
- name: Installing Haxe lol
|
||||
run: |
|
||||
haxe -version
|
||||
|
|
23
.github/workflows/build-shit.yml
vendored
23
.github/workflows/build-shit.yml
vendored
|
@ -30,12 +30,12 @@ jobs:
|
|||
- name: Build game
|
||||
run: |
|
||||
sudo apt-get install -y libx11-dev xorg-dev libgl-dev libxi-dev libxext-dev libasound2-dev libxinerama-dev libxrandr-dev libgl1-mesa-dev
|
||||
haxelib run lime build html5 -debug --times
|
||||
haxelib run lime build html5 -release --times
|
||||
ls
|
||||
- uses: ./.github/actions/upload-itch
|
||||
with:
|
||||
butler-key: ${{ secrets.BUTLER_API_KEY}}
|
||||
build-dir: export/debug/html5/bin
|
||||
build-dir: export/release/html5/bin
|
||||
target: html5
|
||||
create-nightly-win:
|
||||
needs: check_date
|
||||
|
@ -51,10 +51,25 @@ jobs:
|
|||
- uses: ./.github/actions/setup-haxeshit
|
||||
- name: Build game
|
||||
run: |
|
||||
haxelib run lime build windows -debug -DNO_REDIRECT_ASSETS_FOLDER
|
||||
haxelib run lime build windows -release -DNO_REDIRECT_ASSETS_FOLDER
|
||||
dir
|
||||
- uses: ./.github/actions/upload-itch
|
||||
with:
|
||||
butler-key: ${{ secrets.BUTLER_API_KEY}}
|
||||
build-dir: export/debug/windows/bin
|
||||
build-dir: export/release/windows/bin
|
||||
target: win
|
||||
test-unit-win:
|
||||
needs: create-nightly-win
|
||||
runs-on: windows-latest
|
||||
permissions:
|
||||
contents: write
|
||||
actions: write
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- uses: ./.github/actions/setup-haxeshit
|
||||
- name: Run unit tests
|
||||
run: |
|
||||
cd ./tests/unit/
|
||||
./start-win-native.bat
|
||||
|
|
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
|
@ -6,6 +6,7 @@
|
|||
"vshaxe.hxcpp-debugger", // CPP debugging
|
||||
"openfl.lime-vscode-extension", // Lime integration
|
||||
"esbenp.prettier-vscode", // JSON formatting
|
||||
"redhat.vscode-xml" // XML formatting
|
||||
"redhat.vscode-xml", // XML formatting
|
||||
"ryanluker.vscode-coverage-gutters" // Highlight code coverage
|
||||
]
|
||||
}
|
||||
|
|
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
|
@ -117,5 +117,12 @@
|
|||
"args": ["-debug", "-watch"]
|
||||
}
|
||||
],
|
||||
"cmake.configureOnOpen": false
|
||||
"cmake.configureOnOpen": false,
|
||||
"coverage-gutters.coverageFileNames": [
|
||||
"lcov.info",
|
||||
"cov.xml",
|
||||
"coverage.xml",
|
||||
"jacoco.xml",
|
||||
"coverage.cobertura.xml"
|
||||
]
|
||||
}
|
||||
|
|
28
hmm.json
28
hmm.json
|
@ -18,13 +18,15 @@
|
|||
"name": "flixel-addons",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "f107166de3e830648e8fbf3da5526d4b94aa7dfc",
|
||||
"ref": "c8c41e26d463aaf2edc0582fb23b6e228235bd16",
|
||||
"url": "https://github.com/EliteMasterEric/flixel-addons"
|
||||
},
|
||||
{
|
||||
"name": "flixel-ui",
|
||||
"type": "haxelib",
|
||||
"version": "2.5.0"
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "719b4f10d94186ed55f6fef1b6618d32abec8c15",
|
||||
"url": "https://github.com/HaxeFlixel/flixel-ui"
|
||||
},
|
||||
{
|
||||
"name": "flxanimate",
|
||||
|
@ -57,6 +59,13 @@
|
|||
"ref": "be0b18553189a55fd42821026618a18615b070e3",
|
||||
"url": "https://github.com/haxeui/haxeui-flixel"
|
||||
},
|
||||
{
|
||||
"name": "hmm",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "d514d7786cabf18b90e60fcee38399fd44c2ddfb",
|
||||
"url": "https://github.com/andywhite37/hmm"
|
||||
},
|
||||
{
|
||||
"name": "hscript",
|
||||
"type": "haxelib",
|
||||
|
@ -93,7 +102,7 @@
|
|||
"name": "lime",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "558798adc5bf0e82d70fef589a59ce88892e0b5b",
|
||||
"ref": "f195121ebec688b417e38ab115185c8d93c349d3",
|
||||
"url": "https://github.com/EliteMasterEric/lime"
|
||||
},
|
||||
{
|
||||
|
@ -128,14 +137,14 @@
|
|||
"name": "openfl",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "1591a6c5f1f72e65d711f7e17e8055df41424d94",
|
||||
"ref": "d33d489a137ff8fdece4994cf1302f0b6334ed08",
|
||||
"url": "https://github.com/EliteMasterEric/openfl"
|
||||
},
|
||||
{
|
||||
"name": "polymod",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "4bcd614103469af79a320898b823d1df8a55c3de",
|
||||
"ref": "e8a07b81e3bc535238ad8649e38f5d43c46f1b65",
|
||||
"url": "https://github.com/larsiusprime/polymod"
|
||||
},
|
||||
{
|
||||
|
@ -147,13 +156,6 @@
|
|||
"name": "tink_json",
|
||||
"type": "haxelib",
|
||||
"version": "0.11.0"
|
||||
},
|
||||
{
|
||||
"name": "hmm",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "d514d7786cabf18b90e60fcee38399fd44c2ddfb",
|
||||
"url": "https://github.com/andywhite37/hmm"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package funkin;
|
||||
|
||||
import flixel.FlxState;
|
||||
import flixel.addons.transition.FlxTransitionableState;
|
||||
import flixel.addons.transition.FlxTransitionSprite.GraphicTransTileDiamond;
|
||||
import flixel.addons.transition.TransitionData;
|
||||
|
@ -33,8 +34,10 @@ import Discord.DiscordClient;
|
|||
* The initialization state has several functions:
|
||||
* - Calls code to set up the game, including loading saves and parsing game data.
|
||||
* - Chooses whether to start via debug or via launching normally.
|
||||
*
|
||||
* It should not contain any sprites or rendering.
|
||||
*/
|
||||
class InitState extends FlxTransitionableState
|
||||
class InitState extends FlxState
|
||||
{
|
||||
/**
|
||||
* Perform a bunch of game setup, then immediately transition to the title screen.
|
||||
|
|
|
@ -114,6 +114,7 @@ class PolymodHandler
|
|||
|
||||
// Parse hxc files and register the scripted classes in them.
|
||||
useScriptedClasses: true,
|
||||
loadScriptsAsync: #if html5 true #else false #end,
|
||||
});
|
||||
|
||||
if (loadedModList == null)
|
||||
|
|
|
@ -257,7 +257,7 @@ class ChartEditorDialogHandler
|
|||
* @param closable Whether the dialog can be closed by the user.
|
||||
* @return The dialog that was opened.
|
||||
*/
|
||||
@:haxe.warning("-WVarInit")
|
||||
@:haxe.warning("-WVarInit") // Hide the warning about the onDropFile handler.
|
||||
public static function openUploadInstDialog(state:ChartEditorState, closable:Bool = true):Dialog
|
||||
{
|
||||
var dialog:Dialog = openDialog(state, CHART_EDITOR_DIALOG_UPLOAD_INST_LAYOUT, true, closable);
|
||||
|
@ -833,6 +833,9 @@ class ChartEditorDialogHandler
|
|||
songChartDataVariation = SongValidator.validateSongChartData(songChartDataVariation, 'import');
|
||||
|
||||
songChartData.set(variation, songChartDataVariation);
|
||||
state.notePreviewDirty = true;
|
||||
state.notePreviewViewportBoundsDirty = true;
|
||||
state.noteDisplayDirty = true;
|
||||
|
||||
// Tell the user the load was successful.
|
||||
NotificationManager.instance.addNotification(
|
||||
|
@ -858,6 +861,9 @@ class ChartEditorDialogHandler
|
|||
songChartDataVariation = SongValidator.validateSongChartData(songChartDataVariation, 'import');
|
||||
|
||||
songChartData.set(variation, songChartDataVariation);
|
||||
state.notePreviewDirty = true;
|
||||
state.notePreviewViewportBoundsDirty = true;
|
||||
state.noteDisplayDirty = true;
|
||||
|
||||
// Tell the user the load was successful.
|
||||
NotificationManager.instance.addNotification(
|
||||
|
|
|
@ -132,6 +132,8 @@ class ChartEditorNoteSprite extends FlxSprite
|
|||
|
||||
public function updateNotePosition(?origin:FlxObject)
|
||||
{
|
||||
if (this.noteData == null) return;
|
||||
|
||||
var cursorColumn:Int = this.noteData.data;
|
||||
|
||||
if (cursorColumn < 0) cursorColumn = 0;
|
||||
|
|
|
@ -85,8 +85,8 @@ using Lambda;
|
|||
* @author MasterEric
|
||||
*/
|
||||
// Give other classes access to private instance fields
|
||||
// @:nullSafety(Loose) // Enable this while developing, then disable to keep unit tests functional!
|
||||
|
||||
@:nullSafety
|
||||
@:allow(funkin.ui.debug.charting.ChartEditorCommand)
|
||||
@:allow(funkin.ui.debug.charting.ChartEditorDialogHandler)
|
||||
@:allow(funkin.ui.debug.charting.ChartEditorThemeHandler)
|
||||
|
@ -569,7 +569,6 @@ class ChartEditorState extends HaxeUIState
|
|||
|
||||
/**
|
||||
* Whether the note preview graphic needs to be FULLY rebuilt.
|
||||
* The Bitmap can be modified by individual commands without using this.
|
||||
*/
|
||||
var notePreviewDirty:Bool = true;
|
||||
|
||||
|
@ -1317,7 +1316,7 @@ class ChartEditorState extends HaxeUIState
|
|||
healthIconBF = new HealthIcon(currentSongCharacterPlayer);
|
||||
healthIconBF.autoUpdate = false;
|
||||
healthIconBF.size.set(0.5, 0.5);
|
||||
healthIconBF.x = gridTiledSprite.x + GRID_SIZE * (STRUMLINE_SIZE * 2 + 1) + 15;
|
||||
healthIconBF.x = gridTiledSprite.x + gridTiledSprite.width + 15;
|
||||
healthIconBF.y = gridTiledSprite.y + 5;
|
||||
healthIconBF.flipX = true;
|
||||
add(healthIconBF);
|
||||
|
@ -1797,7 +1796,7 @@ class ChartEditorState extends HaxeUIState
|
|||
if (healthIconBF != null)
|
||||
{
|
||||
// Base X position to the right of the grid.
|
||||
var baseHealthIconXPos:Float = gridTiledSprite?.x ?? 0.0 + GRID_SIZE * (STRUMLINE_SIZE * 2 + 1) + 15;
|
||||
var baseHealthIconXPos:Float = (gridTiledSprite == null) ? (0) : (gridTiledSprite.x + gridTiledSprite.width + 15);
|
||||
// Will be 0 when not bopping. When bopping, will increase to push the icon left.
|
||||
var healthIconOffset:Float = healthIconBF.width - (HealthIcon.HEALTH_ICON_SIZE * 0.5);
|
||||
healthIconBF.x = baseHealthIconXPos - healthIconOffset;
|
||||
|
@ -2718,12 +2717,12 @@ class ChartEditorState extends HaxeUIState
|
|||
trace('Creating new Note... (${renderedNotes.members.length})');
|
||||
noteSprite.parentState = this;
|
||||
|
||||
// Setting note data resets position relative to the grid so we fix that.
|
||||
noteSprite.updateNotePosition(renderedNotes);
|
||||
|
||||
// The note sprite handles animation playback and positioning.
|
||||
noteSprite.noteData = noteData;
|
||||
|
||||
// Setting note data resets position relative to the grid so we fix that.
|
||||
noteSprite.updateNotePosition(renderedNotes);
|
||||
|
||||
// Add hold notes that are now visible (and not already displayed).
|
||||
if (noteSprite.noteData != null && noteSprite.noteData.length > 0 && displayedHoldNoteData.indexOf(noteSprite.noteData) == -1)
|
||||
{
|
||||
|
@ -3869,6 +3868,9 @@ class ChartEditorState extends HaxeUIState
|
|||
|
||||
scrollPositionInPixels = 0;
|
||||
playheadPositionInPixels = 0;
|
||||
notePreviewDirty = true;
|
||||
notePreviewViewportBoundsDirty = true;
|
||||
noteDisplayDirty = true;
|
||||
moveSongToScrollPosition();
|
||||
}
|
||||
|
||||
|
|
37
source/funkin/util/macro/InlineMacro.hx
Normal file
37
source/funkin/util/macro/InlineMacro.hx
Normal file
|
@ -0,0 +1,37 @@
|
|||
package funkin.util.macro;
|
||||
|
||||
#if macro
|
||||
using funkin.util.tools.ArrayTools;
|
||||
#end
|
||||
|
||||
/**
|
||||
* A macro to make fields inline.
|
||||
*/
|
||||
class InlineMacro
|
||||
{
|
||||
/**
|
||||
* For the given class, find the (static?) field with the given name and make it inline.
|
||||
* @param field
|
||||
* @param isStatic
|
||||
*/
|
||||
public static macro function makeInline(field:String, isStatic:Bool = false):Array<haxe.macro.Expr.Field>
|
||||
{
|
||||
var pos:haxe.macro.Expr.Position = haxe.macro.Context.currentPos();
|
||||
// The FlxBasic class. We can add new properties to this class.
|
||||
var cls:haxe.macro.Type.ClassType = haxe.macro.Context.getLocalClass().get();
|
||||
// The fields of the FlxClass.
|
||||
var fields:Array<haxe.macro.Expr.Field> = haxe.macro.Context.getBuildFields();
|
||||
|
||||
// Find the field with the given name.
|
||||
var targetField:Null<haxe.macro.Expr.Field> = fields.find(function(f) return f.name == field
|
||||
&& (MacroUtil.isFieldStatic(f) == isStatic));
|
||||
|
||||
// If the field was not found, throw an error.
|
||||
if (targetField == null) haxe.macro.Context.error("Field " + field + " not found in class " + cls.name, pos);
|
||||
|
||||
// Add the inline access modifier to the field.
|
||||
targetField.access.push(AInline);
|
||||
|
||||
return fields;
|
||||
}
|
||||
}
|
|
@ -99,6 +99,11 @@ class MacroUtil
|
|||
return null;
|
||||
}
|
||||
|
||||
public static function isFieldStatic(field:haxe.macro.Expr.Field):Bool
|
||||
{
|
||||
return field.access.contains(AStatic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a value to an equivalent macro expression.
|
||||
*/
|
||||
|
|
|
@ -48,3 +48,9 @@ There are two parameters:
|
|||
### `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
|
||||
|
|
47
tests/unit/assets/preload/data/levels/blankpathtest.json
Normal file
47
tests/unit/assets/preload/data/levels/blankpathtest.json
Normal file
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"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"]
|
||||
}
|
|
@ -37,6 +37,9 @@
|
|||
|
||||
<!-- 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" />
|
||||
|
@ -80,12 +83,22 @@
|
|||
<!-- Test defines -->
|
||||
<set name="no-custom-backend" />
|
||||
<set name="unit-test" />
|
||||
<!--<haxedef name="no-inline" />-->
|
||||
<haxedef name="FLX_UNIT_TEST" />
|
||||
<haxedef name="FLX_RECORD" />
|
||||
|
||||
<!-- Manually set up code coverage -->
|
||||
<!-- Clean up the output -->
|
||||
<haxedef name="no-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" />
|
||||
<haxeflag name="--macro" value="mcover.MCover.coverage(['funkin'],['../../source', 'source/'],[''])" />
|
||||
<haxedef name="safeMode"/>
|
||||
<haxedef name="HXCPP_CHECK_POINTER" />
|
||||
<haxedef name="HXCPP_STACK_LINE" />
|
||||
<haxedef name="HXCPP_STACK_TRACE" />
|
||||
</project>
|
||||
|
|
4
tests/unit/report-linux.sh
Normal file
4
tests/unit/report-linux.sh
Normal file
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
|
||||
cd ./report/
|
||||
genhtml -o ./html/ ./lcov.info
|
|
@ -10,6 +10,7 @@ using flixel.util.FlxArrayUtil;
|
|||
/**
|
||||
* @see https://github.com/HaxeFlixel/flixel/tree/dev/tests/unit
|
||||
*/
|
||||
@:nullSafety
|
||||
class FunkinAssert
|
||||
{
|
||||
/**
|
||||
|
@ -21,15 +22,17 @@ class FunkinAssert
|
|||
* @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
|
||||
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
|
||||
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)
|
||||
|
@ -45,33 +48,83 @@ class FunkinAssert
|
|||
return actual >= expected - margin && actual <= expected + margin;
|
||||
}
|
||||
|
||||
public static function arraysEqual<T>(expected:Array<T>, actual:Array<T>, ?info:PosInfos):Void
|
||||
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
|
||||
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)
|
||||
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)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ 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;
|
||||
|
@ -19,7 +20,7 @@ class FunkinTest
|
|||
static inline var TICKS_PER_FRAME:UInt = 25;
|
||||
static var totalSteps:UInt = 0;
|
||||
|
||||
var destroyable:IFlxDestroyable;
|
||||
var destroyable:Null<IFlxDestroyable> = null;
|
||||
|
||||
public function new() {}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import massive.munit.Assert;
|
|||
import massive.munit.async.AsyncFactory;
|
||||
import funkin.util.DateUtil;
|
||||
|
||||
@:nullSafety
|
||||
class MockTest extends FunkinTest
|
||||
{
|
||||
public function new()
|
||||
|
@ -45,16 +46,12 @@ class MockTest extends FunkinTest
|
|||
// If not, a VerificationException will be thrown and the test will fail.
|
||||
mockatoo.Mockatoo.verify(mockAnim.addByPrefix("testAnim", "blablabla", 24, false, false, false), times(1));
|
||||
|
||||
try
|
||||
{
|
||||
FunkinAssert.validateThrows(function() {
|
||||
// Attempt to verify the method was called.
|
||||
// This should FAIL, since we didn't call the method.
|
||||
mockatoo.Mockatoo.verify(mockAnim.addByIndices("testAnim", "blablabla", [], "", 24, false, false, false), times(1));
|
||||
Assert.fail("Mocking function should have thrown but didn't.");
|
||||
}
|
||||
catch (_:mockatoo.exception.VerificationException)
|
||||
{
|
||||
// Expected.
|
||||
}
|
||||
mockatoo.Mockatoo.verify(mockAnim.addByPrefix("testAnim", "blablabla", 24, false, false, false), times(1));
|
||||
}, function(err) {
|
||||
return Std.isOfType(err, mockatoo.exception.VerificationException);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,11 +6,14 @@ 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
|
||||
{
|
||||
/**
|
||||
|
@ -18,6 +21,8 @@ class TestMain
|
|||
*/
|
||||
static final INCLUDE_IGNORED_REPORT:Bool = false;
|
||||
|
||||
static final COVERAGE_FOLDER:String = "../../../report";
|
||||
|
||||
static function main()
|
||||
{
|
||||
new TestMain();
|
||||
|
@ -25,6 +30,10 @@ class 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));
|
||||
|
||||
|
@ -40,7 +49,9 @@ class TestMain
|
|||
var httpClient = new HTTPClient(new mcover.coverage.munit.client.MCoverSummaryReportClient());
|
||||
// NOTE: You can also create a custom ICoverageTestResultClient implementation
|
||||
|
||||
mcover.coverage.MCoverage.getLogger().addClient(new mcover.coverage.client.CodecovJsonPrintClient());
|
||||
// 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);
|
||||
|
@ -54,6 +65,12 @@ class TestMain
|
|||
runner.completionHandler = completionHandler;
|
||||
runner.run(suites);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
trace('UNCAUGHT EXCEPTION');
|
||||
trace(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* updates the background color and closes the current browser
|
||||
|
|
|
@ -7,10 +7,11 @@ import funkin.play.song.SongData.SongTimeChange;
|
|||
import funkin.util.Constants;
|
||||
import massive.munit.Assert;
|
||||
|
||||
@:nullSafety
|
||||
@:access(funkin.Conductor)
|
||||
class ConductorTest extends FunkinTest
|
||||
{
|
||||
var conductorState:ConductorState;
|
||||
var conductorState:Null<ConductorState> = null;
|
||||
|
||||
@Before
|
||||
function before()
|
||||
|
@ -54,6 +55,9 @@ class ConductorTest extends FunkinTest
|
|||
@Test
|
||||
function testUpdate():Void
|
||||
{
|
||||
var currentConductorState:Null<ConductorState> = conductorState;
|
||||
Assert.isNotNull(currentConductorState);
|
||||
|
||||
Assert.areEqual(0, Conductor.songPosition);
|
||||
|
||||
step(); // 1
|
||||
|
@ -72,15 +76,15 @@ class ConductorTest extends FunkinTest
|
|||
Assert.areEqual(0, Conductor.currentStep);
|
||||
FunkinAssert.areNear(8 / 9, Conductor.currentStepTime);
|
||||
|
||||
Assert.areEqual(0, conductorState.beatsHit);
|
||||
Assert.areEqual(0, conductorState.stepsHit);
|
||||
Assert.areEqual(0, currentConductorState.beatsHit);
|
||||
Assert.areEqual(0, currentConductorState.stepsHit);
|
||||
|
||||
step(); // 9
|
||||
|
||||
Assert.areEqual(0, conductorState.beatsHit);
|
||||
Assert.areEqual(1, conductorState.stepsHit);
|
||||
conductorState.beatsHit = 0;
|
||||
conductorState.stepsHit = 0;
|
||||
Assert.areEqual(0, currentConductorState.beatsHit);
|
||||
Assert.areEqual(1, currentConductorState.stepsHit);
|
||||
currentConductorState.beatsHit = 0;
|
||||
currentConductorState.stepsHit = 0;
|
||||
|
||||
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 9, Conductor.songPosition);
|
||||
Assert.areEqual(0, Conductor.currentBeat);
|
||||
|
@ -89,10 +93,10 @@ class ConductorTest extends FunkinTest
|
|||
|
||||
step(35 - 9); // 35
|
||||
|
||||
Assert.areEqual(0, conductorState.beatsHit);
|
||||
Assert.areEqual(2, conductorState.stepsHit);
|
||||
conductorState.beatsHit = 0;
|
||||
conductorState.stepsHit = 0;
|
||||
Assert.areEqual(0, currentConductorState.beatsHit);
|
||||
Assert.areEqual(2, currentConductorState.stepsHit);
|
||||
currentConductorState.beatsHit = 0;
|
||||
currentConductorState.stepsHit = 0;
|
||||
|
||||
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 35, Conductor.songPosition);
|
||||
Assert.areEqual(0, Conductor.currentBeat);
|
||||
|
@ -101,10 +105,10 @@ class ConductorTest extends FunkinTest
|
|||
|
||||
step(); // 36
|
||||
|
||||
Assert.areEqual(1, conductorState.beatsHit);
|
||||
Assert.areEqual(1, conductorState.stepsHit);
|
||||
conductorState.beatsHit = 0;
|
||||
conductorState.stepsHit = 0;
|
||||
Assert.areEqual(1, currentConductorState.beatsHit);
|
||||
Assert.areEqual(1, currentConductorState.stepsHit);
|
||||
currentConductorState.beatsHit = 0;
|
||||
currentConductorState.stepsHit = 0;
|
||||
|
||||
FunkinAssert.areNear(FunkinTest.MS_PER_STEP * 36, Conductor.songPosition);
|
||||
Assert.areEqual(1, Conductor.currentBeat);
|
||||
|
|
|
@ -7,6 +7,7 @@ import funkin.data.BaseRegistry;
|
|||
import funkin.util.SortUtil;
|
||||
import funkin.util.VersionUtil;
|
||||
|
||||
@:nullSafety
|
||||
@:access(funkin.data.BaseRegistry)
|
||||
class BaseRegistryTest extends FunkinTest
|
||||
{
|
||||
|
@ -49,6 +50,7 @@ class BaseRegistryTest extends FunkinTest
|
|||
|
||||
// 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");
|
||||
|
|
146
tests/unit/source/funkin/data/level/LevelRegistryTest.hx
Normal file
146
tests/unit/source/funkin/data/level/LevelRegistryTest.hx
Normal file
|
@ -0,0 +1,146 @@
|
|||
package funkin.data.level;
|
||||
|
||||
import funkin.data.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.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
|
||||
@Ignore("Requires redoing validation.")
|
||||
public function testCreateEntryBlankPath():Void
|
||||
{
|
||||
FunkinAssert.validateThrows(function() {
|
||||
var result:Null<Level> = LevelRegistry.instance.createEntry("blankpathtest");
|
||||
}, function(err) {
|
||||
return err == "Could not parse level data for id: blankpathtest";
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Requires redoing validation.")
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ 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
|
||||
|
@ -16,48 +17,57 @@ class NoteStyleRegistryTest extends FunkinTest
|
|||
}
|
||||
|
||||
@BeforeClass
|
||||
public function beforeClass()
|
||||
public function beforeClass():Void
|
||||
{
|
||||
NoteStyleRegistry.instance.loadEntries();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public function afterClass() {}
|
||||
public function afterClass():Void {}
|
||||
|
||||
@Before
|
||||
public function setup() {}
|
||||
public function setup():Void {}
|
||||
|
||||
@After
|
||||
public function tearDown() {}
|
||||
public function tearDown():Void {}
|
||||
|
||||
@Test
|
||||
public function testValid()
|
||||
public function testValid():Void
|
||||
{
|
||||
Assert.isNotNull(NoteStyleRegistry.instance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public function testParseEntryData()
|
||||
public function testParseEntryData():Void
|
||||
{
|
||||
var result:NoteStyleData = NoteStyleRegistry.instance.parseEntryData("test2");
|
||||
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.areEqual(result.assets.note.assetPath, "shared:coolstuff");
|
||||
Assert.areEqual(result.assets.note.scale, 1.8);
|
||||
Assert.areEqual(result.assets.note.data.left.prefix, "noteLeft1");
|
||||
Assert.areEqual(result.assets.note.data.down.prefix, "noteDown3");
|
||||
Assert.areEqual(result.assets.note.data.up.prefix, "noteUp2");
|
||||
Assert.areEqual(result.assets.note.data.right.prefix, "noteRight4");
|
||||
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()
|
||||
public function testFetchEntry():Void
|
||||
{
|
||||
var result:NoteStyle = NoteStyleRegistry.instance.fetchEntry("test2");
|
||||
var result:Null<NoteStyle> = NoteStyleRegistry.instance.fetchEntry("test2");
|
||||
|
||||
Assert.isNotNull(result);
|
||||
|
||||
Assert.areEqual(result.toString(), "NoteStyle(test2)");
|
||||
Assert.areEqual(result.getName(), "Test2");
|
||||
|
@ -66,15 +76,15 @@ class NoteStyleRegistryTest extends FunkinTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public function testFetchBadEntry()
|
||||
public function testFetchBadEntry():Void
|
||||
{
|
||||
var result:NoteStyle = NoteStyleRegistry.instance.fetchEntry("blablabla");
|
||||
var result:Null<NoteStyle> = NoteStyleRegistry.instance.fetchEntry("blablabla");
|
||||
|
||||
Assert.areEqual(result, null);
|
||||
Assert.isNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public function testFetchDefault()
|
||||
public function testFetchDefault():Void
|
||||
{
|
||||
var nsrMock:NoteStyleRegistry = mock(NoteStyleRegistry);
|
||||
|
||||
|
|
|
@ -34,7 +34,9 @@ class NoteStyleTest extends FunkinTest
|
|||
@Ignore("This test doesn't work, crashes when the project has 2 mocks of the same class???")
|
||||
public function testBuildNoteSprite()
|
||||
{
|
||||
var target:NoteStyle = NoteStyleRegistry.instance.fetchEntry("funkin");
|
||||
var target:Null<NoteStyle> = NoteStyleRegistry.instance.fetchEntry("funkin");
|
||||
|
||||
Assert.isNotNull(target);
|
||||
|
||||
var mockNoteSprite:NoteSprite = mock(NoteSprite);
|
||||
// var mockAnim = mock(FlxAnimationController);
|
||||
|
@ -48,8 +50,11 @@ class NoteStyleTest extends FunkinTest
|
|||
@Test
|
||||
public function testFallbackBehavior()
|
||||
{
|
||||
var target1:NoteStyle = NoteStyleRegistry.instance.fetchEntry("funkin");
|
||||
var target2:NoteStyle = NoteStyleRegistry.instance.fetchEntry("test2");
|
||||
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);
|
||||
|
@ -63,7 +68,6 @@ class NoteStyleTest extends FunkinTest
|
|||
// 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));
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import massive.munit.Assert;
|
|||
import massive.munit.async.AsyncFactory;
|
||||
import funkin.util.BezierUtil;
|
||||
|
||||
@:nullSafety
|
||||
@:access(funkin.util.BezierUtil)
|
||||
class BezierUtilTest extends FunkinTest
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@ import massive.munit.Assert;
|
|||
import massive.munit.async.AsyncFactory;
|
||||
import funkin.util.ClipboardUtil;
|
||||
|
||||
@:nullSafety
|
||||
@:access(funkin.util.ClipboardUtil)
|
||||
class ClipboardUtilTest extends FunkinTest
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@ import massive.munit.Assert;
|
|||
import massive.munit.async.AsyncFactory;
|
||||
import funkin.util.DateUtil;
|
||||
|
||||
@:nullSafety
|
||||
@:access(funkin.util.DateUtil)
|
||||
class DateUtilTest extends FunkinTest
|
||||
{
|
||||
|
|
|
@ -13,6 +13,7 @@ typedef FooBar =
|
|||
c:Int
|
||||
};
|
||||
|
||||
@:nullSafety
|
||||
@:access(funkin.util.SerializerUtil)
|
||||
class SerializerUtilTest extends FunkinTest
|
||||
{
|
||||
|
|
|
@ -9,6 +9,7 @@ import massive.munit.Assert;
|
|||
import massive.munit.async.AsyncFactory;
|
||||
import funkin.util.SortUtil;
|
||||
|
||||
@:nullSafety
|
||||
@:access(funkin.util.SortUtil)
|
||||
class SortUtilTest extends FunkinTest
|
||||
{
|
||||
|
|
|
@ -57,8 +57,26 @@ class VersionUtilTest extends FunkinTest
|
|||
{
|
||||
var jsonStr:String = "{ \"version\": \"3.1.0\" }";
|
||||
|
||||
var version:thx.semver.Version = VersionUtil.getVersionFromJSON(jsonStr);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import massive.munit.Assert;
|
|||
import massive.munit.async.AsyncFactory;
|
||||
import funkin.util.assets.DataAssets;
|
||||
|
||||
@:nullSafety
|
||||
@:access(funkin.util.assets.DataAssets)
|
||||
class DataAssetsTest extends FunkinTest
|
||||
{
|
||||
|
|
|
@ -9,6 +9,7 @@ import massive.munit.async.AsyncFactory;
|
|||
import funkin.util.DateUtil;
|
||||
import flixel.FlxSprite;
|
||||
|
||||
@:nullSafety
|
||||
@:access(funkin.util.assets.FlxAnimationUtil)
|
||||
class FlxAnimationUtilTest extends FunkinTest
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@ import massive.munit.Assert;
|
|||
import massive.munit.async.AsyncFactory;
|
||||
import funkin.util.tools.ArrayTools;
|
||||
|
||||
@:nullSafety
|
||||
@:access(funkin.util.tools.ArrayTools)
|
||||
class ArraySortToolsTest extends FunkinTest
|
||||
{
|
||||
|
@ -54,21 +55,30 @@ class ArraySortToolsTest extends FunkinTest
|
|||
|
||||
// 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.
|
||||
try
|
||||
{
|
||||
FunkinAssert.validateThrows(function() {
|
||||
ArraySortTools.mergeSort(testArray, null);
|
||||
|
||||
Assert.fail("Function should have thrown an exception.");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
Assert.areEqual("No comparison function provided.", e);
|
||||
}
|
||||
}, function(err) {
|
||||
return err == 'No comparison function provided.';
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -97,6 +107,18 @@ class ArraySortToolsTest extends FunkinTest
|
|||
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);
|
||||
|
@ -105,16 +127,11 @@ class ArraySortToolsTest extends FunkinTest
|
|||
ArraySortTools.quickSort(null, null);
|
||||
|
||||
// Make sure these throw an exception.
|
||||
try
|
||||
{
|
||||
FunkinAssert.validateThrows(function() {
|
||||
ArraySortTools.quickSort(testArray, null);
|
||||
|
||||
Assert.fail("Function should have thrown an exception.");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
Assert.areEqual("No comparison function provided.", e);
|
||||
}
|
||||
}, function(err) {
|
||||
return err == 'No comparison function provided.';
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -143,6 +160,18 @@ class ArraySortToolsTest extends FunkinTest
|
|||
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);
|
||||
|
@ -151,15 +180,10 @@ class ArraySortToolsTest extends FunkinTest
|
|||
ArraySortTools.insertionSort(null, null);
|
||||
|
||||
// Make sure these throw an exception.
|
||||
try
|
||||
{
|
||||
FunkinAssert.validateThrows(function() {
|
||||
ArraySortTools.insertionSort(testArray, null);
|
||||
|
||||
Assert.fail("Function should have thrown an exception.");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
Assert.areEqual("No comparison function provided.", e);
|
||||
}
|
||||
}, function(err) {
|
||||
return err == 'No comparison function provided.';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import massive.munit.Assert;
|
|||
import massive.munit.async.AsyncFactory;
|
||||
import funkin.util.tools.ArrayTools;
|
||||
|
||||
@:nullSafety
|
||||
@:access(funkin.util.tools.ArrayTools)
|
||||
class ArrayToolsTest extends FunkinTest
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@ import massive.munit.Assert;
|
|||
import massive.munit.async.AsyncFactory;
|
||||
import funkin.util.tools.IteratorTools;
|
||||
|
||||
@:nullSafety
|
||||
@:access(funkin.util.tools.IteratorTools)
|
||||
class IteratorToolsTest extends FunkinTest
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@ import massive.munit.Assert;
|
|||
import massive.munit.async.AsyncFactory;
|
||||
import funkin.util.tools.MapTools;
|
||||
|
||||
@:nullSafety
|
||||
@:access(funkin.util.tools.MapTools)
|
||||
class MapToolsTest extends FunkinTest
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@ import massive.munit.Assert;
|
|||
import massive.munit.async.AsyncFactory;
|
||||
import funkin.util.tools.StringTools;
|
||||
|
||||
@:nullSafety
|
||||
@:access(funkin.util.tools.StringTools)
|
||||
class StringToolsTest extends FunkinTest
|
||||
{
|
||||
|
|
3
tests/unit/start-linux-native.sh
Normal file
3
tests/unit/start-linux-native.sh
Normal file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
haxe test-cpp.hxml
|
3
tests/unit/start-linux-web.sh
Normal file
3
tests/unit/start-linux-web.sh
Normal file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
haxe test-web.hxml
|
3
tests/unit/start-win-web.bat
Normal file
3
tests/unit/start-win-web.bat
Normal file
|
@ -0,0 +1,3 @@
|
|||
REM Launches the unit tests for the native target on Windows.
|
||||
|
||||
haxe test-web.hxml
|
|
@ -1,11 +1,6 @@
|
|||
# Updates TestSuite.hx to include all tests
|
||||
#-cmd haxelib run munit gen
|
||||
# Actually performs the tests
|
||||
#-cmd haxelib run munit test -debug -coverage
|
||||
# -debug may or may not be needed
|
||||
# -coverage adds code coverage reporting
|
||||
|
||||
# Legacy style. Doesn't give detailed coverage reports,
|
||||
# but it works without crashing.
|
||||
-cmd haxelib run munit gen
|
||||
-cmd haxelib run lime test cpp
|
||||
# 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
|
||||
|
||||
|
|
|
@ -1,3 +1,39 @@
|
|||
## 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 hxCodec
|
||||
-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
|
||||
|
|
Loading…
Reference in a new issue