Monday, February 29, 2016

Note for Perl programmers using Haxe on compiler error "Float has no field MyVariableName"

You're missing a dot...instead of "for (i in 0..blah)" you want "for (i in 0...blah)" (three dots).  Also note that the latter number is excluded from the loop, unlike in Perl.

Tuesday, February 16, 2016

Code coverage coming along for FlxScrollableArea...which has a new release!

In fact, technically if we're just talking about FlxScrollableArea.hx, it's complete.  Thus, scrollable-area 0.0.2-alpha is out!  Just in time for the release of HaxeFlixel 4.0.0, which it's already compatible with.  (In fact, it wasn't compatible with any previous version, because I needed the dev branch for certain fixes.)

Unit testing paid off already, because I discovered two bugs while writing the tests.

What's incomplete is coverage and further testing of the scrollbars themselves, in particular a simulation of dragability.

Code Coverage Result: 81.29%

Missing Code Coverage: gimmicky.FlxScrollbar [61.45%]
 
Because FlxScrollbar has to update FlxScrollableArea as it goes, I've left it loosely coupled, but this means that to test the former to full coverage, I will need to mock and stub the latter.  Stay tuned for adventures with Mockatoo!  (Yeah, because blogs are tuned into.  Don't forget to jump up and down and hold your arms at funny angles to improve your reception.)

Buddy likes magic too! BDD FTW!

I was able to get tests going with a similar test.hxml for Buddy:

-main TestMain
-cp tests
-cp source
-cp C:/HaxeToolkit/haxe/lib/flixel/git
-D flixel=3.3.12
-cp C:/HaxeToolkit/haxe/lib/openfl/3,6,0
-D openfl=3.6.0
-cp C:/HaxeToolkit/haxe/lib/lime/2,9,0
-D lime=2.9.0
-cp C:/HaxeToolkit/haxe/lib/buddy/0,18,1
-D buddy=0.18.1
-cp C:/HaxeToolkit/haxe/lib/promhx/1,0,21/src/main
-D promhx=1.0.21
-cp C:\HaxeToolkit\haxe\lib\openfl/3,6,0/extern
--times
-D reporter=buddy.reporting.TraceReporter
-D native-trace
-D openfl-next
-D tools=2.9.0
-D flash-use-stage
-D no-compilation
-D openfl-flash
-D fdb-ci
-D web
--macro flixel.system.macros.FlxDefines.run()
-swf-lib export/flash/obj/assets.swf
-swf-version 11.8
-swf export/test/flash/bin/buddyhftest.swf
-swf-header 640:480:60:000000
-cp export/flash/haxe
-debug

All that was then needed was the same magic line, just in the new() of the Tests class.  And also a bit of trace redirection.  As ciscoheat says, enjoy your new Buddy!

Working coverage and unit testing, even autocompletion!

The key to getting munit and mcover working was in the test.hxml file.  This worked for me in the end:

## All targets

-main TestMain
-lib munit
-lib hamcrest
-cp C:/HaxeToolkit/haxe/lib/flixel/git
-D flixel=3.3.12
-cp C:/HaxeToolkit/haxe/lib/openfl/3,6,0
-D openfl=3.6.0
-cp C:/HaxeToolkit/haxe/lib/lime/2,9,0
-D lime=2.9.0
-cp C:/HaxeToolkit/haxe/lib/hscript/2,0,5
-D hscript=2.0.5
-cp C:\HaxeToolkit\haxe\lib\openfl/3,6,0/extern
-cp source
-cp test
-cp export/flash/haxe
--macro flixel.system.macros.FlxDefines.run()
--macro mcover.MCover.coverage([''],['source'])

--each

## Flash 9+

-swf-version 11.8
-swf export/test/flash/coveragetest.swf

#--next

## CPP

#-D HXCPP_M64
#-cpp export/test/cpp

A few notes:
  1. "--each" is great.  DRY: it applies to all subsequent targets.
  2. Despite "--each" being great, we're not really deriving full benefit from it at the moment, because CPP is commented out.  That's because I don't seem to be able to test on a CPP target.
  3. The magic line (see previous post) creating a FlxGame object in TestMain.hx is still required if you want to test anything that refers to FlxG, otherwise it won't exist. 
  4. The "-cp" lines I took from building a project that uses my library, then looking at the debug.hxml file generated in projectroot/export/flash/haxe.  Thanks to ciscoheat for inspiration in that regard.
