Monday, December 31, 2012

Dart Reflection

‹prev | My Chain | next›

I know that the Dart reflection system is under heavy development and will likely change sometime early in the new year. Still, it seems far enough along that it is worth getting somewhat familiar with it.

Since it is likely to change, I will explore this library with some unit tests that can tell me when things change. I start with a simple unit test skeleton that also include my yummy Cookie class for use in exploration:
import 'dart:mirrors';
import 'package:unittest/unittest.dart';

class Cookie {
  int number_of_chips;
  Cookie({this.number_of_chips:0});
}

main() {
  group('[reflection]', (){
    // tests will go here...
  });
}
I start by using the dart:mirrors' top-level method reflect() to grab a instance mirror of my cookie class:
  group('[reflection]', (){
    InstanceMirror im;
    setUp((){
      im = reflect(new Cookie(number_of_chips: 42));
    });
  });
At this point, I have reflected on an instance of the Cookie class, which gives me a mirror with which to probe the instance. My first attempt at probing uses the getField method from InstanceMirror to see if I can grab the number of chips from the original instance:
    setUp((){
      im = reflect(new Cookie(number_of_chips: 42));
    });

    test('getField', (){
      expect(im.getField('number_of_chips'), equals(42));
    });
That fails, telling me that instead of the expected value of 42, I get a Future instead:
FAIL: [reflection] getField
  Expected: <42>
       but: was <Instance of '_FutureImpl@0x36924d72'>.
That seems useful to note for the future, so I make a test to ensure that getField continues to return a Future:
    test('getField returns a future', (){
      var type = im.getField('number_of_chips').runtimeType;
      expect(type.toString(), contains('Future'));
    });
To extract the actual value out, I need to supply a then() function for the Future to invoke when it completes its thing:
    test('getField can find the original value', (){
      im.getField('number_of_chips').then((v){
        expect(v.reflectee, equals(42));
      });
    });
With that, I have two passing tests:
➜  classes git:(master) ✗ dart reflection.dart
unittest-suite-wait-for-done
PASS: [reflection] getField returns a future
PASS: [reflection] getField can find the original value

All 2 tests passed. 
There is not much else to InstanceMirror aside from the relfectee property. Were I sending mirrors across isolates, I would expect some limitation in what I can do. Since I am writing my tests all in the same isolate, I should be able to access a Cookie instance directly from the reflectee property:
    test('reflectee in same isolate', (){
      expect(im.hasReflectee, isTrue);
      expect(im.reflectee.number_of_chips, equals(42));
    });
And indeed that works:
➜  classes git:(master) ✗ dart reflection.dart
unittest-suite-wait-for-done
PASS: [reflection] getField returns a future
PASS: [reflection] getField can find the original value
PASS: [reflection] reflectee in same isolate

All 3 tests passed.
I would expect that the InstanceMirror's reflectee refers to the same object as the original rather than to a clone of the original. To be sure, I write a test, which requires a slight modification of the set() code:
    InstanceMirror im;
    Cookie cookie;
    setUp((){
      cookie = new Cookie(number_of_chips: 42);
      im = reflect(cookie);
    });

    test('reflectee refers to the same object as the original', (){
      expect(identical(cookie, im.reflectee), isTrue);
    });
And it turns out that reflectees do point to the original instance:
➜  classes git:(master) ✗ dart reflection.dart
unittest-suite-wait-for-done
PASS: [reflection] getField returns a future
PASS: [reflection] getField can find the original value
PASS: [reflection] reflectee in same isolate
PASS: [reflection] reflectee refers to the same object as the original

All 4 tests passed.
Aside from invoke(), which seems to be identical to getField except for methods instead of getters, that looks to be the extent of InstanceMirror. Before calling it a night, I take a quick look at ClassMirror. I can get a ClassMirror instance from the type property of my instance mirror.

This lets me reflect on various aspects of the class, including the methods:
    test('list instance methods', (){
      var cm = im.type,
          methods = cm.methods;
      expect(methods, equals({}));
    });

    test('list instance getters', (){
      var cm = im.type,
          getters = cm.getters;
      expect(getters, equals({}));
    });

    test('list instance members', (){
      var cm = im.type,
          members = cm.members;
      expect(members.values.map((v)=>v.simpleName), equals(['number_of_chips']));
    });
Since there are no getters or methods in my Cookie class, I expect the class mirror to contain an empty map. There is the number_of_chips property, which I am able to extract from the mirror with the members property. With that, I have a fairly respectable start on understanding the current state of Dart mirrors:
➜  classes git:(master) ✗ dart reflection.dart
unittest-suite-wait-for-done
PASS: [reflection] getField returns a future
PASS: [reflection] getField can find the original value
PASS: [reflection] reflectee in same isolate
PASS: [reflection] reflectee refers to the same object as the original
PASS: [reflection] list instance methods
PASS: [reflection] list instance getters
PASS: [reflection] list instance members

All 7 tests passed.
I will probably leave it at that for now, since mirrors in Dart are not baked yet:
➜  classes git:(master) ✗ dart_analyzer reflection.dart 
file:/home/chris/repos/csdart/Book/code/classes/reflection.dart:3:1: dart:mirrors is not fully implemented yet
     2: 
     3: import 'dart:mirrors';
        ~~~~~~~~~~~~~~~~~~~~~~
I do look forward to more on this front. It seems like quite a bit of ceremony—especially coming from a Ruby/JavaScript background. Still, I am excited to see what comes of this library.


Day #616

Sunday, December 30, 2012

Annotations in Dart

‹prev | My Chain | next›

While mucking about with constant constructors in Dart, I happened across a mention of a feature that is new to me: annotations. This mention in the spec was the first time that I have ever heard of annotations, so it seems worth stopping for a bit of investigation. I tend to doubt that understanding will come today, but stranger things have happened.

A bit of research reveals that annotations are similar to annotations in Java or attributes in C#, which goes a long way toward explaining why I have never heard of them. That also might explain why I may find it difficult to wrap my brain around them.

Per the spec:
Reflective access to metadata is not yet implemented as of the M2 release.
In other words, I will not be able to use Dart annotations directly in my code—at least not yet. That's just as well, because I doubt that I could figure them out tonight anyway.

What I can do is adopt the BugFix example from C# attributes in Programming C#. The example in there presents attributes / annotations as a mechanism for formalizing comments. In this case, bug fixes. Using what I know about constant constructors, I create a constant constructor for a BugFix class:
class BugFix {
  final int number;
  final String author;
  final String comment;
  const BugFix({this.number, this.author, this.comment});
}
Now, above the Cookie class upon which I have been working laboriously, I can indicate when I have applied bug fixes and a bit of information about them:
@BugFix(number: 42, comment: "Typo")
@BugFix(number: 45, author: "Chris", comment: "Typo")
class Cookie {
  int number_of_chips;
  Cookie({this.number_of_chips:0});
}
If I code up a main clause that puts this code to good use:
main() {
  var cookie = new Cookie();
  print("cookie has ${cookie.number_of_chips} chips");
}
I find that the code is executed normally—as if the annotation did not exist:
$ dart annotations.dart 
cookie has 0 chips
But I have formalize the manner in which bug fixes are associated with code.

I cannot say that I have have ever wanted something like that in a real codebase, but it does help to get a better feel for these beasties. Perhaps tomorrow I can come up with a better example of how I might want to use annotations—at least until they are available in reflection.


Day #615

Saturday, December 29, 2012

I Did Not Understand Constant Constructors

‹prev | My Chain | next›

If you really want to understand Dart constant constructors, read the comments to last night's post on the subject. Lasse wrote an excellent, succinct introduction to the subject. As for me, I learn best by playing with code, so tonight I follow up on yesterday's attempt at understanding.

The main thing that I was doing wrong yesterday was in instantiating my constant objects. I had been using the usual new keyword:
class PerfectCookie {
  final number_of_chips;
  const PerfectCookie({this.number_of_chips});
}

main() {
  var perfect_cookie = new PerfectCookie(number_of_chips: 42);
}
It turns out that const is overloaded to not only declare constant values, but it can also instantiate constant objects:
main() {
  var perfect_cookie = const PerfectCookie(number_of_chips: 42);
}
Following through with Lasse's notes, I expect that multiple instances of constant objects are the same thing—that is they should be identical:
main() {
  var pc1 = const PerfectCookie(number_of_chips: 42),
      pc2 = const PerfectCookie(number_of_chips: 42);

  print("pc1 and pc2 identical? ${identical(pc1, pc2)}");
}
Running this code results in:
pc1 and pc2 identical? true
As pointed out to me, constant constructors create compile-time constants. Another way of saying this, and this is what I missed yesterday, is that all of the associated values are known (and fixed) at compile time.

At the risk of repeating Lasse's entire comment, Dart used to allow only these compile time constants to be assigned to instance variables at compile-time. I never really understood what those compile-time constants were back then and, now that instance variables are lazily evaluated, they don't matter as much. Ah well, that's progress.

