Add timing info for tests and correct caching vs. run ratio

Now prints:

//foo:bar    (cached) PASSED in 0.1s

instead of:

//foo:bar    (1/0 cached) PASSED

Fixes #218.

--
MOS_MIGRATED_REVID=105210302
diff --git a/src/test/java/com/google/devtools/build/lib/runtime/AbstractCommandTest.java b/src/test/java/com/google/devtools/build/lib/runtime/AbstractCommandTest.java
new file mode 100644
index 0000000..7abb490
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/runtime/AbstractCommandTest.java
@@ -0,0 +1,118 @@
+// Copyright 2015 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.runtime;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
+import com.google.devtools.build.lib.testutil.MoreAsserts;
+import com.google.devtools.build.lib.util.ExitCode;
+import com.google.devtools.common.options.Option;
+import com.google.devtools.common.options.OptionsBase;
+import com.google.devtools.common.options.OptionsParser;
+import com.google.devtools.common.options.OptionsProvider;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link BlazeCommand}.
+ */
+@RunWith(JUnit4.class)
+public class AbstractCommandTest {
+
+  public static class FooOptions extends OptionsBase {
+    @Option(name = "foo", category = "one", defaultValue = "0")
+    public int foo;
+  }
+
+  public static class BarOptions extends OptionsBase {
+    @Option(name = "bar", category = "two", defaultValue = "42")
+    public int foo;
+
+    @Option(name = "baz", category = "one", defaultValue = "oops")
+    public String baz;
+  }
+
+  private static class ConcreteCommand implements BlazeCommand {
+    @Override
+    public ExitCode exec(CommandEnvironment env, OptionsProvider options) {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void editOptions(CommandEnvironment env, OptionsParser optionsParser) {}
+  }
+
+  @Command(name = "test_name",
+          help = "Usage: some funny usage for %{command} ...;\n\n%{options}; end",
+          options = {FooOptions.class, BarOptions.class},
+          shortDescription = "a short description",
+          allowResidue = false)
+  private static class TestCommand extends ConcreteCommand {}
+
+  @Test
+  public void testGetNameYieldsAnnotatedName() {
+    assertEquals("test_name",
+        new TestCommand().getClass().getAnnotation(Command.class).name());
+  }
+
+  @Test
+  public void testGetOptionsYieldsAnnotatedOptions() {
+    ConfiguredRuleClassProvider ruleClassProvider = new ConfiguredRuleClassProvider.Builder()
+        .build();
+
+    MoreAsserts.assertSameContents(optionClassesWithDefault(FooOptions.class, BarOptions.class),
+        BlazeCommandUtils.getOptions(
+            TestCommand.class, ImmutableList.<BlazeModule>of(), ruleClassProvider));
+  }
+
+  /***************************************************************************
+   * The tests below test how a command interacts with the dispatcher except *
+   * for execution, which is tested in {@link BlazeCommandDispatcherTest}.   *
+   ***************************************************************************/
+
+  @Command(name = "a", options = {FooOptions.class}, shortDescription = "", help = "")
+  private static class CommandA extends ConcreteCommand {}
+
+  @Command(name = "b", options = {BarOptions.class}, inherits = {CommandA.class},
+           shortDescription = "", help = "")
+  private static class CommandB extends ConcreteCommand {}
+
+  @Test
+  public void testOptionsAreInherited() {
+    ConfiguredRuleClassProvider ruleClassProvider = new ConfiguredRuleClassProvider.Builder()
+        .build();
+    MoreAsserts.assertSameContents(optionClassesWithDefault(FooOptions.class),
+        BlazeCommandUtils.getOptions(
+            CommandA.class, ImmutableList.<BlazeModule>of(), ruleClassProvider));
+    MoreAsserts.assertSameContents(optionClassesWithDefault(FooOptions.class, BarOptions.class),
+        BlazeCommandUtils.getOptions(
+            CommandB.class, ImmutableList.<BlazeModule>of(), ruleClassProvider));
+  }
+
+  private Collection<Class<?>> optionClassesWithDefault(Class<?>... optionClasses) {
+    List<Class<?>> result = new ArrayList<>();
+    Collections.addAll(result, optionClasses);
+    result.add(BlazeCommandEventHandler.Options.class);
+    result.add(CommonCommandOptions.class);
+    return result;
+  }
+}