Expose target_under_test's bin and genfiles path (#202)

The output directories for the target under test may differ when the target is under a config transition (config_settings is passed to analysistest.make). Since analysis tests may assert about the command-line of generated actions, and those command-lines may contain paths to output files, this is useful information to expose.
diff --git a/lib/unittest.bzl b/lib/unittest.bzl
index 873d8f0..718eca4 100644
--- a/lib/unittest.bzl
+++ b/lib/unittest.bzl
@@ -126,11 +126,16 @@
         toolchains = [TOOLCHAIN_TYPE],
     )
 
-_ActionInfo = provider(fields = ["actions"])
+_ActionInfo = provider(fields = ["actions", "bin_path", "genfiles_path"])
 
 def _action_retrieving_aspect_impl(target, ctx):
-    _ignore = [ctx]
-    return [_ActionInfo(actions = target.actions)]
+    return [
+        _ActionInfo(
+            actions = target.actions,
+            bin_path = ctx.bin_dir.path,
+            genfiles_path = ctx.genfiles_dir.path,
+        ),
+    ]
 
 _action_retrieving_aspect = aspect(
     attr_aspects = [],
@@ -463,8 +468,29 @@
     """
 
     # Validate?
-    dep = _target_under_test(env)
-    return dep[_ActionInfo].actions
+    return _target_under_test(env)[_ActionInfo].actions
+
+def _target_bin_dir_path(env):
+    """Returns ctx.bin_dir.path for the target under test.
+
+    Args:
+      env: The test environment returned by `analysistest.begin`.
+
+    Returns:
+      Output bin dir path string.
+    """
+    return _target_under_test(env)[_ActionInfo].bin_path
+
+def _target_genfiles_dir_path(env):
+    """Returns ctx.genfiles_dir.path for the target under test.
+
+    Args:
+      env: The test environment returned by `analysistest.begin`.
+
+    Returns:
+      Output genfiles dir path string.
+    """
+    return _target_under_test(env)[_ActionInfo].genfiles_path
 
 def _target_under_test(env):
     """Returns the target under test.
@@ -506,5 +532,7 @@
     end = _end_analysis_test,
     fail = _fail,
     target_actions = _target_actions,
+    target_bin_dir_path = _target_bin_dir_path,
+    target_genfiles_dir_path = _target_genfiles_dir_path,
     target_under_test = _target_under_test,
 )
diff --git a/tests/unittest_tests.bzl b/tests/unittest_tests.bzl
index e25e4da..e3ca45b 100644
--- a/tests/unittest_tests.bzl
+++ b/tests/unittest_tests.bzl
@@ -177,6 +177,63 @@
     _inspect_actions_test,
 )
 
+########################################
+####### inspect_output_dirs_test #######
+########################################
+_OutputDirInfo = provider(fields = ["bin_path", "genfiles_path"])
+
+def _inspect_output_dirs_test(ctx):
+    """Test verifying output directories used by a test."""
+    env = analysistest.begin(ctx)
+
+    # Assert that the output dirs observed by the aspect added by analysistest
+    # are the same as those observed by the rule directly, even when that's
+    # under a config transition and therefore not the same as the output
+    # dirs used by the test rule.
+    bin_path = analysistest.target_bin_dir_path(env)
+    genfiles_path = analysistest.target_genfiles_dir_path(env)
+    target_under_test = analysistest.target_under_test(env)
+    asserts.false(env, not bin_path, "bin dir path not found.")
+    asserts.false(env, not genfiles_path, "genfiles path not found.")
+    asserts.false(
+        env,
+        bin_path == ctx.bin_dir.path,
+        "bin dir path expected to differ between test and target_under_test.",
+    )
+    asserts.false(
+        env,
+        genfiles_path == ctx.genfiles_dir.path,
+        "genfiles dir path expected to differ between test and target_under_test.",
+    )
+    asserts.equals(env, bin_path, target_under_test[_OutputDirInfo].bin_path)
+    asserts.equals(
+        env,
+        genfiles_path,
+        target_under_test[_OutputDirInfo].genfiles_path,
+    )
+    return analysistest.end(env)
+
+def _inspect_output_dirs_fake_rule(ctx):
+    return [
+        _OutputDirInfo(
+            bin_path = ctx.bin_dir.path,
+            genfiles_path = ctx.genfiles_dir.path,
+        ),
+    ]
+
+inspect_output_dirs_fake_rule = rule(
+    implementation = _inspect_output_dirs_fake_rule,
+)
+
+inspect_output_dirs_test = analysistest.make(
+    _inspect_output_dirs_test,
+    # The output directories differ between the test and target under test when
+    # the target under test is under a config transition.
+    config_settings = {
+        "//command_line_option:compilation_mode": "fastbuild",
+    },
+)
+
 #########################################
 
 def unittest_passing_tests_suite():
@@ -226,3 +283,12 @@
         name = "inspect_actions_fake_target",
         tags = ["manual"],
     )
+
+    inspect_output_dirs_test(
+        name = "inspect_output_dirs_test",
+        target_under_test = ":inspect_output_dirs_fake_target",
+    )
+    inspect_output_dirs_fake_rule(
+        name = "inspect_output_dirs_fake_target",
+        tags = ["manual"],
+    )