I still find it strange that using the regular new keyword works for constant constructors:
class PerfectCookie {
  final number_of_chips;
  const PerfectCookie({this.number_of_chips});
}

main() {
  var pc1 = const PerfectCookie(number_of_chips: 42),
      pc2 = const PerfectCookie(number_of_chips: 42),
      pc3 = new PerfectCookie(number_of_chips: 42);

  print("pc1 and pc2 identical? ${identical(pc1, pc2)}");
  print("pc1 and pc3 identical? ${identical(pc1, pc3)}");
}
The first and second "perfect cookies" are identical because their values are set at compile-time. The third perfect cookie is not evaluated until runtime. Even though the value for the number of chips is the same for all three objects, the Dart compiler cannot guarantee that the number of chips is fixed, hence the third instance refers to a different object than the first two:
pc1 and pc2 identical? true
pc1 and pc3 identical? false
I can seen the suggested benefits of using constant constructors as enums and sentinels. I may have to explore annotations because I was not even aware of this feature of Dart.

New to me is that Dart's case statement requires compile-time constants. So I might write the following:
main() {
  var pc1 = const PerfectCookie(number_of_chips: 42),
      pc2 = const PerfectCookie(number_of_chips: 42),
      pc3 = new PerfectCookie(number_of_chips: 42);

  print("pc1 and pc2 identical? ${identical(pc1, pc2)}");
  print("pc1 and pc3 identical? ${identical(pc1, pc3)}");

  const pc42 = const PerfectCookie(number_of_chips: 42),
      pc84 = const PerfectCookie(number_of_chips: 84),
      pc99 = const PerfectCookie(number_of_chips: 99);

  var cookie = pc1;
  switch(cookie) {
  case(pc42):
    print(42);
    break;
  case(pc84):
    print(84);
    break;
  case(pc99):
    print(99);
    break;
  }
}
Which would result in printing the value of 42 since the pc1 and pc42 are the same:
pc1 and pc2 identical? true
pc1 and pc3 identical? false
42
Constant constructors still seem of limited use in typical Dart coding, but I feel much better for having (mostly) explored this corner of the language.


Day #614

Friday, December 28, 2012

Dart Constant Constructors

‹prev | My Chain | next›

One of the many aspects of Dart that I do not cover in Dart for Hipsters is constant constructors. I briefly played with them a while back, but never really understood them. I will give them another try tonight.

A "regular" Dart cookie class (the yummy kind, not the browser obnoxious kind) might look and get used something like the following:
class Cookie {
  var number_of_chips;
  Cookie({this.number_of_chips});
}

main() {
  var cookie = new Cookie(number_of_chips: 12);

  print("An ordinary cookie has ${cookie.number_of_chips} chips");
}
Running this code would result in the following output:
An ordinary cookie has 12 chips
Constant constructors, as the name implies, involve instance variables that cannot be changed. In Dart, this is generally what the final keyword does—it creates variables (instance or otherwise) that cannot be updated.

Bearing that in mind, I create a PerfectCookie class, which is almost identical to my "regular" Cookie class, except that the number of chips is declared as a final value of 42:
class PerfectCookie {
  final number_of_chips = 42;
  const PerfectCookie();
}
Updating the main() entry point to use a PerfectCookie as well, I have:
main() {
  var cookie = new Cookie(number_of_chips: 12);
  var perfect_cookie = new PerfectCookie();

  print("An ordinary cookie has ${cookie.number_of_chips} chips");
  print("The perfect cookie has ${perfect_cookie.number_of_chips} chips");
}
The resulting output, as expected, now claims that 42 is the ideal number of chips in a cookie:
An ordinary cookie has 12 chips
The perfect cookie has 42 chips
Running this code through dart_analyzer generates no comments, so this seems a legitimate use-case for constant constructors.

Based on the description in the spec, I can also declare number_of_chips as final, but without assigning an actual value:
class PerfectCookie {
  final number_of_chips;
  const PerfectCookie({this.number_of_chips});
}
I can then use this class identically to the "regular" Cookie class:
main() {
  var cookie = new Cookie(number_of_chips: 12);
  var perfect_cookie = new PerfectCookie(number_of_chips: 42);

  print("An ordinary cookie has ${cookie.number_of_chips} chips");
  print("The perfect cookie has ${perfect_cookie.number_of_chips} chips");
}
I still get the same output:
An ordinary cookie has 12 chips
The perfect cookie has 42 chips
Most interestingly, the code still passes dart_analyzer. I had really expected dart_analyzer to complain that I was assigning a non-final value to number_of_chips in my constant constructor, but this seems fine.

What does not work (and is prohibited per the spec) is updating the number of chips in the object generated by the constant constructor:
main() {
  var cookie = new Cookie(number_of_chips: 12);
  var perfect_cookie = new PerfectCookie(number_of_chips: 42);

  cookie.number_of_chips = 13;
  perfect_cookie.number_of_chips = 43;

  print("An ordinary cookie has ${cookie.number_of_chips} chips");
  print("The perfect cookie has ${perfect_cookie.number_of_chips} chips");
}
I do not need dart_analyzer for this code. It produced a compile-time error:
Unhandled exception:
NoSuchMethodError : method not found: 'number_of_chips='
Receiver: Instance of 'PerfectCookie'
Arguments: [43]
#0      Object._noSuchMethod (dart:core-patch:1354:3)
#1      Object.noSuchMethod (dart:core-patch:1355:25)
#2      main (file:///Code/classes/constant_class.dart:16:18)
In this fashion, constant constructors seem a cheap way of creating objects with getters and no corresponding setter. It feels a little strange declaring this in the constructor rather than at the class name level. Is it possible to define a class with a constant constructor and non-constant constructor? And if so, to what end? Those minor worries aside, I can definitely see using these as some point—even if not often.


Day #613

Thursday, December 27, 2012

Complete Full Stack Testing in Dart

‹prev | My Chain | next›

As I have struggled with the right balance of mocking and stubbing in my Dart tests, it occurred to me that maybe the answer is no stubbing at all. The obvious problem with HttpRequest code is the dreaded cross origin violation:
XMLHttpRequest cannot load file:///comics. Cross origin requests are only supported for HTTP.
It would be ideal for a headless browser test to also be able to spin up a backend server against which it could run its tests. That is a ways off, however since the dart:io library is not available in Dartium (meaning I cannot spin up a web server in a browser, which is just as well).

Manually spinning up a web server and then accessing the test from the web server does not particularly appeal to me, but I file this under "don't knock it until you've tried it."

So I update my application server to serve up the test directory as well:
main() {
  HttpServer app = new HttpServer();

  new StaticFiles(app);
  new StaticFiles(app, dir:'test', mountPoint: '/test');
  // ...
})
Already I dislike this approach—including the test directory in a production app is just wrong. Actually, I already have a test environment check in place (to listen to a different port). What if I include that test directory only if running in test mode?
main() {
  HttpServer app = new HttpServer();

  new StaticFiles(app);
  // ...
  var port = 8000;
  if (Platform.environment['ENV'] == 'test') {
    port = 9999;
    new StaticFiles(app, dir:'test', mountPoint: '/test');
    Comics.filename = 'test.db';
  }
  // ...
}
That works just fine and I still have all of my (stubbed) tests passing, now on the 9999 test port:


After this, it is a matter of getting the client-side code built up enough to make requests to the backend. This code is primarily intended to support a chapter from Dart for Hipsters and had been scattered to support easy inclusion into the book. Now that my emphasis is on tested code samples, I have to work to reassemble that old code.

Eventually, I settle on the following setup code:
import '/scripts/comics.dart' as Main;

