Dart: Adds tests of a couple Dart examples.

We should keep the examples under //examples/dart in a working state.

R=johnmccutchan@google.com

Review URL: https://codereview.chromium.org/1571823002 .
diff --git a/examples/dart/example_tests.py b/examples/dart/example_tests.py
new file mode 100755
index 0000000..4039054
--- /dev/null
+++ b/examples/dart/example_tests.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Runs Dart example tests"""
+
+# This script runs tests of example Dart Mojo apps.
+# It looks for files named *_test.dart under subdirectories of
+# //examples/dart in the EXAMPLES list, below. These tests are
+# passed a command line argument --mojo-shell /path/to/mojo_shell that they
+# can use to run the example.
+
+import argparse
+import os
+import subprocess
+import sys
+
+SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
+SRC_DIR = os.path.dirname(os.path.dirname(SCRIPT_DIR))
+
+DART_SDK = os.path.join(SRC_DIR, 'third_party', 'dart-sdk', 'dart-sdk', 'bin')
+DART = os.path.join(DART_SDK, 'dart')
+
+# Add subdirectories of //examples/dart here.
+EXAMPLES = ['hello_world', 'wget']
+
+def FindTests(example):
+  tests = []
+  for root, _, files in os.walk(os.path.join(SCRIPT_DIR, example)):
+    for f in files:
+      if f.endswith('_test.dart'):
+        tests.append(os.path.join(root, f))
+  return tests
+
+def RunTests(tests, build_dir, package_root):
+  for test in tests:
+    test_path = os.path.join(SCRIPT_DIR, test)
+    subprocess.check_call(
+        [DART, '-p', package_root, '--checked', test_path,
+         '--mojo-shell', os.path.join(build_dir, 'mojo_shell'),])
+
+def main(build_dir, package_root):
+  for example in EXAMPLES:
+    tests = FindTests(example)
+    RunTests(tests, build_dir, package_root)
+
+if __name__ == '__main__':
+  parser = argparse.ArgumentParser(description="Run Dart example tests")
+  parser.add_argument('-b', '--build-dir',
+                      dest='build_dir',
+                      metavar='<build-directory>',
+                      type=str,
+                      required=True,
+                      help='The build output directory. E.g. out/Debug')
+  args = parser.parse_args()
+  package_root = os.path.join(
+      SRC_DIR, args.build_dir, 'gen', 'dart-pkg', 'packages')
+  sys.exit(main(args.build_dir, package_root))
diff --git a/examples/dart/hello_world/hello/lib/main.dart b/examples/dart/hello_world/hello/lib/main.dart
index 0d572cc..140f725 100644
--- a/examples/dart/hello_world/hello/lib/main.dart
+++ b/examples/dart/hello_world/hello/lib/main.dart
@@ -18,9 +18,12 @@
   void initialize(List<String> args, String url) {
     print("$url Hello");
 
+    var worldUrl = url.replaceAll("hello", "world");
+    print("Connecting to $worldUrl");
+
     // We expect to find the world mojo application at the same
     // path as this application.
-    var c = connectToApplication(url.replaceAll("hello", "world"));
+    var c = connectToApplication(worldUrl);
 
     // A call to close() here would cause this app to go down before the "world"
     // app has a chance to come up. Instead, we wait to close this app until
diff --git a/examples/dart/hello_world/hello/pubspec.yaml b/examples/dart/hello_world/hello/pubspec.yaml
index 0756a3d..6f1b88c 100644
--- a/examples/dart/hello_world/hello/pubspec.yaml
+++ b/examples/dart/hello_world/hello/pubspec.yaml
@@ -1 +1,10 @@
 name: mojo_dart_hello
+author: Chromium Authors <mojo-dev@googlegroups.com>
+description: A Hello World style Mojo example app.
+dependencies:
+  mojo_sdk: 0.2.9
+dev_dependencies:
+  args: ^0.13.2
+  path: ^1.3.9
+  test: ^0.12.6
+version: 0.0.1
diff --git a/examples/dart/hello_world/hello/test/hello_test.dart b/examples/dart/hello_world/hello/test/hello_test.dart
new file mode 100644
index 0000000..3ba3d19
--- /dev/null
+++ b/examples/dart/hello_world/hello/test/hello_test.dart
@@ -0,0 +1,72 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import "package:args/args.dart";
+import "package:path/path.dart" as path;
+import "package:test/test.dart";
+
+void main(List<String> args) {
+  final ArgParser parser = new ArgParser();
+  parser.addOption('mojo-shell',
+      help: 'Path to the Mojo shell.');
+  final ArgResults results = parser.parse(args);
+  final String shellPath = results['mojo-shell'];
+  final List<String> devtoolsFlags = results.rest;
+
+  test("Hello, .mojo!", () async {
+    final String mojoUrl = 'http://core.mojoapps.io/dart_hello.mojo';
+    final List<String> args = new List.from(devtoolsFlags)..add(mojoUrl);
+    final ProcessResult result = await Process.run(shellPath, args);
+    expect(result.exitCode, equals(0));
+    expect(result.stdout.contains('Hello'), isTrue);
+    expect(result.stdout.contains('World'), isTrue);
+  });
+
+  test("Hello, .dart!", () async {
+    final HttpServer server = await HttpServer.bind('127.0.0.1', 0);
+    final String scriptOrigin = path.normalize(
+        path.join(path.dirname(Platform.script.path), '..', '..'));
+    final String packageOrigin = path.normalize(
+        path.join(path.fromUri(Platform.packageRoot), '..'));
+
+    server.listen((HttpRequest request) async {
+      final String requestPath = request.uri.toFilePath();
+
+      String origin;
+      if (requestPath.startsWith('/packages')) {
+        origin = packageOrigin;
+      } else {
+        origin = scriptOrigin;
+      }
+
+      final String filePath =
+          path.join(origin, path.relative(requestPath, from: '/'));;
+      final File file = new File(filePath);
+      if (await file.exists()) {
+        try {
+          await file.openRead().pipe(request.response);
+        } catch (e) {
+          print(e);
+        }
+      } else {
+        request.response.statusCode = HttpStatus.NOT_FOUND;
+        request.response.close();
+      }
+    });
+
+    final String dartUrl =
+        'http://127.0.0.1:${server.port}/hello/lib/main.dart';
+
+    final List<String> args = new List.from(devtoolsFlags)..add(dartUrl);
+    final ProcessResult result = await Process.run(shellPath, args);
+    expect(result.exitCode, equals(0));
+    expect(result.stdout.contains('Hello'), isTrue);
+    expect(result.stdout.contains('World'), isTrue);
+    server.close();
+  });
+}
diff --git a/examples/dart/wget/pubspec.yaml b/examples/dart/wget/pubspec.yaml
index 8ae14c0..4ee2695 100644
--- a/examples/dart/wget/pubspec.yaml
+++ b/examples/dart/wget/pubspec.yaml
@@ -1,4 +1,10 @@
 name: mojo_dart_wget
+author: Chromium Authors <mojo-dev@googlegroups.com>
+description: A Mojo example that fetches a URL.
 dependencies:
-  mojo: ^0.4.0
-  mojo_services: ^0.4.0
+  mojo_sdk: 0.2.9
+dev_dependencies:
+  args: ^0.13.2
+  path: ^1.3.9
+  test: ^0.12.6
+version: 0.0.1
diff --git a/examples/dart/wget/test/wget_test.dart b/examples/dart/wget/test/wget_test.dart
new file mode 100644
index 0000000..85a0811
--- /dev/null
+++ b/examples/dart/wget/test/wget_test.dart
@@ -0,0 +1,90 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import "package:args/args.dart";
+import "package:path/path.dart" as path;
+import "package:test/test.dart";
+
+void main(List<String> args) {
+  final ArgParser parser = new ArgParser();
+  parser.addOption('mojo-shell',
+      help: 'Path to the Mojo shell.');
+  final ArgResults results = parser.parse(args);
+  final String shellPath = results['mojo-shell'];
+  final List<String> devtoolsFlags = results.rest;
+
+  HttpServer testServer;
+  String testServerUrl;
+  setUp(() async {
+    testServer = await HttpServer.bind('127.0.0.1', 0);
+    testServer.listen((HttpRequest request) {
+      request.response.write('Hello, world!');
+      request.response.close();
+    });
+    testServerUrl = 'http://127.0.0.1:${testServer.port}/';
+  });
+
+  tearDown(() async {
+    testServer.close();
+  });
+
+  test("Wget .mojo", () async {
+    final String mojoUrl = 'http://core.mojoapps.io/dart_wget.mojo';
+    final List<String> args = new List.from(devtoolsFlags)..add(mojoUrl);
+    args.add('--args-for=$mojoUrl $testServerUrl');
+
+    final ProcessResult result = await Process.run(shellPath, args);
+    expect(result.exitCode, equals(0));
+    expect(result.stdout.contains('Hello, world!'), isTrue);
+  });
+
+  test("Wget .dart", () async {
+    final HttpServer server = await HttpServer.bind('127.0.0.1', 0);
+    final String scriptOrigin = path.normalize(
+        path.join(path.dirname(Platform.script.path), '..', '..'));
+    final String packageOrigin = path.normalize(
+        path.join(path.fromUri(Platform.packageRoot), '..'));
+
+    server.listen((HttpRequest request) async {
+      final String requestPath = request.uri.toFilePath();
+
+      String origin;
+      if (requestPath.startsWith('/packages')) {
+        origin = packageOrigin;
+      } else {
+        origin = scriptOrigin;
+      }
+
+      final String filePath =
+          path.join(origin, path.relative(requestPath, from: '/'));;
+      final File file = new File(filePath);
+      if (await file.exists()) {
+        try {
+          await file.openRead().pipe(request.response);
+        } catch (e) {
+          print(e);
+        }
+      } else {
+        request.response.statusCode = HttpStatus.NOT_FOUND;
+        request.response.close();
+      }
+    });
+
+    final String dartUrl =
+        'http://127.0.0.1:${server.port}/wget/lib/main.dart';
+
+    final List<String> args = new List.from(devtoolsFlags)..add(dartUrl);
+    args.add('--args-for=$dartUrl $testServerUrl');
+
+    final ProcessResult result = await Process.run(shellPath, args);
+    expect(result.exitCode, equals(0));
+    expect(result.stdout.contains('Hello, world!'), isTrue);
+
+    server.close();
+  });
+}
diff --git a/mojo/tools/get_test_list.py b/mojo/tools/get_test_list.py
index 53d93ec..11c416d 100755
--- a/mojo/tools/get_test_list.py
+++ b/mojo/tools/get_test_list.py
@@ -177,21 +177,30 @@
             "--build-dir=" + build_dir,
             "--dart-exe=third_party/dart-sdk/dart-sdk/bin/dart"])
 
-  # Dart mojom package generate.dart script tests:
-  if target_os == Config.OS_LINUX and ShouldRunTest(Config.TEST_TYPE_DEFAULT):
-    AddEntry("Dart mojom package generate tests",
-        [os.path.join("third_party", "dart-sdk", "dart-sdk", "bin", "dart"),
-         "--checked",
-         "-p", os.path.join(build_dir, "gen", "dart-pkg", "packages"),
-         os.path.join(
-           "mojo", "dart", "packages", "mojom", "test", "generate_test.dart")])
+  if target_os == Config.OS_LINUX:
+    # Dart mojom package generate.dart script tests:
+    if ShouldRunTest(Config.TEST_TYPE_DEFAULT):
+      AddEntry("Dart mojom package generate tests",
+          [os.path.join("third_party", "dart-sdk", "dart-sdk", "bin", "dart"),
+           "--checked",
+           "-p", os.path.join(build_dir, "gen", "dart-pkg", "packages"),
+           os.path.join(
+             "mojo", "dart", "packages", "mojom", "test",
+             "generate_test.dart")])
 
-  if target_os == Config.OS_LINUX and ShouldRunTest(Config.TEST_TYPE_DEFAULT):
-    AddEntry("Dart snapshotter test",
-        ["python",
-         os.path.join("mojo", "dart", "embedder", "snapshotter", "test",
-                      "dart_snapshotter_test.py"),
-         "--build-dir=" + build_dir])
+    # Tests of Dart examples.
+    if ShouldRunTest(Config.TEST_TYPE_DEFAULT):
+      AddEntry("Dart examples tests",
+          ["python", os.path.join("examples", "dart", "example_tests.py"),
+           "--build-dir", build_dir])
+
+    # Test of Dart's snapshotter.
+    if ShouldRunTest(Config.TEST_TYPE_DEFAULT):
+      AddEntry("Dart snapshotter test",
+          ["python",
+           os.path.join("mojo", "dart", "embedder", "snapshotter", "test",
+                        "dart_snapshotter_test.py"),
+           "--build-dir=" + build_dir])
 
   # Dart analyzer test
   if ShouldRunTest(Config.TEST_TYPE_DEFAULT, "analyze-dart"):