(You may notice that ciscoheat is the developer behind Buddy, rather than munit.  I was also trying to set up Buddy to do BDD rather than TDD here.  Since I seem to have them both working now, I've decided that munit/mcover is a better fit for my library testing, while Buddy is a better fit for testing my actual game.  Although, code coverage would be nice there too, so maybe I'll use both, or something.)

That was great, but then I found out my earlier example of making a unit test:


haxelib run munit ct characterAIAimsAndFires -for Character

...was broken in a couple ways:

  1. Tests need to be named ending in "Test" (well, "Test.hx") otherwise they aren't picked up by "munit ct".  This isn't done automatically if you supply the wrong name on the command line like I did.
  2. They also need to start with an uppercase letter ("munit ct" also doesn't do this automatically.)
So, we instead just need this:

haxelib run munit ct CharacterAIAimsAndFiresTest -for Character

...and then everything's happy.  Almost.  The compiler is still barfing in the output pane whenever I type.  Turns out that this is just due to how autocomplete works, at least within FlashDevelop, because it looks for a Project.xml file to figure out which libraries and other source files to autocomplete from.  All I needed to do was create a (much simpler than normal) Project.xml in my project root:

<?xml version="1.0" encoding="utf-8"?>
<project>
 <!-- This file exists solely so that autocompletion works on FlashDevelop.  It's not intended to actually build the project. -->
 <!--Minimum without FLX_NO_GAMEPAD: 11.8, without FLX_NO_NATIVE_CURSOR: 11.2 -->
 <set name="SWF_VERSION" value="11.8" />
 <classpath name="source" />
 <haxelib name="flixel"/>
 <haxelib name="mcover"/>
</project>

...and then autocomplete worked like a champ for "Assert." and anything HaxeFlixel-related.

Now for the icing on the cake, I went to Project->Properties->Build and changed the pre-build command line to:

"$(CompilerPath)/haxelib" run munit t -coverage

And now I can run the test suite and get code coverage output simply by pressing F5.

So, the next challenges are:
  • cpp testing
  • android testing
  • does the magic FlxGame line work with Buddy too?
  • being able to check individual pixels in a cross-platform way would be a very solid way of testing scrollbars, IMHO
I hope this was helpful to somebody.  :)

Monday, February 15, 2016

A bit of progress

That issue with IBitmapDrawable...well, I didn't narrow down the exact line that was causing it, but an updated test.hxml file definitely helps (ignoring the cpp target problem, which this doesn't address, hence that target is commented out for now):

## All targets

-main TestMain
-lib munit
-lib hamcrest
-cp C:/HaxeToolkit/haxe/lib/flixel/git
-D flixel=3.3.12
-cp C:/HaxeToolkit/haxe/lib/openfl/3,6,0
-D openfl=3.6.0
-cp C:/HaxeToolkit/haxe/lib/lime/2,9,0
-D lime=2.9.0
-cp C:/HaxeToolkit/haxe/lib/hscript/2,0,5
-D hscript=2.0.5
-cp C:\HaxeToolkit\haxe\lib\openfl/3,6,0/extern
-cp source
-D native-trace
-cp test
-D openfl-next
-D tools=2.9.0
-D flash-use-stage
-D no-compilation
-D openfl-flash
-D fdb
-D web
-D noflxg
-cp export/flash/haxe
--macro flixel.system.macros.FlxDefines.run()
--macro mcover.MCover.coverage([''],['source'])

--each

## Flash 9+

-swf-version 11.8
-swf export/test/coveragetest.swf

#--next

## CPP

#-D HXCPP_M64
#-cpp export/cpp_test

With that, it actually compiles and runs, and the example test passes, with "haxelib run munit t."  Great!  Now, how about an actual test?  To be continued...

Unit testing scrollable-area

Seemed like a good idea to start with a library rather than my whole project.

So I made a new git branch locally, then ran "munit ct" as in an earlier post.  All good.

I'd like the library to work with html5, but it will probably not test properly in a JavaScript-only vacuum, so I think I will steal some code from openfl to try to get html5 testing to work.

Now I'm facing new trouble: even the as3 step in test.hxml (the first platform...) is not working with the default example:

...scrollable-area>haxelib run munit t
Massive Unit - Copyright 2016 Massive Interactive. Version 2.1.2
   haxe -main TestMain -lib munit -lib hamcrest -cp src -cp test -swf-version 11
 -cmd lime\ build\ html5 -swf build/as3_test.swf
HaxeWrapper.hx:73: 'lime\' is not recognized as an internal or external command,

HaxeWrapper.hx:73: operable program or batch file.
HaxeWrapper.hx:73: Error: Command failed with error 1
Error: Error compiling hxml for as3
Target as3 ...scrollable-area\build\as3_test.s
wf

So, where is it getting this "lime\" from?  It looks like, because test.hxml includes this line with spaces in it, that somewhere along the line the spaces get escaped, and then another place along the line, a command interpreter, the escaping doesn't seem to count and the system chokes on the backslash.

Hmm.  Well, it could just be because it's old code, which I hadn't at first noticed (openfl-validation is deprecated.)  The more recent version of openfl's test.hxml looks a bit different.  That's because they're making use of their own "haxelib run openfl" script.  Where does that come from?  Haxelib's docs say to look for a file named "run.n".  It's in openfl's repo root, but it's precompiled.  Looking at its changelog, it seems RunScript.hx was modified at the same time, so probably run.n comes from there.  But the source doesn't even mention a "build" parameter...so how can test.hxml be calling "haxelib run openfl build html5" or "haxelib run openfl build flash" successfully?

I guess the final line passes on the parameters to haxelib.  But haxelib doesn't have a "build" parameter either.  So I'm still not quite sure how this functions, exactly.

Making scrollable areas swipe-able in HaxeFlixel

So, this weekend I went to add some basic code to scrollable-area to make it more touch-friendly, because using 20px-thick scrollbars on an actual phone is a PITA. At least on what I endearingly term "my low-budget crap phone."

Anyway, I ran into a problem: FlxG.swipes reports *any* touch event as a swipe. This isn't a problem in and of itself, as it's useful for custom code. The problem is that, even a distance=0 swipe, which is clearly a tap by anyone's algorithm, shows up in FlxG.swipes. This means we must implement some custom code to distinguish between swipes and taps. This may not seem terribly complicated at first, but...well, for example, read this wonderful resource to get an idea of the situation.

The next part of the problem, which is a little bit more of a problem, is that basing an algorithm on pixels, rather than a real-world unit of measurement like centimetres, means that the algorithm will work vastly differently on a "retina" device versus an older-generation, lower-density budget device like mine.  If I calibrate to retina devices, what would be a 0.75 cm "tap" there could be a 2.25 cm "swipe" on my crap phone...and I wouldn't want a nearly inch-long gesture to necessarily be interpreted as a tap.

So we should know the DPI.  Is this possible in HaxeFlixel?  Sure, if you want to include custom code for each platform like this library does.  A possible workaround, we really just need to start overriding Android Java code, and more or less just exposing the results of this one call, I think.

And if we want something cleaner?  Thankfully, there's something in the pipe.  Because my game is not far enough along just yet that I'm testing a lot on phones, I will opt to wait.  Also because the Java override technique would mean scrollable-area would go from being a fairly straightforward include (even though you have to set up your content offscreen for it, at the moment) to something much more integrated.  So, hopefully by the time I'm ready for swipeyness, Lime will be too.  :)

Thursday, February 11, 2016

Writing an actual test...not yet.

First, I had to copy this very important line to TestMain.hx, and its requisite import lines.

Now, I'm curious if MUnit was tested with FlashDevelop, because I'm getting something strange regarding code completion.  If I type "Assert." (even in the example file, whose test passes; right below a line also beginning with "Assert.") and wait to see which methods I can use, I get the following in the Output pane:


Error: Could not process argument #--macro
Class name must start with uppercase character

It does not pop up a list of methods. I get the same error if I hit F4 over the token Assert, which is coloured blue to show it's correctly imported. Hmm...so, that's problem 1.  Update: I found this handy info from here:

There’s just one last thing required to properly get up and running writing tests: adding the munit library to the project so that you can get code-completion on munit’s API. Open application.xml and add the line <haxelib name="munit" /> to the classpath, haxe libs section so it looks like:

<!-- classpath, haxe libs -->
<source path="src" />
<haxelib name="openfl" />
<haxelib name="actuate" />
<haxelib name="munit" />

