Merge pull request #15 from markovuksanovic/feature/result-emission

Benchmark harness can emit results.
diff --git a/lib/benchmark_harness.dart b/lib/benchmark_harness.dart
index c921fa9..5cea7bf 100644
--- a/lib/benchmark_harness.dart
+++ b/lib/benchmark_harness.dart
@@ -1,3 +1,4 @@
 library benchmark_harness;
 
 part 'src/benchmark_base.dart';
+part 'src/score_emitter.dart';
diff --git a/lib/src/benchmark_base.dart b/lib/src/benchmark_base.dart
index f48b93d..f741da6 100644
--- a/lib/src/benchmark_base.dart
+++ b/lib/src/benchmark_base.dart
@@ -4,9 +4,13 @@
 
 class BenchmarkBase {
   final String name;
+  final ScoreEmitter emitter;
 
   // Empty constructor.
-  const BenchmarkBase(String name) : this.name = name;
+  const BenchmarkBase(String name,
+      { ScoreEmitter emitter: const PrintEmitter() })
+      : this.name = name,
+        this.emitter = emitter;
 
   // The benchmark code.
   // This function is not used, if both [warmup] and [exercise] are overwritten.
@@ -58,8 +62,7 @@
   }
 
   void report() {
-    double score = measure();
-    print("$name(RunTime): $score us.");
+    emitter.emit(name, measure());
   }
 
 }
diff --git a/lib/src/score_emitter.dart b/lib/src/score_emitter.dart
new file mode 100644
index 0000000..0e8af2d
--- /dev/null
+++ b/lib/src/score_emitter.dart
@@ -0,0 +1,13 @@
+part of benchmark_harness;
+
+abstract class ScoreEmitter {
+  void emit(String testName, double value);
+}
+
+class PrintEmitter implements ScoreEmitter {
+  const PrintEmitter();
+
+  void emit(String testName, double value) {
+    print("$testName(RunTime): $value us.");
+  }
+}
\ No newline at end of file
diff --git a/pubspec.yaml b/pubspec.yaml
index f8d6c21..db341d0 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -5,3 +5,5 @@
 homepage: http://www.dartlang.org
 dependencies:
   browser: any
+dev_dependencies:
+  unittest: any
diff --git a/test/fixed-unittest.dart b/test/fixed-unittest.dart
new file mode 100644
index 0000000..2c1ed53
--- /dev/null
+++ b/test/fixed-unittest.dart
@@ -0,0 +1,9 @@
+library unittest;
+
+import 'package:unittest/unittest.dart';
+
+export 'package:unittest/unittest.dart';
+
+// Jasmine-like syntax for unittest.
+void describe(String spec, TestFunction body) => group(spec, body);
+void it(String spec, TestFunction body) => test(spec, body);
diff --git a/test/result_emitter_test.dart b/test/result_emitter_test.dart
new file mode 100644
index 0000000..4975835
--- /dev/null
+++ b/test/result_emitter_test.dart
@@ -0,0 +1,49 @@
+library remote;
+
+import 'fixed-unittest.dart';
+import 'package:unittest/mock.dart';
+import 'package:benchmark_harness/benchmark_harness.dart';
+
+
+void main() {
+  benchmarkHarnessTest();
+}
+
+class MockResultEmitter extends Mock implements ScoreEmitter {
+  var hasEmitted = false;
+
+  MockResultEmitter() {
+    when(callsTo('emit')).alwaysCall(fakeEmit);
+  }
+
+  void fakeEmit(String name, double value) {
+    hasEmitted = true;
+  }
+}
+
+// Create a new benchmark which has an emitter.
+class BenchmarkWithResultEmitter extends BenchmarkBase {
+  const BenchmarkWithResultEmitter(ScoreEmitter emitter) : super("Template", emitter: emitter);
+
+  void run() { }
+
+  void setup() { }
+
+  void teardown() { }
+}
+
+benchmarkHarnessTest() {
+  MockResultEmitter createMockEmitter() {
+    MockResultEmitter emitter = new MockResultEmitter();
+    return emitter;
+  }
+
+  describe('ResultEmitter', () {
+    it('should be called when emitter is provided', () {
+      MockResultEmitter emitter = createMockEmitter();
+      var testBenchmark = new BenchmarkWithResultEmitter(emitter);
+      testBenchmark.report();
+      emitter.getLogs(callsTo('emit')).verify(happenedOnce);
+    });
+  });
+}
\ No newline at end of file