Skip to content

Static factories for creating Matchers using lambdas #440

Description

@rmcdouga

Having static factories that accept lambdas will reduce duplicated/boilerplate code when creating matchers. A flawed PR (#203) was created for this however it lacked unit tests and the implementation failed some standard tests when passed incompatible objects (TypeSafeDiagnosingMatcher is supposed to fail gracefully without an exception when passed an incompatible object but was throwing an exception instead).

I intend to create a new PR for this with unit tests and an implementation that conforms to the expected behaviour for TypeSafeDiagnosingMatcher.

Activity

  1. rmcdouga commented on Aug 24, 2025

    @rmcdouga
    Author

    I have a PR ready to create that has two static factories - one for TypeSafeDiagnosingMatcher and one for FeatureMatcher. I haven't created a static factory in all classes as I believe that these two are the primary ones used for creating custom Matcher implementations. If there are other classes that are commonly used for custom matchers, let me know and I can look into creating static factories for those as well.

    The static factory method signature for TypeSafeDiagnosingMatcher looks like this:

    public static <T> Matcher<T> matcher(Predicate<T> predicate, final String successDescription, final String failureDescription, Class<T> expectedType)

    A sample matcher looks like this:

    /**
     * A matcher that checks if a directory exists.
     * @return the file matcher
     */
    public static Matcher<Path> anExistingDirectory() {
        return matcher(Files::isDirectory, "an existing directory", "is not a directory", Path.class);
    }

    The static factory method signature for FeatureMatcher looks like this:

    public static <T,F> Matcher<T> matcher(final Matcher<F> expected, final Function<T, F> extractor, String featureDescription, String featureName, Class<T> expectedType)

    A sample FeatureMatcher matcher looks like this:

    /**
      * A matcher that checks if a file size matches an expected size.
      * @param expected matcher for the expected size
      * @return the file matcher
      */
    public static Matcher<Path> hasSize(final Matcher<Long> expected) {
        return FeatureMatcher.matcher(expected, p->toUncheckedEx(()->Files.size(p)), "A file with size", "size", Path.class);
    }

    instead of

     /**
       * A matcher that checks if a file size matches an expected size.
       * @param expected matcher for the expected size
       * @return the file matcher
       */
     public static Matcher<Path> hasSize(final Matcher<Long> expected) {
         return new FeatureMatcher<Path, Long>(expected, "A file with size", "size") {
                @Override protected Long featureValueOf(Path actual) { return toUncheckedEx(()->Files.size(actual)); }
        };
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions