diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 15ecdb9..6d89b8a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,36 +1,75 @@ +# https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions name: CI on: push: + branches: + - master + paths-ignore: + - '**/*.md' + - '.vscode/*' pull_request: - workflow_dispatch: - repository_dispatch: - schedule: - - cron: '0 4 * * *' + # workflow_dispatch: + # repository_dispatch: + # schedule: + # - cron: '0 4 * * *' jobs: build: - # strategy: - # matrix: - # haxe-version: ["4.3.6"] - # fail-fast: false - # runs-on: ubuntu-latest - runs-on: macos-13 + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - macos-latest + - windows-latest + haxe: + # - latest TODO: fix tests/bare/src/Main.hx:78: Too many arguments - gAssert(5 < 3); + - 4.3.7 + steps: - # - run: sudo apt-get update - - - uses: actions/checkout@v4 - - - uses: krdlab/setup-haxe@v1 + - name: Show environment variables + shell: bash + run: env | sort + + - name: Git Checkout + uses: actions/checkout@v2 #https://github.com/actions/checkout + + # - name: "Cache Haxelib Repository" + # uses: actions/cache@v4 + # with: + # path: $RUNNER_TOOL_CACHE/haxe/${{ matrix.haxe }}/x64/lib + # key: ${{ runner.os }}-haxelib-${{ hashFiles('**/haxelib.json') }} + # restore-keys: | + # ${{ runner.os }}-haxelib- + + - name: Install Haxe ${{ matrix.haxe }} + uses: krdlab/setup-haxe@v2 # https://github.com/krdlab/setup-haxe with: - # haxe-version: ${{matrix.haxe-version}} - haxe-version: "4.3.4" - - - name: Set HAXEPATH + haxe-version: ${{ matrix.haxe }} + + - name: Install haxe libs + shell: bash + id: prerequisites run: | - echo "HAXEPATH=$HAXE_STD_PATH/.." >> $GITHUB_ENV + haxelib git utest https://github.com/haxe-utest/utest.git + + + ################################################## + # Tests + ################################################## - - name: Build test + - name: Build bare test + run: | + echo "Building bare test" + cd tests/bare/ + haxe test.hxml + cd ../../ + + - name: Build unit tests run: | - echo "Building test" - haxe -cp test/src -cp lib -D analyzer-optimize -main Main --interp \ No newline at end of file + echo "Building unit tests" + cd tests/unit/ + haxe test.hxml + cd ../../ \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1c4a6b5..5ece99b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /.DS_Store -export/ \ No newline at end of file +export/ +.unittest +dump/ \ No newline at end of file diff --git a/lib/debug/Assert.hx b/lib/debug/Assert.hx index 9a79f09..6e7bf86 100644 --- a/lib/debug/Assert.hx +++ b/lib/debug/Assert.hx @@ -258,7 +258,7 @@ class AssertRaw if (args.length == 2) return evalFinal(instance, args[0], args[1]); - throw "Invalid number of args"; + throw 'Invalid number of args, expecting (condition:Bool, ?msg:String):Void, got ${args}'; } static function evalFinal(instance:Expr, cond:ExprOf, ?msg:ExprOf):Expr diff --git a/lib/debug/Logger.hx b/lib/debug/Logger.hx index 39aedce..67d3f4f 100644 --- a/lib/debug/Logger.hx +++ b/lib/debug/Logger.hx @@ -177,6 +177,14 @@ private class LoggerRaw verbose = new LoggerPriority(this, VERBOSE); } + #if logger.unit_test + public function resetFromCompilerFlags() + { + logLevels.resetFromCompilerFlags(LOG, id); + throwLevels.resetFromCompilerFlags(THROW, id); + } + #end + public function destroy() { error.destroy(); @@ -272,7 +280,6 @@ abstract PriorityList(Array) from Array return this.copy(); } - public function setPriority(priority:Priority) { this.resize(0); @@ -314,6 +321,22 @@ abstract PriorityList(Array) from Array return value; } + function copyBase(arr:Array) + { + this.splice(0, this.length); + for (i in 0...arr.length) + this.push(arr[i]); + } + + #if logger.unit_test + public function resetFromCompilerFlags(type:LogType, id:String) + { + final newList = fromCompilerFlag(type, id, this); + if (newList != this) + copyBase(cast newList); + } + #end + static final arrReg = ~/^\[(.+)\]$/; /** @@ -493,12 +516,15 @@ enum abstract Priority(Int) } } -private class LoggerDefines +#if !logger.unit_test +private +#end +class LoggerDefines { /** * Every single compiler flag, and its value */ - #if (!display && !macro) + #if (!macro) public static final all:Map = getDefines(); #else public static final all:Map = []; diff --git a/lib/debug/LoggerPriority.hx b/lib/debug/LoggerPriority.hx index d337ffc..822b232 100644 --- a/lib/debug/LoggerPriority.hx +++ b/lib/debug/LoggerPriority.hx @@ -3,7 +3,7 @@ package debug; import debug.Logger; import haxe.PosInfos; -@:forward(enabled, throws, assert) +@:forward(enabled, throws, assert, level) abstract LoggerPriority(LoggerPriorityRaw) { public function new(parent, level) @@ -28,7 +28,7 @@ abstract LoggerPriority(LoggerPriorityRaw) private class LoggerPriorityRaw { var parent:Logger; - final level:Priority; + public final level:Priority; public var assert(default, null):Assert; diff --git a/test/src/Main.hx b/tests/bare/src/Main.hx similarity index 100% rename from test/src/Main.hx rename to tests/bare/src/Main.hx diff --git a/test/test.hxml b/tests/bare/test.hxml similarity index 81% rename from test/test.hxml rename to tests/bare/test.hxml index 989febc..3ed8162 100644 --- a/test/test.hxml +++ b/tests/bare/test.hxml @@ -1,9 +1,10 @@ --class-path src ---class-path ../lib/ +--class-path ../../lib/ --main Main -D main.log=warn -D alt.log=info -D main.sub.log=warn +-D dump-dependencies --dce full -D analyzer-optimize -D logger.verboseMacroErrors diff --git a/tests/unit/src/Main.hx b/tests/unit/src/Main.hx new file mode 100644 index 0000000..67a1a88 --- /dev/null +++ b/tests/unit/src/Main.hx @@ -0,0 +1,235 @@ +import debug.Logger; +import debug.LoggerPriority; +import utest.Assert as UAssert; + +class Main +{ + static public function main():Void + { + utest.UTest.run + ( [ new Test1() + ] + ); + trace("done"); + } +} +class Test1 extends Test +{ + var log1:Logger; + var log2:Logger; + + override function initLoggers() + { + super.initLoggers(); + + log1 = new Logger("test1", WARN, ERROR); + log2 = new Logger("test2", WARN, ERROR); + } + + function testDefaults() + { + // test global logger + UAssert.equals(true, Logger.log.verbose.enabled); + UAssert.equals(false, Logger.log.verbose.throws); + + UAssert.equals(true, Logger.log.info.enabled); + UAssert.equals(false, Logger.log.info.throws); + + UAssert.equals(true, Logger.log.warn.enabled); + UAssert.equals(false, Logger.log.warn.throws); + + UAssert.equals(true, Logger.log.error.enabled); + UAssert.equals(true, Logger.log.error.throws); + + // test category + UAssert.equals(false, log1.verbose.enabled); + UAssert.equals(false, log1.verbose.throws); + + UAssert.equals(false, log1.info.enabled); + UAssert.equals(false, log1.info.throws); + + UAssert.equals(true, log1.warn.enabled); + UAssert.equals(false, log1.warn.throws); + + UAssert.equals(true, log1.error.enabled); + UAssert.equals(true, log1.error.throws); + } + + function testPriorityFields() + { + function checkPriority(priority:LoggerPriority, id:String) + { + final testMsg = 'log succeeded'; + lastLog = null; + + priority.throws = false; + priority.enabled = true; + priority(testMsg); + UAssert.notEquals(null, lastLog, 'Expected $id.${priority.level} to not log'); + + lastLog = null; + + priority.enabled = false; + priority(testMsg); + UAssert.equals(null, lastLog, 'Expected $id.${priority.level} to log'); + + priority.throws = false; + priority.assert(false, testMsg); + UAssert.equals(null, lastLog, 'Expected $id.${priority.level}.assert to not log'); + + priority.throws = true; + try + { + priority.assert(false, testMsg); + UAssert.fail("Expected thrown exception"); + } + catch(e) + { + UAssert.pass(); + UAssert.equals(null, lastLog, 'Expected $id.${priority.level}.assert to not log'); + } + } + + checkPriority(log1.verbose, "log1"); + checkPriority(log1.info, "log1"); + checkPriority(log1.warn, "log1"); + checkPriority(log1.error, "log1"); + + // make sure context works with the lastLog system + final logContext = new Logger("test1[context]"); + checkPriority(logContext.verbose, "logContext"); + checkPriority(logContext.info, "logContext"); + checkPriority(logContext.warn, "logContext"); + checkPriority(logContext.error, "logContext"); + } + + function testFlags() + { + simulateCompileFlags + (" + -D log=info + -D test1.throw=none + -D test1.log=verbose + "); + + // test global logger + UAssert.equals(false, Logger.log.verbose.enabled); + UAssert.equals(true, Logger.log.info.enabled); + UAssert.equals(true, Logger.log.warn.enabled); + UAssert.equals(true, Logger.log.error.enabled); + UAssert.equals(false, Logger.log.verbose.throws); + UAssert.equals(false, Logger.log.info.throws); + UAssert.equals(false, Logger.log.warn.throws); + UAssert.equals(true, Logger.log.error.throws); + + // test category + UAssert.equals(true, log1.verbose.enabled); + UAssert.equals(true, log1.info.enabled); + UAssert.equals(true, log1.warn.enabled); + UAssert.equals(true, log1.error.enabled); + UAssert.equals(false, log1.verbose.throws); + UAssert.equals(false, log1.info.throws); + UAssert.equals(false, log1.warn.throws); + UAssert.equals(false, log1.error.throws); + + simulateCompileFlags + (" + -D log=info + -D test1.throw=none + "); + + // test global logger + UAssert.equals(false, Logger.log.verbose.enabled); + UAssert.equals(true, Logger.log.info.enabled); + UAssert.equals(true, Logger.log.warn.enabled); + UAssert.equals(true, Logger.log.error.enabled); + UAssert.equals(false, Logger.log.verbose.throws); + UAssert.equals(false, Logger.log.info.throws); + UAssert.equals(false, Logger.log.warn.throws); + UAssert.equals(true, Logger.log.error.throws); + + // test category + UAssert.equals(false, log1.verbose.enabled); + UAssert.equals(true, log1.info.enabled); + UAssert.equals(true, log1.warn.enabled); + UAssert.equals(true, log1.error.enabled); + UAssert.equals(false, log1.verbose.throws); + UAssert.equals(false, log1.info.throws); + UAssert.equals(false, log1.warn.throws); + UAssert.equals(false, log1.error.throws); + + // specifically test defaults again + simulateCompileFlags(""); + testDefaults(); + } + + function testReuse() + { + UAssert.equals(log1, new Logger("test1")); + } + + function testSub() + { + simulateCompileFlags + (" + -D throw=none + -D test1.log=warn + -D test2.log=info + -D c.log=verbose + -D test1.c.log=none + -D b.log=none + "); + + final logA1 = log1.sub("a"); + final logB1 = log1.sub("b"); + final logC1 = log1.sub("c"); + + final logA2 = log2.sub("a"); + final logB2 = log2.sub("b"); + final logC2 = log2.sub("c"); + + // -D test1.log=warn + UAssert.equals(false, log1.verbose.enabled); + UAssert.equals(false, log1.info.enabled); + UAssert.equals(true , log1.warn.enabled); + UAssert.equals(true , log1.error.enabled); + // -D test2.log=info + UAssert.equals(false, log2.verbose.enabled); + UAssert.equals(true , log2.info.enabled); + UAssert.equals(true , log2.warn.enabled); + UAssert.equals(true , log2.error.enabled); + + // -D test1.log=warn (matches parent) + UAssert.equals(false, logA1.verbose.enabled); + UAssert.equals(false, logA1.info.enabled); + UAssert.equals(true , logA1.warn.enabled); + UAssert.equals(true , logA1.error.enabled); + // -D test2.log=info (matches parent) + UAssert.equals(false, logA2.verbose.enabled); + UAssert.equals(true , logA2.info.enabled); + UAssert.equals(true , logA2.warn.enabled); + UAssert.equals(true , logA2.error.enabled); + + // -D b.log=none + UAssert.equals(false, logB1.verbose.enabled); + UAssert.equals(false, logB1.info.enabled); + UAssert.equals(false, logB1.warn.enabled); + UAssert.equals(false, logB1.error.enabled); + // -D b.log=none + UAssert.equals(false, logB2.verbose.enabled); + UAssert.equals(false, logB2.info.enabled); + UAssert.equals(false, logB2.warn.enabled); + UAssert.equals(false, logB2.error.enabled); + + // -D test1.c.log=none + UAssert.equals(false, logC1.verbose.enabled); + UAssert.equals(false, logC1.info.enabled); + UAssert.equals(false, logC1.warn.enabled); + UAssert.equals(false, logC1.error.enabled); + // -D c.log=verbose + UAssert.equals(true , logC2.verbose.enabled); + UAssert.equals(true , logC2.info.enabled); + UAssert.equals(true , logC2.warn.enabled); + UAssert.equals(true , logC2.error.enabled); + } +} \ No newline at end of file diff --git a/tests/unit/src/Test.hx b/tests/unit/src/Test.hx new file mode 100644 index 0000000..1d21b88 --- /dev/null +++ b/tests/unit/src/Test.hx @@ -0,0 +1,51 @@ +import debug.Logger; +import haxe.PosInfos; +import utest.Assert as UAssert; + +typedef Log = { id:String, priority:String, msg:String, pos:PosInfos }; + +abstract class Test extends utest.Test +{ + var lastLog:Log; + + final reg = ~/(.+?)(?:\[([^\]\[]+)\])?: (.*)/; + public function setup() + { + simulateCompileFlags(""); + + Logger.globalLog = function (msg, ?pos) + { + if (reg.match(msg)) + { + lastLog = { id: reg.matched(1), priority: reg.matched(2), msg: reg.matched(3), pos:pos }; + } + else + { + throw 'Unable to process log: $msg'; + } + } + lastLog = null; + } + + final flagReg = ~/\s*-D\s+(.+?)\s*=\s*(.+)\s*/; + function simulateCompileFlags(str:String) + { + @:privateAccess Logger.list.clear(); + @:privateAccess PriorityList.flagsByID.clear(); + + final all = LoggerDefines.all; + all.clear(); + for (line in str.split("\n")) + { + if (flagReg.match(line)) + all.set(flagReg.matched(1), flagReg.matched(2)); + } + + Logger.log.setPriority(VERBOSE); + Logger.log.setThrowPriority(ERROR); + Logger.log.resetFromCompilerFlags(); + initLoggers(); + } + + function initLoggers() {} +} \ No newline at end of file diff --git a/tests/unit/test.hxml b/tests/unit/test.hxml new file mode 100644 index 0000000..4e9586d --- /dev/null +++ b/tests/unit/test.hxml @@ -0,0 +1,6 @@ +--class-path src +--class-path ../../lib/ +--library utest +-D logger.unit_test +--main Main +--interp \ No newline at end of file