VoilĂ —for realsies!
Except that adding the "munit" line as above--to a default project.xml I had to create (with current templates I have yet to come across application.xml so I believe that's outdated and/or openfl-specific rather than haxeflixel-specific)--only changed the error whenever I try autocompletion to:

Invalid commandline class : test.ExampleTest should be ExampleTest
./test/ExampleTest.hx:3: characters 7-31 : Type not found : massive.munit.util.Timer

That's on the import line.  If I remove that, then it can't find the Timer class referenced in the example.  Back to the drawing board...well, hopefully not that far back.

Meanwhile, if I try to write a test anyway, my characterAIAimsAndFires class was apparently mal-named, despite following the naming convention in the help, because the compiler complains (via macros, while I type code for the test) that the file name ought not to start with a lowercase letter.  So now it's CharacterAIAimsAndFires.  In its setup(), I call FlxG.switchState() to get my main world set up--just for now, until I properly decouple some of my code, I suppose.

Just adding the above and trying to compile, I get an error about TestMain, that it can't find FlxG.  That's because test.hxml also needs some lines like these:

-lib flixel
-lib flixel-addons
-lib scrollable-area
-lib nape
-lib advanced-layout

...or at least the first one, in this case. But I thought since I'll be testing pretty broadly, I should include whatever I have included in my Project.xml via haxelib directives.

 Turns out that's not enough:

HaxeWrapper.hx:73: C:\HaxeToolkit\haxe\lib\openfl/3,6,0/openfl/display/IBitmapDrawable.hx:17: characters 8-66 : Type not found : RenderSession
Error: Error compiling hxml for as3

Now, even if I add "-lib openfl" and "-lib lime", I still get this.  So that's problem 2, which is significantly bigger than problem 1...

I see that IBitmapDrawable refers to RenderSession via the package openfl._internal.renderer, but its entire contents are conditionally compiled "#if (!display && !flash)".  I guess either display or flash is defined true when compiling with munit, but not normally.

Likewise if I target cpp instead of flash (which my game compiles to without trouble) in the test.hxml file, I get this:

HaxeWrapper.hx:73: C:\HaxeToolkit\haxe\lib\flixel/git/flixel/FlxGame.hx:3: characters 7-27 : You cannot access the flash package while targeting cpp (for flash.display.Bitmap)
HaxeWrapper.hx:73: test/unit/TestMain.hx:1: characters 7-21 :     referenced here
Error: Error compiling hxml for cpp


Welcome to the new blog

I decided to put development posts in their own blog.  Here.

Unit testing my HaxeFlixel-based code

Since I'm still in the prototyping stage, I won't say that I should have added unit testing to my project earlier, necessarily.  TDDers may argue otherwise.  So be it.

Anyhoo, it's time to see how well MUnit and a HaxeFlixel project will play together.  Pretty well, I'm assuming, since HF itself uses MUnit for its unit tests.

So how do we get set up?  As the docs say, we install it and run it with haxelib.

The help displayed when running it gave some additional hints:

Massive Unit - Copyright 2016 Massive Interactive. Version 2.1.2
Usage: munit [subcommand] [options]
Type 'help ' for help on a specific subcommand.

Available commands:
   gen (g) : Generate a test runner based on classes in a test src directory
   run (r) : Runs a single unit test target and generates results
   test (t) : Updates, compiles and runs all targets from an hxml file
   create (ct) : Create test class
   config (c) : Modify default project specific settings for munit
   report (re) : Generate reports for CI environments and 3rd party tools


So, what I needed to do next was CD to my project's root, then run it again with the config (c) option.  It asked me for a bunch of paths, which were different from the standard HF demo template I had started with.  The last three, templates and coverage related, I left as null.

After that, it was time to create a new test, using the ct option.  I have a Character class already made, so I ran this:

haxelib run munit ct characterAIAimsAndFires -for Character


It seems I didn't need to run the gen (g) option at this point, because it had already made the required files.  Time to run the tests, then, with the test (t) option.

Oops, it complains, "Error: Library hamcrest is not installed."  I did what it said and installed hamcrest using haxelib.  Not sure why that wasn't an auto-installed dependency.  Maybe it only applies to certain platforms.

Trying again, I got a new error: "Error: Error compiling hxml for as2."  To get past this, I had to customize the auto-generated test.hxml by chopping out the as2, neko, and other sections I don't need.  Then, success!  I got a result on the command line saying the whole as3 platform passed ("PLATFORMS TESTED: 1, PASSED: 1, FAILED: 0, ERRORS: 0, TIME: 1.839") and also a browser window saying the 2 individual tests within it passed ("PASSED  Tests: 2  Passed: 2  Failed: 0 Errors: 0 Ignored: 0 Time: 0.255.")

Now to write an actual test...