Initial commit.
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..89f7747
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+.buildlog
+.DS_Store
+.idea
+.pub/
+.settings/
+build/
+packages
+pubspec.lock
diff --git a/.status b/.status
new file mode 100644
index 0000000..364ca4b
--- /dev/null
+++ b/.status
@@ -0,0 +1,4 @@
+# Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..0b1c48a
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,6 @@
+# Below is a list of people and organizations that have contributed
+# to the project. Names should be added to the list like so:
+#
+#   Name/Organization <email address>
+
+Google Inc. scheglov@google.com
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..2a2d63c
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Changelog
+
+## 0.0.1
+
+- Initial version
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..6f5e0ea
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,33 @@
+Want to contribute? Great! First, read this page (including the small print at
+the end).
+
+### Before you contribute
+Before we can use your code, you must sign the
+[Google Individual Contributor License Agreement](https://cla.developers.google.com/about/google-individual)
+(CLA), which you can do online. The CLA is necessary mainly because you own the
+copyright to your changes, even after your contribution becomes part of our
+codebase, so we need your permission to use and distribute your code. We also
+need to be sure of various other things—for instance that you'll tell us if you
+know that your code infringes on other people's patents. You don't have to sign
+the CLA until after you've submitted your code for review and a member has
+approved it, but you must do it before we can put your code into our codebase.
+
+Before you start working on a larger contribution, you should get in touch with
+us first through the issue tracker with your idea so that we can help out and
+possibly guide you. Coordinating up front makes it much easier to avoid
+frustration later on.
+
+### Code reviews
+All submissions, including submissions by project members, require review.
+
+### File headers
+All files in the project must start with the following header.
+
+    // Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+    // for details. All rights reserved. Use of this source code is governed by a
+    // BSD-style license that can be found in the LICENSE file.
+
+### The small print
+Contributions made by corporations are covered by a different agreement than the
+one above, the
+[Software Grant and Corporate Contributor License Agreement](https://developers.google.com/open-source/cla/corporate).
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..de31e1a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2015, the Dart project authors. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of Google Inc. nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..cbc7e63
--- /dev/null
+++ b/README.md
@@ -0,0 +1,26 @@
+# test_reflective_loader
+
+Support for discovering tests and test suites using reflection.
+
+It follows the xUnit style where each class is a test suite, and each method
+with the name prefix "test_" is a single text.
+
+Methods with names starting with "test_" are are run using test() function with
+the corresponding name. If the class defines methods setUp() or tearDown(),
+they are executed before / after each test correspondingly, even the test fails.
+
+Methods with names starting with "solo_test_" are run using solo_test() function.
+
+Methods with names starting with "fail_" are expected to fail.
+
+Methods with names starting with "solo_fail_" are run using solo_test() function
+and expected to fail.
+
+Method returning Future class instances are asynchronous, so tearDown() is
+executed after the returned Future completes.
+
+## Features and bugs
+
+Please file feature requests and bugs at the [issue tracker][tracker].
+
+[tracker]: https://github.com/dart-lang/test_reflective_loader/issues
diff --git a/lib/test_reflective_loader.dart b/lib/test_reflective_loader.dart
new file mode 100644
index 0000000..6ea195a
--- /dev/null
+++ b/lib/test_reflective_loader.dart
@@ -0,0 +1,121 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test_reflective_loader;
+
+@MirrorsUsed(metaTargets: 'ReflectiveTest')
+import 'dart:mirrors';
+import 'dart:async';
+
+import 'package:unittest/unittest.dart';
+
+/**
+ * Runs test methods existing in the given [type].
+ *
+ * Methods with names starting with `test` are run using [test] function.
+ * Methods with names starting with `solo_test` are run using [solo_test] function.
+ *
+ * Each method is run with a new instance of [type].
+ * So, [type] should have a default constructor.
+ *
+ * If [type] declares method `setUp`, it methods will be invoked before any test
+ * method invocation.
+ *
+ * If [type] declares method `tearDown`, it will be invoked after any test
+ * method invocation. If method returns [Future] to test some asyncronous
+ * behavior, then `tearDown` will be invoked in `Future.complete`.
+ */
+void runReflectiveTests(Type type) {
+  ClassMirror classMirror = reflectClass(type);
+  if (!classMirror.metadata.any((InstanceMirror annotation) =>
+  annotation.type.reflectedType == ReflectiveTest)) {
+    String name = MirrorSystem.getName(classMirror.qualifiedName);
+    throw new Exception('Class $name must have annotation "@reflectiveTest" '
+    'in order to be run by runReflectiveTests.');
+  }
+  String className = MirrorSystem.getName(classMirror.simpleName);
+  group(className, () {
+    classMirror.instanceMembers.forEach((symbol, memberMirror) {
+      // we need only methods
+      if (memberMirror is! MethodMirror || !memberMirror.isRegularMethod) {
+        return;
+      }
+      String memberName = MirrorSystem.getName(symbol);
+      // test_
+      if (memberName.startsWith('test_')) {
+        test(memberName, () {
+          return _runTest(classMirror, symbol);
+        });
+        return;
+      }
+      // solo_test_
+      if (memberName.startsWith('solo_test_')) {
+        solo_test(memberName, () {
+          return _runTest(classMirror, symbol);
+        });
+      }
+      // fail_test_
+      if (memberName.startsWith('fail_')) {
+        test(memberName, () {
+          return _runFailingTest(classMirror, symbol);
+        });
+      }
+      // solo_fail_test_
+      if (memberName.startsWith('solo_fail_')) {
+        solo_test(memberName, () {
+          return _runFailingTest(classMirror, symbol);
+        });
+      }
+    });
+  });
+}
+
+Future _invokeSymbolIfExists(InstanceMirror instanceMirror, Symbol symbol) {
+  var invocationResult = null;
+  try {
+    invocationResult = instanceMirror.invoke(symbol, []).reflectee;
+  } on NoSuchMethodError {}
+  if (invocationResult is Future) {
+    return invocationResult;
+  } else {
+    return new Future.value(invocationResult);
+  }
+}
+
+/**
+ * Run a test that is expected to fail, and confirm that it fails.
+ *
+ * This properly handles the following cases:
+ * - The test fails by throwing an exception
+ * - The test returns a future which completes with an error.
+ *
+ * However, it does not handle the case where the test creates an asynchronous
+ * callback using expectAsync(), and that callback generates a failure.
+ */
+Future _runFailingTest(ClassMirror classMirror, Symbol symbol) {
+  return new Future(() => _runTest(classMirror, symbol)).then((_) {
+    fail('Test passed - expected to fail.');
+  }, onError: (_) {});
+}
+
+_runTest(ClassMirror classMirror, Symbol symbol) {
+  InstanceMirror instanceMirror = classMirror.newInstance(new Symbol(''), []);
+  return _invokeSymbolIfExists(instanceMirror, #setUp)
+  .then((_) => instanceMirror.invoke(symbol, []).reflectee)
+  .whenComplete(() => _invokeSymbolIfExists(instanceMirror, #tearDown));
+}
+
+/**
+ * A marker annotation used to instruct dart2js to keep reflection information
+ * for the annotated classes.
+ */
+class ReflectiveTest {
+  const ReflectiveTest();
+}
+
+/**
+ * A marker annotation used to instruct dart2js to keep reflection information
+ * for the annotated classes.
+ */
+const ReflectiveTest reflectiveTest = const ReflectiveTest();
diff --git a/pubspec.yaml b/pubspec.yaml
new file mode 100644
index 0000000..b741dfc
--- /dev/null
+++ b/pubspec.yaml
@@ -0,0 +1,11 @@
+name: test_reflective_loader
+version: 0.0.1
+description: Support for discovering tests and test suites using reflection.
+author: Dart Team <misc@dartlang.org>
+homepage: https://github.com/dart-lang/test_reflective_loader
+
+environment:
+  sdk: '>=1.0.0 <2.0.0'
+
+dev_dependencies:
+  unittest: '>=0.9.0 <0.12.0'