run() {
  group("[main]", (){
    var el = new Element.html('<ul id="comics-list">');

    setUp((){
      var comics = new Main.ComicsCollection();
      comics.create({
        "title": "Sandman",
        "author":"Neil Gaiman"
      });

      document.body.append(el);
    });
I directly access the collection class in the code that I am testing, using it to create a record on the test server. Then, in the test, I verify that this record is used to build the application page:
    test('populates the list', (){
      Main.main();
      window.setTimeout(() {
        expect(el.innerHtml, contains('Sandman'));
      }, 100);
    });
Unfortunately, I find that the setTimeout is required to give the page a chance to render after receiving the response from the server. That aside, it works as desired.

There are some definite advantages to this very full stack testing. I had a lot of code missing until I had to get it working end-to-end like this. Still, I do not think that I am sold on this approach. In addition to the setUp, I also have to be careful to tearDown my backend DB. That is an easy thing to lose track of. And I just don't care for having to spin up the test server and remember the URL to access. It is much easier to be in the right directory and type chrome index.html. That said, the full-stack effort is of some value, so I may find some way to make use of it in the future.

Day #612

Wednesday, December 26, 2012

More Mock Http Requests in Dart

‹prev | My Chain | next›

I have a hacky unit test in place for some early code from Dart for Hipsters. Rather unfortunately, this involves jamming a conditional-behavior HttpRequest class directly in production code. Ultimately, this code evolves into Hipster MVC, which allows the data sync layer to be injected as a matter of course. Testing will be easy there. But what happens when I try to test the code after the initial implementation and before the injection class? Hopefully I might learn a better way of doing this.

In the book, I move the HttpRequest code out into something of a MVC collection. The code is identical to the fully inline code used before refactoring with one small exception:
class ComicsCollection implements Collection {
  //  ...
  void fetch() {
    var req = new HttpRequest();
    req.on.load.add((event) {
      var list = JSON.parse(req.responseText);
      _handleOnLoad(list);
    });
    // verb, resource, boolean async
    req.open('get', url, true);
    req.send();
  }
}
The difference is the _handleOnLoad() private method. In the original implementation, this had simply built HTML for the page, which could be immediately tested. Now, I build a bunch of models based on the JSON and dispatch a load event:
  _handleOnLoad(list) {
    list.forEach((attrs) {
      var new_model = new ComicBook(attrs);
      new_model.collection = this;
      models.add(new_model);
    });

    on.load.dispatch(new CollectionEvent('load', this));
  }
Eventually that load event reaches the necessary view, which draws the individual elements on the page.

I can play the same trick of my code that I did yesterday, replacing HttpRequest in that fetch() method with my custom built MaybeMockHttpRequest. By default, that uses the real HttpRequest, so my sample app still runs. Some well placed setUp() code in my tests insert a fake HttpRequest and response:
    setUp((){
      Main.MaybeMockHttpRequest.use_mock = true;
      Main.MockHttpRequest.responseText = """
        [{"id":"42", "title": "Sandman", "author":"Neil Gaiman"}]
      """;

      document.body.append(el);
    });

    test('populates the list', (){
      Main.main();
      expect(el.innerHtml, contains('Sandman'));
    });
With that, I have a passing test:


It is encouraging that this MaybeMockHttpRequest approach still works in the modified code. I have a bit more confidence in sticking with this approach—at least to keep the code in my book under test.

At the same time, it still feels wrong. I should not have to resort to fake class hackery in live code just to test my code. I might claim that Dart wants dependency injected HttpRequest layers by virtue of difficulty testing any other way—I did eventually factor this code out into a testable sync layer. But that seems a cop out—I ought to be able to test vanilla HttpRequest code.

Part of the problem is definitely me. I am trying to perform (nearly) full stack integration testing with a unit testing library. Maybe I should live with a bit of hackery. Or maybe I need to embrace the insanity and fire up a test server so that I can truly test the entire stack. Tomorrow.


Day #611

Tuesday, December 25, 2012

Fake Mocks to Test HttpRequest Dart Apps

‹prev | My Chain | next›

In order to test some introductory code in Dart for Hipsters, I ended up introducing a MaybeMockHttpRequest class:
load_comics() {
  var list_el = document.query('#comics-list')
    , req = new MaybeMockHttpRequest();

  req.open('get', '/comics', true);

  req.on.load.add((res) {
    var list = JSON.parse(req.responseText);
    list_el.innerHtml = graphic_novels_template(list);
  });

  req.send();
}
I will use a bit of code generation trickery to strip the MaybeMock bit from the code that actually goes in the book. The bottom line is that I can use this mock HttpRequest to stand-in for a real HttpRequest object under test.

The MaybeMockHttpRequest class uses a static variable to determine whether all objects constructed by this class are the real thing or a mock version:
class MaybeMockHttpRequest {
  static var use_mock;

  factory MaybeMockHttpRequest() {
    if (MaybeMockHttpRequest.use_mock) return new MockHttpRequest();

    return new HttpRequest();
  }
}
By default, the real thing is used. To force the faker, I call MaybeMockHttpRequest from my test:
  group("[main]", (){
    setUp(() {
      Main.MaybeMockHttpRequest.use_mock = true;
    });
    // ...
  });
The actual MockHttpRequest class defines only the methods used in my code:
class MockHttpRequest {
  open(_a, _b, _c) => true;
  get on => new NullObject();
  send() => true;
}
That NullObject beast is a simple object that returns instances of itself whenever any of its methods are invoked:
class NullObject {
  noSuchMethod(invocation) {
    return new NullObject();
  }
}
Ah, the magic of noSuchMethod(). Anyhow, this has very simple tests passing:
    test('the app returns OK', (){
      expect(Main.main, returnsNormally);
    });
I would like a more substantive test. In this case, I would like to verify that, on successful JSON response for the list of comics books in my collection, the web page is updated with the appropriate title.

To accomplish that, I need to either inject or hard-code a response. I think hard-coding might be an appropriate solution in this case, but, since injecting is more difficult, I opt for that approach tonight. To be clear, I am not seeking a general solution. I am most decidedly playing with code to learn. If the resulting test code seems robust enough, I may keep it—after all it is just test code—but I am not trying to build a library or anything close to reusable.

In the setUp for my test, I am already telling the MaybeMockHttpRequest class that it should mock requests. In addition to that, I now want to tell the MockHttpRequest class what the response should be:
    setUp((){
      Main.MaybeMockHttpRequest.use_mock = true;
      Main.MockHttpRequest.responseText = """
        [{"id":"42", "title": "Sandman", "author":"Neil Gaiman"}]
      """;

      document.body.append(el);
    });
I can support that fairly easily with a static variable and static setter:
class MockHttpRequest {
  static var _responseText;

  static set responseText(v) => _responseText = v;
  get responseText => _responseText;

  open(_a, _b, _c) => true;
  get on => new NullObject();
  send() => true;
}
The static variable/setter and instance getter is a bit of a hack, but it serves my purposes. It works even though the _responseText reference in the instance getter fails—happily Dart will look up the same variable at the class level, which is where it finds it defined.

This still does not work because that responseText is called via a callback:
load_comics() {
  var list_el = document.query('#comics-list')
    , req = new MaybeMockHttpRequest();

  req.open('get', '/comics', true);

  req.on.load.add((res) {
    var list = JSON.parse(req.responseText);
    list_el.innerHtml = graphic_novels_template(list);
  });

  req.send();
}
Dang, I don't think that awesome NullObject is going to work for the on property in MockHttpRequest. Instead, I create a MockEvents class with a load property:
class MockEvents {
  List load = [];
}
As pretty as the NullObject was, that one-line body is even better as it more closely mimics the real on property.

With that, I can update MockHttpRequest to call all of the callbacks in the load list when the fake HTTP request is sent:
class MockHttpRequest {
  static var _responseText;
  var on = new MockEvents();

  static set responseText(v) => _responseText = v;
  get responseText => _responseText;

  open(_a, _b, _c) => true;
  send() => on.load.forEach((cb){cb(null);});
}
With that, I make my test invoke the main() function and set my expectation that the page will soon contain the comic book title from my dummy JSON:
    test('populates the list', (){
      Main.main();
      expect(el.innerHtml, contains('Sandman'));
    });
And... it passes:


In the end, I somewhat like this approach. The three classes, MaybeMockHttpRequest, MockHttpRequest and MockEvents have 11 lines of code between them to replace the normal HttpRequest classes:
class MaybeMockHttpRequest {
  static var use_mock;

  factory MaybeMockHttpRequest() {
    if (MaybeMockHttpRequest.use_mock) return new MockHttpRequest();

    return new HttpRequest();
  }
}

class MockHttpRequest {
  static var _responseText;
  var on = new MockEvents();

  static set responseText(v) => _responseText = v;
  get responseText => _responseText;

  open(_a, _b, _c) => true;
  send() => on.load.forEach((cb){cb(null);});
}

class MockEvents {
  List load = [];
}
I have a test that verifies that, when send() results in a call to the list of load event listeners, then the web page gets populated. To be sure, this is not the same as a full stack, integration test, but it is still useful. Best of all, the dart_analyzer barely bats an eye at this code. All that seems to bother it is the mixing of the static and instance method names for the responseText stuff:
file://your_first_dart_app/public/scripts/comics.dart:116:14: Field's getter and setter should be both static or not static
   115:
   116:   static set responseText(v) => _responseText = v;
                     ~~~~~~~~~~~~
Of course this bothers me a bit too, so I will likely fix it. But all in all, I am fairly happy with this.

That said, I wouldn't say "no" if Dart suddenly supported a mechanism to override responseText. Until that capability comes along, this will do.


Day #610

Monday, December 24, 2012

Cannot Stub HttpRequest in Dart

‹prev | My Chain | next›

Up today, I hope to figure out how to test HttpRequest code in Dart. I began building a test suite for the first chapter in Dart for Hipsters yesterday, but that client-side code did little more than not crash.

The remainder of the code in Chapter One builds around HttpRequest code such as:
main() {
  load_comics();
}

load_comics() {
  var list_el = document.query('#comics-list')
    , req = new HttpRequest();

  req.open('get', '/comics', true);

  req.on.load.add((res) {
    var list = JSON.parse(req.responseText);
    list_el.innerHTML = graphic_novels_template(list);
    attach_delete_handlers(list_el);
  });

  req.send();
}
I will try to test the actual functionality later. For now. I start with a simple returnsNormally test:
    test('the app returns OK', (){
      expect(Main.main, returnsNormally);
    });
Unfortunately, that results in the following failure:
[main] the app returns OK. Expected: return normally but: threw <Error: NETWORK_ERR: XMLHttpRequest Exception 101>.
This particular error results from an HttpRequest attempt from a file:// page (the HTML page that holds the tests). In the Dart console I see a JavaScripty complaint:
XMLHttpRequest cannot load file:///comics. Cross origin requests are only supported for HTTP.
Unfortunately, I think I am stuck here. There is no way to redefine a method in Dart, so I have no hope of redefining open(). I might try to redefine the HttpRequest class so that it returns a real or fake HttpRequest object depending on a static variable setting. Unfortunately, this kind of thing will not work:
class MockHttpRequest implements HttpRequest {}
class RealHttpRequest  {
  factory RealHttpRequest() => new HttpRequest();
}

class HttpRequest {
  factory HttpRequest() {
    return new RealHttpRequest();
  }
}
This turns out to be a good way to generate a stack overflow (RealHttpRequest return an instance of HttpRequest, which returns an instance of RealHttpRequest).

My real problem is that I absolutely must stick with creating an instance of HttpRequest using the form:
req = new HttpRequest();
Were this real-world code, I could use some form of dependency injection to supply an alternate HttpRequest object. I do this sort of thing in HipsterSync in the Hipster MVC library.

What I would really like is some way to intercept or stub all network connections in Dart. But this seems a ways off at this time. So I find myself stuck with this particular bit of code. I will mull this over a bit, but I may have to either leave this bit of code untested or I may have to resort to some kind of Frankenstein-like code sample assembly in the book. Neither option is particularly pleasant, but I do not see many alternatives.


Day #609

Sunday, December 23, 2012

Testing Old-School Code in Dart

‹prev | My Chain | next›

I have gotten into a pretty good rhythm updating Dart for Hipsters. I am feverishly trying to update the book for Dart's recent M2 release (before they freaking announce an M3). This has mostly involved extracting code samples out into tested source files. But most of my work so far has involved non-browser based Dart code. Since most of the book involves building a client-side application, I really need a way to extract those code samples into testable chunks.

There are two problems that I foresee. First, the early parts of the book follow more of a JavaScript convention for building applications (to ease the reader into the Dart way). If I have my code in non-standard Dart locations, testing is more difficult. The second problem is that I need to keep the code sample in sync with various branches in the Dart Comics sample application. For sundry reasons, git sub-modules are not a possibility, so I see no other way than to manually copy code from Dart Comics into Dart for Hipsters.

Compounding my problems is Dart's current inability to perform headless testing. Whenever I make a change to the code in my Dart Functions chapter, I can run my tests and, in less than a second, know that everything still works. I am going to need to adjust my workflow for the browser-based chapters to reload a testing web page. That's not a huge deal, but I definitely look forward to headless testing.

I begin the book by introducing the following skeleton script:
import('dart:html');
import('dart:json');
main() {
  loadComics();
}
loadComics() {
  // Do stuff here
}
Since it does not actually do anything, there is little to test beyond that it compiles and returns without error. Since it is so simple, that seems like a good starting point. So, in my chapter's test directory, I create a local test page to hold my test output:
<html>
<head>
  <title>Your First Dart App Tests</title>
  <script type="application/dart" src="test.dart"></script>

  <script type="text/javascript">
    // start dart
    navigator.webkitStartDart();
  </script>
</head>

<body>
<h1>Test!</h1>

</body>
</html>
In the referenced test.dart file, I adapt the convention that I have been using in my pure Dart tests. I import a series of tests that describe a particular aspect of the book's discussion and run the tests:
import 'package:unittest/html_enhanced_config.dart';

import 'skeleton.dart' as Skeleton;

main () {
  useHtmlEnhancedConfiguration();

  Skeleton.run();
}
The only difference here is the use of the html_enhanced_config.dart library to draw pretty test results in the browser.

As for the skeleton.dart test file, I do the usual thing of importing the unittest library, importing the skeleton file itself and then defining my expectation:
library skeleton_snippet_test;

import 'package:unittest/unittest.dart';

import '../public/scripts/skel.dart' as Skeleton;

run() {
  group("[skeleton]", (){
    test('the skeleton app returns OK', (){
      expect(Skeleton.main, returnsNormally);
    });
  });
}
I really appreciate the rich variety of test matchers that come built into the Dart unit testing library. The returnsNormally matcher will pass as long as the supplied function returns without exception or error.

When I finally load this test up in Dartium, however, I hit a compile-time error:
Internal error: 'file:///Code/your_first_dart_app/public/scripts/skel.dart': Error: line 1 pos 1: library name definition expected
import('dart:html');
^ 
I cannot import something that is not a library. Unfortunately, I cannot include external source unless it is declared an exclusive part of another library either, so I am stuck adding a library declaration to the top of the code being tested:
library skeleton_example;

import 'dart:html';
import 'dart:json';
main() {
  loadComics();
}
loadComics() {
  // Do stuff here
  throw new UnsupportedError();
}
That is less than ideal since I am testing a standalone script, not a library. Also, this is way too early in the book to be introducing libraries—the only reason that I use them here is for testing the code that will be included in the book.

Unfortunately, I cannot think of another way to be able to test these standalone snippets. The library statement does not change in the behavior of the real application. So I will likely strip the library statement from the book, but leave it in the actual code to keep it testable.

This is not a Dart deficiency. I am writing my application code contrary to Dart conventions so I have to live with the consequences. Including a library statement is a small consequence.

With the library statement in place, I load up my test page again and find that I have a passing test:


Solely for my own edification, I alter the code to see what happens if the main() function would not return normally:
main() {
  loadComics();
}
loadComics() {
  // Do stuff here
  throw new UnsupportedError();
}
Now, I get a pretty old backtrace:


OK, perhaps the backtrace is not pretty, but the error message sure is: "Expected: return normally but: threw <No such method: 'UnsupportedError'." That is thanks to the returnsMatcher that I used. I love stuff like that. I am really enjoying testing with Dart.


Day #608

Saturday, December 22, 2012

Testing Print Output in Dart

‹prev | My Chain | next›

While working through the process of converting code samples in Dart for Hipsters, I ran into a small problem with printing examples. I am converting the code samples from (mostly) inline examples to external, tested files. The problem is that several of the earlier examples involve printing output.

While describing optional parameters, I use a good_day() function that prints out a pleasant greeting:
      good_day("Bob");
      // Good day, Bob.
If an optional emphatic parameter is supplied, then the printed message will be a bit stronger:
      good_day("Bob", emphatic: true);
      // Good day, Bob.
      // I said good day!
Dart, of course, has a wonderful syntax to support optional parameters. This makes the definition of the good_day function quite easy:
good_day(name, {emphatic}) {
  print("Good day, ${name}.");
  if (emphatic) {
    print("I said good day!");
  }
}
After a bit of fiddling, I opt to override the built-in print() method. Instead of sending messages to STDOUT (with the SDK) or the console (in the browser), I store them in a private list of all of the messages that were sent to print():
var _prints = [];
print(val) => _prints.add(val);
If I am careful to clear that list before each test, I can test the expected print output against the _prints list. Doing something before each test is the purview of the setUp function, so my tests can be written something like:
    setUp(() => _prints = []);

    test('required only', (){
      good_day("Bob");
      // Good day, Bob.

      expect(_prints, equals(['Good day, Bob.']));
    });
And, thanks to that setUp() which clears the _prints list each time, subsequent tests are also mercifully clean:
    test('optional named parameter', (){
      good_day("Bob", emphatic: true);
      // Good day, Bob.
      // I said good day!

      expect(_prints, equals([
        'Good day, Bob.',
        'I said good day!'
      ]));
    });
The only problem with this approach is the duplication between the comment (that appears in the book to signify the print output) and the expected list of print output. I might try reading the source code from the test, but this seems more trouble than it is worth. The test will be harder to read, which would make it harder to see what is going wrong when the test breaks.

The best solution is likely to simply limit the number of code examples that print output. That may even make some of the discussion in the book better. But, for those examples where print() makes sense, I have a decent working solution.


Day #607

Friday, December 21, 2012

Dart Regression Testing for Hipsters

‹prev | My Chain | next›

A solid test suite was not an option for the first two editions of Dart for Hipsters. It is now. The advent of a proper unittest package in the Dart Pub means that I have no more excuses for incorrect code. More importantly, I have no excuse for not quickly identifying which code samples are out of date with the latest changes to Dart.

The question still remains, how do I test a code sample that looks something like the following?
    var str1 = "foo",
        str2 = str1;

    str1.hashCode; // 596015325
    str2.hashCode; // 596015325
(this demonstrates that string copies point to the original object)

I like the format of the code—it fits well in the narrative of the book. I would hate to introduce print() or other statements that might obscure the point. But as-is, that is not exactly a method that lends itself to testing. It's not even a method.

My first instinct is to put the code for the book inside a multi-line comment and then test similar code. That is less than ideal because I would need to work hard to keep the commented code in sync with the testing code.

In the end, I decide to put this inside a setUp block. The variables are local to that function, so I need a way to expose them for subsequent testing—library scoped variables to the rescue:
import 'package:unittest/unittest.dart';

String _str1, _str2;

main() {
  setUp((){
    /* ------------------------- */
    var str1 = "foo",
        str2 = str1;

    str1.hashCode; // 596015325
    str2.hashCode; // 596015325
    /* ------------------------- */

    _str1 = str1;
    _str2 = str2;
  });

  test('"foo" is 596015325', (){
    expect(_str1.hashCode, equals(596015325));
  });

  test('copy of "foo" is 596015325', (){
    expect(_str2.hashCode, equals(596015325));
  });
}
Using private variables to mirror the variables in the code sample is a choice of convenience rather than a need for them to be private. I get to use the same name, just with a leading underscore. This should make it obvious what is going on when I revisit this test a few months down the line.

The actual value of the hash code is not too important, so I may change it to a setUp variable in the future if I find that this causes trouble.

In the end, it is easy to visually see where the actual code snippet is. It is easy for the book software to grab that same extract. And I have a test that passes:
$ dart strings.dart                   
unittest-suite-wait-for-done
PASS: "foo" is 596015325
PASS: copy of "foo" is 596015325

All 2 tests passed.
unittest-suite-success
That is one snippet. How do I run multiple snippets at the same time? I cannot simply pass multiple dart tests to the dart interpreter because they would all have a main() entry point:
# Only the string concatenation tests run:
$ dart strings.dart string_concat.dart
unittest-suite-wait-for-done
PASS: "foo" is 596015325
PASS: copy of "foo" is 596015325

All 2 tests passed.
unittest-suite-success
I could put all of the tests into one big file. For various reasons, it would be better to keep the code snippets in separate files. In Dart, that means either import of libraries or including the separate files as a part of the whole.

I opt for import because that will allow me to use the same method name in each executable snippet. That is, instead of main() in my tests, I use run():
library strings_snippet;

import 'package:unittest/unittest.dart';

String _str1, _str2;

run() {
  group("[strings]", (){
    setUp((){
      /* ------------------------- */
      // code snippet here...
      /* ------------------------- */
      // ...
    });

    // tests here...
  });
}
Aside from the new run() method name, I also add a group call around my test to better distinguish the tests when all of them are run together. And, of course, I need a library statement at the top so that I can import the library into the main test.dart file.

As for the main test file, it is relatively simple:
import 'strings.dart' as Strings;
import 'string_concat.dart' as StringConcat;

main () {
  Strings.run();
  StringConcat.run();
}
Even though both libraries define a run() method, I can still import and use them thanks to Dart's library namespacing. The end result is quite readable—I rather like it.

And better still, I have some very nice test output verifying that my code snippets work with the most recent Dart:
$ dart test.dart
unittest-suite-wait-for-done
PASS: [strings] "foo" is 596015325
PASS: [strings] copy of "foo" is 596015325
PASS: [string concat] "foo" is 596015325
PASS: [string concat] "foo".concat("bar") is 961740263

All 4 tests passed.
unittest-suite-success
Well, at least the version of Dart from three days ago. Who knows what could be broken now? Actually I can—thanks to my nifty test suite.


Day #606

Thursday, December 20, 2012

Test Driven Error Fixes in Dart

‹prev | My Chain | next›

Thanks to the magic of dart_analyzer I know that my Dart Comics example Dart application is in exceptional shape. +Kasper Lund pointed out that my exception handling might be a bit off—despite the fact that dart_analyzer did not complain about it.

The problem is that in my haste to ensure that the remove() method in my event listener list class was not supported, I am not actually throwing an error:
abstract class HipsterEventListenerList implements EventListenerList {
  // ...
  EventListenerList remove(EventListener listener, [bool useCapture=false]) {
    throw UnsupportedError;
  }
  // ...
}
Instead of throwing an error, I am throwing an error class. That is allowed per the dart language spec. Any old object can get thrown—it does not have to be an exception or error subclass. Indeed it seems that I can even throw classes. But I do not believe that it is possible to catch that error.

To test that theory, I write a test. This particular class resides in the Hipster MVC package, so I will add my test there.

I am going to need a browser for this test since the event classes are based on the events in the dart:html library, which requires a browser (and there are no headless Dart environments yet). The skeleton of the test imports the unittest library, the enhanced HTML reporter (for pretty browser reporting), and the events library:
import 'package:unittest/unittest.dart';
import 'package:unittest/html_enhanced_config.dart';

import 'package:hipster_mvc/hipster_events.dart';

class TestEventListenerList extends HipsterEventListenerList {}

main() {
  useHtmlEnhancedConfiguration();
  // tests go here...
}
I need a concrete class to test the remove() method in the abstract HipsterEventListenerList, hence TestEventListenerList above. In the main() entry point, I start the HTML reporter.

As for the test itself, I define a group in which I will describe all unsupported methods (currently only remove). Groups are not strictly required by the testing library, but they help with the output. In the test proper, I create an instance of TestEventListenerList so that I can test it. As for my expectation, I expect the result of invoking an anonymous function that removes a dummy value from the list will throw an unsupported error:
main() {
  useHtmlEnhancedConfiguration();

  group('unsupported', () {
    test('remove', (){
      var it = new TestEventListenerList();
      expect(
        () => it.remove("foo"),
        throwsUnsupportedError
      );
    });
  });
}
If I do not use an anonymous function inside the expect function, then it.remove() would get evaluated before the expect call. That is, the following would not work:
    test('remove', (){
      var it = new TestEventListenerList();
      expect(
        it.remove("foo"),
        throwsUnsupportedError
      );
The it.remove("foo") would throw an UnsupportedError before expect even has a chance to evaluate its two parameters.

As an aside, I think that I appreciate the distinction between errors (non-recoverable) and exceptions (exceptional occurrences, but recoverable). In this case, code that expects that an event listener was removed would almost certainly be in an unstable state, which should crash the application. Hopefully an intrepid contributor would then feel compelled to submit a patch.

Anyhow, back to my original problem. What happens when I run this test against my code that throws a class instead of an object? The test crashes, dumping the following into the console:
Internal error: 'file:///home/chris/repos/hipster-mvc/test/packages/hipster_mvc/hipster_events.dart': Error: line 32 pos 11: illegal use of class name 'UnsupportedError'
    throw UnsupportedError;
          ^ 
Ah! So dart_analyzer might give me a pass on this, but the Dart VM in Dartium does not.

The next step is easy enough: I have my failing (well, not compiling) test. Let's make it pass. The fix is similarly easy—I just need to throw an instance of UnsupportedError:
abstract class HipsterEventListenerList implements EventListenerList {
  // ...
  EventListenerList remove(EventListener listener, [bool useCapture=false]) {
    throw new UnsupportedError("Planned in a future release");
  }
  // ...
}
With that, I have my first Hipster MVC test passing:


I appreciate being able to drive this bug fix with tests, which are easy in Dart since the unittest library is available as a Dart Pub package. Hopefully this particular test will not be long-lived, and will be replaced by a test that verifies removal of an event listener. Still, it is nice to have the ability to drive functionality with a reusable test (of course, I would still prefer a way to do so headless).

I also really like the test matchers that are built into the unit testing library. It is nice being able to write throwsUnsupportedError rather than setting my expectation on the outcome of a try-catch block. Reporting—especially when tests fail—is much nicer with matchers like this.


Day #605

Wednesday, December 19, 2012

Static Typing Driven Refactoring

‹prev | My Chain | next›

I found yesterday that there was not much that I needed to do in order to ready for the M2 release of Dart—most of the work that I have been doing recently seems to already be bundled in M2. One thing that the dart_analyzer complained about in my code was some insufficient sub-classing in Hipster MVC. This is not a new problem—it is one that I have been ignoring for quite some time.

The problem is how I propagate events through my stack. I use subclasses of the built-in Event class from the dart:html library. I felt that I could kinda/sorta get away with this because dart:html is required for a client-side library. But at the same time, I always felt a little weird about subclassing a browser event class to propagate my MVC stack events. Warnings like the following were a manifestation of the weirdness:
file:/home/chris/repos/hipster-mvc/lib/hipster_model.dart:135:7: Concrete class ModelEvent has unimplemented member(s) 
    # From Event:
        bool bubbles
        bool cancelBubble
        bool cancelBubble
        bool cancelable
        Clipboard clipboardData
        EventTarget currentTarget
        bool defaultPrevented
        int eventPhase
        bool returnValue
        bool returnValue
        EventTarget target
        int timeStamp
        void $dom_initEvent(String, bool, bool)
        void preventDefault()
        void stopImmediatePropagation()
        void stopPropagation()
   134: 
   135: class ModelEvent implements Event {
              ~~~~~~~~~~
I have two choices here. I can either implement those methods with empty definitions or I can stop subclassing Event. I have the nagging suspicion that building my own event class is the way to go, but I opt for the former tonight. The hope is that I can definitively find a reason that subclassing Event for non-DOM events is a bad thing.

It turns out that the simplest thing actually works. I convert each of those method signatures into empty or false definitions:
class ModelEvent implements Event {
  var type, model;
  ModelEvent(this.type, this.model);

  bool bubbles = false;
  bool cancelable = false;
  bool cancelBubble = false;
  Clipboard clipboardData;
  EventTarget currentTarget;
  bool defaultPrevented = false;
  int eventPhase;
  bool returnValue = false;
  EventTarget target;
  int timeStamp;
  void $dom_initEvent(String _a, bool _b, bool _c) {}
  void preventDefault() {}
  void stopImmediatePropagation() {}
  void stopPropagation() {}
}
And I no longer have any warnings—at least not from that class. I deal with most of the other errors in the same manner, but then I come across:
file:/home/chris/repos/hipster-mvc/lib/hipster_model.dart:167:7: Concrete class ModelEventList has unimplemented member(s)
    # From EventListenerList:
        EventListenerList remove(EventListener)
   166: 
   167: class ModelEventList implements EventListenerList {
              ~~~~~~~~~~~~~~
The event listener list is the nexus of events in Dart. It is a list of callbacks that are invoked when a delete happens (or a create happens, or an add, etc.). It probably makes sense to be able to remove callbacks. Someday I will add this functionality, but right now I do not need it. So I simply throw an unsupported error:
class ModelEventList implements EventListenerList {
  var listeners = [];

  add(fn, [bool useCapture=false]) {
    listeners.add(fn);
  }

  EventListenerList remove(EventListener listener, [bool useCapture=false]) {
    throw UnsupportedError;
  }

  bool dispatch(Event event) { /* ... */ }
}
That eliminates all of the warnings from the model class, but the collection class has very similar problems. In fact, it has the exact same problems because the collection supports generating and dispatching events in the same way. Instead of ModelEvent, it is CollectionEvent. There are some collection events that optionally include the model (e.g. when a model is deleted). Aside from those minor differences, the ModelEvent classes are the same as the CollectionEvent classes.

Say, this seems like a good time to introduce a common superclass, which is exactly what I do. In a new hipster_events.dart library file, I declare 3 abstract classes with as much of the common functionality included:
library hipster_events;

import 'dart:html';

abstract class HipsterEvent implements Event {
  // ...
}

abstract class HipsterEvents implements Events {}

abstract class HipsterEventListenerList implements EventListenerList {
  // ...
}
The HipsterEvent class includes all of the missing Event methods that I just added to ModelEvent so that I do not have to add them to both the soon-to-exist ModelEvent and CollectionEvent classes.

I declare these three classes as abstract primarily because I do not want them being used directly. Also, since Event does not have a generative (normal / non-factory) constructor, I would have to define one if I had not declared the class as abstract.

After importing hipster_events.dart into the hipster_collection library, I can then extend the abstract HipsterEvent class:
class CollectionEvent extends HipsterEvent {
  String type;
  HipsterCollection collection;
  HipsterModel model;

  CollectionEvent(this.type, this.collection, {this.model});
}
After doing the same for the other classes (the collection events and the list of listeners for those events), I have eliminated all of the errors from my code—at least as far as dart_analyzer is concerned.

I have to admit that I find an abstract class (HipsterEvent) implementing an interface (Event) a little awkward. How can it truly implement the interface if it still has abstract methods (methods with no bodies)? The only alternative, however, is to extend the interface. That won't work because I would still be left with an interface. Even if I declare method bodies in that interface, the HipsterEvent subclass / implementer does not see those definitions.

One nice side-effect of moving all of the event code into its own library is that neither the hipster_collection nor the hispter_model libraries need to import 'dart:html' any longer. Both libraries are now composed solely of other Hipster MVC classes or the code defined inside their own libraries. Removing an external dependency makes this approach a winner.

As for whether or not I should define my own classes, that question remains outstanding. But if I do, I only need to make that change in a single location now—the hipster_events library—rather than in two locations. But for the time being, I think I will be content to leave well enough alone. And well enough in this case means functional code that still works in the Dart Comics sample application and passes through dart_analyzer.


Day #604

Tuesday, December 18, 2012

Not Quite Ready for Dart M2

‹prev | My Chain | next›

The Dart team gave the world a lovely present: the M2 release of the langauge. This means more than new language awesomeness—it means that it's time to run the dart_analyzer again.

Many of the changes that I need to make are minor changes to the API—things like removing parentheses from getters, specifying default values, etc. Among the more interesting things that changed are the departures from JavaScript naming of standard DOM things. I get a lot of deprecation warnings along the lines of:
file:/home/chris/repos/dart-comics/app/lib/Views.Comics.dart:22:8: Field 'innerHTML' is deprecated
    21:   render() {  
    22:     el.innerHTML = template(collection);
It is now innerHtml instead of innerHTML. I, for one, definitely appreciate the switch for consistency's sake.

Another warning is more of a quasi-bug than it is an M2 issue. The warning is:
file:/home/chris/repos/dart-comics/app/lib/Views.AddComicForm.dart:13:10: 'ModalDialog' is not assignable to 'Element'
    12:   post_initialize() {
    13:     el = new ModalDialog();
                 ~~~~~~~~~~~~~~~~~
In a view, I am setting the el property to a locally written ModalDialog object, which is a perfectly reasonable thing to do. The reason that dart_analyzer is complaining is that the el property was declared as an Element whereas ModalDialog is a plain old Dart class.

The fix is easy enough, I just need to declare ModalDialog as extending (subclassing) Element:
library modal_dialog;

import "dart:html";

class ModalDialog extends Element {
  Element el, bg;
  var resizeHandler;

  ModalDialog(): this.tag('div');

  ModalDialog.tag(String tag) {
    el = new Element.tag(tag);
    resizeHandler = _drawBackground;
  }

  ModalDialog.html(String html) {
    el = new Element.tag('div');
    el.innerHtml = html;
  }
  // ...
}
And that fixes my problem. Except it introduces two new problems:
file:/home/chris/repos/dart-comics/app/lib/ModalDialog.dart:11:3: super type Element does not have a default constructor
    10: 
    11:   ModalDialog.tag(String tag) {
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
file:/home/chris/repos/dart-comics/app/lib/ModalDialog.dart:16:3: super type Element does not have a default constructor
    15: 
    16:   ModalDialog.html(String html) {
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This, I think is probably a legitimate bug. Unfortunately, I am unsure how to fix it. The Element constructors are factory constructors, so I can eliminate the dart_analyzer warning with a simple factory constructor like:
class ModalDialog extends DivElement {
  Element el = new DivElement();
  Element bg;
  var resizeHandler = _drawBackground;

  factory ModalDialog() => new DivElement();
  // ...
}
The dart_analyzer warnings go away, but the code no longer runs in Dartium. When I try to start a ModalDialog, I receive the following error:
Internal error: 'http://localhost:8000/packages/scripts/ModalDialog.dart': Error: line 5 pos 7: class 'ModalDialog' is trying to extend a native fields class, but library 'http://localhost:8000/packages/scripts/ModalDialog.dart' has no native resolvers
class ModalDialog extends DivElement {
This would seem to indicate that there is no way to create an Element subclass in Dart, which would be a bummer as I would like to create element-like things like modal dialogs. I have to call it a night here, but I will try to revisit tomorrow.



Day #603

Monday, December 17, 2012

Packaging Main.dart for Organization and Testing

‹prev | My Chain | next›

I ended yesterday with the main entry point in my Dart application in the scripts directory. Thanks to the magic of Dart Pub, that main entry point was then able to import the remaining application code.

The web page looks like:
<head>
  <title>Dart Comics</title>
  <link rel="stylesheet" href="/stylesheets/style.css">

  <script src="/dart.js"></script>
  <script src="/packages/scripts/main.dart" type="application/dart"></script>
</head>
In other words, it is a pretty typical <script> tag that is pulling my main entry point from scripts/main.dart and looks like:
import 'package:scripts/Collections.Comics.dart' as Collections;
import 'package:scripts/Views.Comics.dart' as Views;
import 'package:scripts/Views.AddComic.dart' as Views;

import 'dart:html';
import 'dart:json';

import 'package:hipster_mvc/hipster_sync.dart';

main() {
  // initialize code here
}
Aside from the awesome import and package stuff, it is very much like the usual JavaScript code that I might write.

In the comments to yesterday's article, Ladislav Thon suggested another possible approach—one that leveraged Dart's imports a bit more. With this approach, I need to move my main.dart entry point out of the app/web/scripts directory and move it into app/lib. As such, it is no longer directly accessible via a <script> tag, but it is part of my application's packages.

So, my HTML now performs an inline import:
<head>
  <title>Dart Comics</title>
  <link rel="stylesheet" href="/stylesheets/style.css">

  <script src="/scripts/dart.js"></script>
  <script type="application/dart">
    import 'package:scripts/main.dart' as App;
    main() => App.main();
  </script>
</head>
I would prefer it if I could do that import as part of the <script> tag, but until <script> tags become package aware, I will have to settle for that.

I am not quite done yet. It is not possible to import a library in Dart without declaring the file as a library. So I add the library directive along with an identifier to the top of main.dart in the app/lib directory:
library app;

import 'package:scripts/Collections.Comics.dart' as Collections;
import 'package:scripts/Views.Comics.dart' as Views;
import 'package:scripts/Views.AddComic.dart' as Views;

import 'dart:html';
import 'dart:json';

import 'package:hipster_mvc/hipster_sync.dart';

main() {
  // initialize code here
}
It feels a little henky being forced to declare my main entry point as a library, but I can probably learn to live with it.

What that buys me is the ability to keep all of the Dart code associated with this application in one place—the app/lib directory:
app
├── lib
│   ├── Collections.Comics.dart
│   ├── main.dart
│   ├── ModalDialog.dart
│   ├── Models.ComicBook.dart
│   ├── Views.AddComic.dart
│   ├── Views.AddComicForm.dart
│   └── Views.Comics.dart
├── packages
│   └── // stuff installed by Dart pub
├── pubspec.lock
├── pubspec.yaml
├── test
│   └── // client-side tests
└── web
    ├── index.html
    ├── scripts
    │   └── dart.js
    └── stylesheets
        └── style.css
Given the inline <script> import and the weirdness with declaring my main.dart entry point, is the organization improvement worth it? I think it probably is. The main reason is that, in addition to keeping all the Dart code in one place, it is easier to test. I can write a simple test that uses the same import statement for main.dart and get a functioning test:
import 'package:unittest/unittest.dart';
import 'package:unittest/html_enhanced_config.dart';

import 'package:scripts/main.dart' as App;

class TestModel {
  String get url => '/test';
}

main() {
  useHtmlEnhancedConfiguration();

  group('reading', () {
    test('empty when no data previously stored', (){
      var it = new TestModel();
      expect(
        App.localSync('read', it),
        completion(equals([]))
      );
    });
  });
}
Just like that, I have a test passing against my main entry point:


I will mull it over a bit more, but I think I like this approach.


Day #602

Sunday, December 16, 2012

Yet Another Try at Dart Client Code Organization

‹prev | My Chain | next›

All right, let me give this one more try. After last night's failed experiment with code organization for Dart web applications, Ladislav Thon suggested an alternate approach. And I think it makes a good deal of sense.

His suggestion was to stop trying to put stuff in the public directory. Instead, I ought to make the web subdirectory of my application code the "public" directory from which all HTML, CSS, and Dart is served. I make that happen in my server.dart web server by updating the paths for my public directory handler. Then I move a bunch of code around, ending up with the following directory structure:
➜  dart-comics git:(master) ✗ tree app
app
├── lib
│   ├── Collections.Comics.dart
│   ├── main.dart
│   ├── ModalDialog.dart
│   ├── Models.ComicBook.dart
│   ├── Views.AddComic.dart
│   ├── Views.AddComicForm.dart
│   └── Views.Comics.dart
├── packages
│   ├── hipster_mvc -> /home/chris/.pub-cache/hosted/pub.dartlang.org/hipster_mvc-0.2.0/lib
│   ├── scripts -> /home/chris/repos/dart-comics/app/lib
│   └── unittest -> /home/chris/.pub-cache/hosted/pub.dartlang.org/unittest-0.2.8+2/lib
├── pubspec.lock
├── pubspec.yaml
├── test
│   ├── <test code here>
└── web
    ├── dart.js
    ├── index.html
    ├── packages -> /home/chris/repos/dart-comics/app/packages
    └── stylesheets
        ├── packages -> /home/chris/repos/dart-comics/app/packages
        └── style.css
I update the index.html to point to the new locations of the JavaScript kicker and the main.dart file:
<head>
  <title>Dart Comics</title>
  <link rel="stylesheet" href="/stylesheets/style.css">

  <script src="/dart.js"></script>
  <script src="/packages/scripts/main.dart" type="application/dart"></script>
</head>
But that main.dart won't work there because I am reaching under the Dart Pub covers by sourcing main.dart from the packages path. The primary problem being that all of the associated libraries are not found. So I move it into app/web as well.

That almost works, but I still need to update the import paths in main.dart to pull from the "scripts" package:
import 'package:scripts/Collections.Comics.dart' as Collections;
import 'package:scripts/Views.Comics.dart' as Views;
import 'package:scripts/Views.AddComic.dart' as Views;

import 'dart:html';
import 'dart:json';

import 'package:hipster_mvc/hipster_sync.dart';

main() {
  // ...
}
It is the "scripts" package by virtue of the name listed in the pubspec.yaml in the app directory:
name: scripts
dependencies:
  hipster_mvc: any
  unittest: any
Witht that, I have my application back in business:


I think I can live with that application structure. Then end result is:
app
├── lib
│   ├── Collections.Comics.dart
│   ├── ModalDialog.dart
│   ├── Models.ComicBook.dart
│   ├── Views.AddComic.dart
│   ├── Views.AddComicForm.dart
│   └── Views.Comics.dart
├── packages
│   ├── hipster_mvc -> /home/chris/.pub-cache/hosted/pub.dartlang.org/hipster_mvc-0.2.0/lib
│   ├── scripts -> /home/chris/repos/dart-comics/app/lib
│   └── unittest -> /home/chris/.pub-cache/hosted/pub.dartlang.org/unittest-0.2.8+2/lib
├── pubspec.lock
├── pubspec.yaml
├── test
│   ├── HipsterCollectionTest.dart
│   ├── index.html
│   ├── packages -> /home/chris/repos/dart-comics/app/packages
│   └── Views.AddComicForm_test.dart
└── web
    ├── dart.js
    ├── index.html
    ├── main.dart
    ├── packages -> /home/chris/repos/dart-comics/app/packages
    └── stylesheets
        ├── packages -> /home/chris/repos/dart-comics/app/packages
        └── style.css
The only thing about which I am unsure is including the main.dart file directly in the app/web directory. The old-fashioned way of doing that is putting it in a scripts directory. Maybe I am just stuck in my old ways and this is, in fact fine. Then again, it might be worth exploring a bit more tomorrow.

Update: It turns out that moving dart.js and main.dart into app/web/scripts works just fine. I just have to update the paths in index.html and re-run pub install to get the packages directory set up properly in app/web/scripts:
└── web
    ├── index.html
    ├── packages -> /home/chris/repos/dart-comics/app/packages
    ├── scripts
    │   ├── dart.js
    │   ├── main.dart
    │   └── packages -> /home/chris/repos/dart-comics/app/packages
    └── stylesheets
        ├── packages -> /home/chris/repos/dart-comics/app/packages
        └── style.css
That also explains why stylesheets gets a packages symlink.


Day #601

Saturday, December 15, 2012

Experimenting with Dart Application Locations

‹prev | My Chain | next›

From the very beginning, I have built my Dart web applications the same way that I build my JavaScript applications—with client-side code directly in my web server's public directory. Last night, I finally tried to test my application and found that maybe, just maybe there is a better way of doing this.

The solution that I came up with last night was to put my Dart application code in the appcode directory directly under the root level of my website. I then manually symlink the appcode/web subdirectory into my site's public directory:
➜  dart-comics git:(master) ✗ tree
.
├── appcode
│   ├── packages
│   │   ├── hipster_mvc -> /home/chris/.pub-cache/hosted/pub.dartlang.org/hipster_mvc-0.2.0/lib
│   │   └── unittest -> /home/chris/.pub-cache/hosted/pub.dartlang.org/unittest-0.2.8+2/lib
│   ├── pubspec.lock
│   ├── pubspec.yaml
│   ├── test
│   │   ├── index.html
│   │   ├── packages -> /home/chris/repos/dart-comics/appcode/packages
│   │   └── Views.AddComicForm_test.dart
│   └── web
│       ├── Collections.Comics.dart
│       ├── main.dart
│       ├── ModalDialog.dart
│       ├── Models.ComicBook.dart
│       ├── packages -> /home/chris/repos/dart-comics/appcode/packages
│       ├── Views.AddComic.dart
│       ├── Views.AddComicForm.dart
│       └── Views.Comics.dart
├── public
│   ├── images
│   ├── index.html
│   ├── scripts
│   │   ├── dart_comics -> ../../appcode/web
│   │   ├── dart.js
│   └── stylesheets
│       └── style.css
...
The nice thing about this approach is that I can still run my appcode tests locally, none of the tests or other associated code is available in the public subdirectory, and Dart Pub works fine with the appcode—including when appcode/web is symlinked into public.

This got me to thinking—perhaps I can move appcode out into its own repository and then use pub install to add it to the website. There is one way to find out.

So I create that repository in $HOME/repos/dart-comics-app. The only change that I make is to the name in the pubspec.yaml to reflect its application status:
name: dart_comics_app
dependencies:
  hipster_mvc: any
  unittest: any
Back in the website public/scripts directory, I create a pubspec.yaml that will pull this application into the site:
name: scripts
dependencies:
  dart_comics_app:
    git: /home/chris/repos/dart-comics-app
In public/scripts, I run pub install:
➜  scripts git:(master) ✗ pub install
Resolving dependencies... 
Warning: Package "dart_comics_app" does not have a "lib" directory so you will not be able to import any libraries from it.
Dependencies installed! 
That does not seem promising. And indeed, that did not install dart_comics_app in the packages directory or anywhere else:
➜  scripts git:(master) ✗ tree  
.
├── dart.js
├── packages
│   ├── hipster_mvc -> /home/chris/.pub-cache/hosted/pub.dartlang.org/hipster_mvc-0.2.0/lib
│   └── unittest -> /home/chris/.pub-cache/hosted/pub.dartlang.org/unittest-0.2.8+2/lib
├── pubspec.lock
└── pubspec.yaml
Bummer. It seems like that won't work.

The dart_comics_app is included in the generated pubspec.lock:
{"packages":
{"dart_comics_app":{
  "version":"0.0.0",
  "source":"git",
  "description":{
    "url":"/home/chris/repos/dart-comics-app",
    "ref":null,
    "resolved-ref":"35f4fe3cb59da75457671347b7cc43b8dd718ed7"
  }
},
"hipster_mvc":{"version":"0.2.0","source":"hosted","description":"hipster_mvc"},
"unittest":{"version":"0.2.8+2","source":"hosted","description":"unittest"}
}}
And it did get installed into my pub cache:
➜  scripts git:(master) ✗ ls -l ~/.pub-cache/git/dart_comics_app-35f4fe3cb59da75457671347b7cc43b8dd718ed7 
total 16
-rw-r--r-- 1 chris chris  170 Dec 15 20:31 pubspec.lock
-rw-r--r-- 1 chris chris   71 Dec 15 20:31 pubspec.yaml
drwxr-xr-x 2 chris chris 4096 Dec 15 20:31 test
drwxr-xr-x 2 chris chris 4096 Dec 15 20:31 web
But that did not result in actually seeing that in my website. I could manually symlink the web subdirectory from my pub cache, but I do not see any advantage in doing that over simply keeping the code in an appcode directory in the website proper.

Ah well, at the risk of invoking sour grapes, I am not sure that a separate code repository would have bought me much anyway. There is definitely something to be said for keeping it in the codebase along with the rest of the site.


Day #600

Friday, December 14, 2012

Organizing Dart App Code for Testing

‹prev | My Chain | next›

Up today I hope to figure out how to test a "real" Dart application. I have been using the unittest library to test some of the client-side code that I built to support Dart for Hipsters, but the code in question was not laid out to use packages from Dart Pub. That is, the code was placed directly in public/scripts rather than in public/scripts/web. Furthermore, I have not needed to account for pub packages in my tests so far—it all existed directly in public/scripts.

The code layout, including tests, that I now have in my sample app looks like:
.
├── packages
│   ├── dirty -> /home/chris/.pub-cache/hosted/pub.dartlang.org/dirty-0.0.2/lib
│   ├── unittest -> /home/chris/.pub-cache/hosted/pub.dartlang.org/unittest-0.2.8+2/lib
│   └── uuid -> /home/chris/.pub-cache/hosted/pub.dartlang.org/uuid-0.0.9/lib
├── public
│   ├── images
│   ├── index.html
│   ├── scripts
│   │   ├── packages
│   │   │   └── hipster_mvc -> /home/chris/.pub-cache/hosted/pub.dartlang.org/hipster_mvc-0.2.0/lib
│   │   ├── pubspec.lock
│   │   ├── pubspec.yaml
│   │   └── web
│   │       ├── Collections.Comics.dart
│   │       ├── main.dart
│   │       ├── Models.ComicBook.dart
│   │       ├── packages -> /home/chris/repos/dart-comics/public/scripts/packages
│   │       ├── Views.AddComicForm.dart
│   │       └── Views.Comics.dart
│   └── stylesheets
├── pubspec.yaml
└── test
    ├── HipsterCollectionTest.dart
    ├── index.html
    ├── packages -> /home/chris/repos/dart-comics/packages
    └── Views.AddComicForm_test.dart
I had been placing my client-side tests in the root-level test directory. Now that my client-side Dart code resides in public/scripts/web instead of public/scripts and, more importantly, now that the Hipster MVC classes are in the Pub's packages directory, the root level test directory will no longer work. I get errors like the following:
Failed to load a file file:///home/chris/repos/dart-comics/test/packages/hipster_mvc/hipster_view.dart Views.AddComicForm_test.dart:-1
GET file:///home/chris/repos/dart-comics/test/packages/hipster_mvc/hipster_view.dart  index.html:17
The problem is in the Views.AddComicForm.dart file:
library add_comic_form_view;

import 'dart:html';
import 'package:hipster_mvc/hipster_view.dart';

class AddComicForm extends HipsterView {
  // ...
}
The import of the hipster_view.dart library is looking in the top-level packages directory since the test resides in the top-level test directory. But the only packages that reside in the top-level packages directory are those that support the Dart web server.

I had resisted placing my tests in the public/test directory because then they would be in the public (i.e. publicly available) directory. But now it seem that I may not have a choice.

So, in the public/scripts directory, I add a test sub-directory and run pub install:
➜  scripts git:(master) ✗ mkdir test 
➜  scripts git:(master) ✗ pub install
Resolving dependencies...
Dependencies installed!
➜  scripts git:(master) ✗ ls -l test
total 0
lrwxrwxrwx 1 chris chris 53 Dec 14 23:15 packages -> /home/chris/repos/dart-comics/public/scripts/packages
This creates a link to the pub packages directory, so I seem to be on the right track.

I move my client-side tests from the root level into this new public test directory and adjust the import paths accordingly:
import 'package:unittest/unittest.dart';
import 'package:unittest/html_enhanced_config.dart';

import '../web/Views.AddComicForm.dart';

main() {
  // ...
}
With that, I have my tests passing again, now from the public directory:


I suppose the test code in the public directory is not a huge deal. Still it seems wrong to allow test code to be publicly available from the web server. I could use something like an .htacess file to prevent access to the test sub-directory, but that too seems less than ideal.

Instead, I move my application code, my tests and the associated pubspec.yaml file outside of public. For now, I place it all in a new directory named appcode in the application root. After re-running pub install, the appcode sub-directory looks like the following:
➜  appcode git:(master) ✗ tree   
.
├── packages
│   ├── hipster_mvc -> /home/chris/.pub-cache/hosted/pub.dartlang.org/hipster_mvc-0.2.0/lib
│   └── unittest -> /home/chris/.pub-cache/hosted/pub.dartlang.org/unittest-0.2.8+2/lib
├── pubspec.lock
├── pubspec.yaml
├── test
│   ├── HipsterCollectionTest.dart
│   ├── index.html
│   ├── packages -> /home/chris/repos/dart-comics/appcode/packages
│   └── Views.AddComicForm_test.dart
└── web
    ├── Collections.Comics.dart
    ├── main.dart
    ├── ModalDialog.dart
    ├── Models.ComicBook.dart
    ├── packages -> /home/chris/repos/dart-comics/appcode/packages
    ├── Views.AddComic.dart
    ├── Views.AddComicForm.dart
    └── Views.Comics.dart
The trick here is that, publicly, I only need the stuff in the web sub-directory. Well, I also need the pub packages, but I have them in the web sub-directory by virtue of the packages symlink that points to an absolute path. In other words, I can symlink just the web sub-directory into public:
➜  appcode git:(master) ✗ pwd
/home/chris/repos/dart-comics/appcode
➜  appcode git:(master) ✗ cd ../public/scripts 
➜  scripts git:(master) ✗ ln -s ../../appcode/web dart_comics
And that works. I still have my test suite passing, but now it is only accessible from a local filesystem. And, I still have my application working:


After considering it for a bit, I believe that this (or something like this) is what Dart Pub wants me to do. That is, I believe that including only the web sub-directory in a public folder is how Dart applications should be served up. The web sub-directory could come from an appcode sub-directory as I have done here. More interestingly, it could come a pub package—possibly from a git repository.

I think that is an idea worth pursuing a bit more. Tomorrow.


Day #599