feat: add file_basename_equals, file_extension_in matchers

These come from some of experience from porting the cc rules to use
rules_testing

* Also moves the matcher tests into their own file because the
  truth_tests.bzl file is getting large.
* Also switches the matcher tests to be basic tests, since they don't
  really require a target graph to be setup.

Fixed #44
diff --git a/lib/private/matching.bzl b/lib/private/matching.bzl
index 6093488..fb83e95 100644
--- a/lib/private/matching.bzl
+++ b/lib/private/matching.bzl
@@ -79,6 +79,37 @@
         match = lambda f: _match_parts_in_order(f.path, parts),
     )
 
+def _match_file_basename_equals(value):
+    """Match that a `File.basename` string equals `value`.
+
+    Args:
+        value: ([`str`]) the basename to match.
+
+    Returns:
+        [`Matcher`] instance
+    """
+    return struct(
+        desc = "<file basename equals '{}'>".format(value),
+        match = lambda f: f.basename == value,
+    )
+
+def _match_file_extension_in(values):
+    """Match that a `File.extension` string is any of `values`.
+
+    See also: `file_path_matches` for matching extensions that
+    have multiple parts, e.g. `*.tar.gz` or `*.so.*`.
+
+    Args:
+        values: ([`list`] of [`str`]) the extensions to match.
+
+    Returns:
+        [`Matcher`] instance
+    """
+    return struct(
+        desc = "<file extension is any of {}>".format(repr(values)),
+        match = lambda f: f.extension in values,
+    )
+
 def _match_is_in(values):
     """Match that the to-be-matched value is in a collection of other values.
 
@@ -190,7 +221,9 @@
     custom = _match_custom,
     equals_wrapper = _match_equals_wrapper,
     file_basename_contains = _match_file_basename_contains,
+    file_basename_equals = _match_file_basename_equals,
     file_path_matches = _match_file_path_matches,
+    file_extension_in = _match_file_extension_in,
     is_in = _match_is_in,
     never = _match_never,
     str_endswith = _match_str_endswith,
diff --git a/tests/matching/BUILD.bazel b/tests/matching/BUILD.bazel
new file mode 100644
index 0000000..3464e38
--- /dev/null
+++ b/tests/matching/BUILD.bazel
@@ -0,0 +1,3 @@
+load(":matching_tests.bzl", "matching_test_suite")
+
+matching_test_suite(name = "matching_tests")
diff --git a/tests/matching/matching_tests.bzl b/tests/matching/matching_tests.bzl
new file mode 100644
index 0000000..19d4fb2
--- /dev/null
+++ b/tests/matching/matching_tests.bzl
@@ -0,0 +1,98 @@
+"""Tests for matchers."""
+
+load("//lib:test_suite.bzl", "test_suite")
+load("//lib:truth.bzl", "matching")
+
+_tests = []
+
+def _file(path):
+    _, _, basename = path.rpartition("/")
+    _, _, extension = basename.rpartition(".")
+    return struct(
+        path = path,
+        basename = basename,
+        extension = extension,
+    )
+
+def _verify_matcher(env, matcher, match_true, match_false):
+    # Test postive match
+    env.expect.where(matcher = matcher.desc, value = match_true).that_bool(
+        matcher.match(match_true),
+        expr = "matcher.match(value)",
+    ).equals(True)
+
+    # Test negative match
+    env.expect.where(matcher = matcher.desc, value = match_false).that_bool(
+        matcher.match(match_false),
+        expr = "matcher.match(value)",
+    ).equals(False)
+
+def _contains_test(env):
+    _verify_matcher(
+        env,
+        matching.contains("x"),
+        match_true = "YYYxZZZ",
+        match_false = "zzzzz",
+    )
+
+_tests.append(_contains_test)
+
+def _file_basename_equals_test(env):
+    _verify_matcher(
+        env,
+        matching.file_basename_equals("bar.txt"),
+        match_true = _file("foo/bar.txt"),
+        match_false = _file("foo/bar.md"),
+    )
+
+_tests.append(_file_basename_equals_test)
+
+def _file_extension_in_test(env):
+    _verify_matcher(
+        env,
+        matching.file_extension_in(["txt", "rst"]),
+        match_true = _file("foo.txt"),
+        match_false = _file("foo.py"),
+    )
+
+_tests.append(_file_extension_in_test)
+
+def _is_in_test(env):
+    _verify_matcher(
+        env,
+        matching.is_in(["a", "b"]),
+        match_true = "a",
+        match_false = "z",
+    )
+
+_tests.append(_is_in_test)
+
+def _str_matchers_test(env):
+    _verify_matcher(
+        env,
+        matching.str_matches("f*b"),
+        match_true = "foobar",
+        match_false = "nope",
+    )
+
+    _verify_matcher(
+        env,
+        matching.str_endswith("123"),
+        match_true = "abc123",
+        match_false = "123xxx",
+    )
+
+    _verify_matcher(
+        env,
+        matching.str_startswith("true"),
+        match_true = "truechew",
+        match_false = "notbuck",
+    )
+
+_tests.append(_str_matchers_test)
+
+def matching_test_suite(name):
+    test_suite(
+        name = name,
+        basic_tests = _tests,
+    )
diff --git a/tests/truth_tests.bzl b/tests/truth_tests.bzl
index e0930e6..6951a86 100644
--- a/tests/truth_tests.bzl
+++ b/tests/truth_tests.bzl
@@ -1093,46 +1093,6 @@
 
 _suite.append(label_subject_test)
 
-def matchers_contains_test(name):
-    analysis_test(name, impl = _matchers_contains_test, target = "truth_tests_helper")
-
-def _matchers_contains_test(env, _target):
-    fake_env = _fake_env(env)
-    ut_asserts.true(env, matching.contains("x").match("YYYxZZZ"))
-    ut_asserts.false(env, matching.contains("x").match("zzzzz"))
-    _end(env, fake_env)
-
-_suite.append(matchers_contains_test)
-
-def matchers_str_matchers_test(name):
-    analysis_test(name, impl = _matchers_str_matchers_test, target = "truth_tests_helper")
-
-def _matchers_str_matchers_test(env, _target):
-    fake_env = _fake_env(env)
-
-    ut_asserts.true(env, matching.str_matches("f*b").match("foobar"))
-    ut_asserts.false(env, matching.str_matches("f*b").match("nope"))
-
-    ut_asserts.true(env, matching.str_endswith("123").match("abc123"))
-    ut_asserts.false(env, matching.str_endswith("123").match("123xxx"))
-
-    ut_asserts.true(env, matching.str_startswith("true").match("truechew"))
-    ut_asserts.false(env, matching.str_startswith("buck").match("notbuck"))
-    _end(env, fake_env)
-
-_suite.append(matchers_str_matchers_test)
-
-def matchers_is_in_test(name):
-    analysis_test(name, impl = _matchers_is_in_test, target = "truth_tests_helper")
-
-def _matchers_is_in_test(env, _target):
-    fake_env = _fake_env(env)
-    ut_asserts.true(env, matching.is_in(["a", "b"]).match("a"))
-    ut_asserts.false(env, matching.is_in(["x", "y"]).match("z"))
-    _end(env, fake_env)
-
-_suite.append(matchers_is_in_test)
-
 def runfiles_subject_test(name):
     analysis_test(name, impl = _runfiles_subject_test, target = "truth_tests_helper")