<commit_before>/*
 * Released under the terms of the MIT License.
 *
 * Copyright (c) 2017 objecttrouve.org <<EMAIL>>
 *
 */

package org.objecttrouve.testing.matchers.fluentatts;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;

import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;

/**
 * <p>
 * {@link org.hamcrest.TypeSafeMatcher} implementation
 * offering a fluent-style lambda-accepting API
 * to match multiple properties of the <i>actual</i> object
 * simultaneously.
 * </p>
 * <p>
 * Example:
 * </p>
 *
 * <pre>
 * <code>
 *
 * package org.objecttrouve.testing.matchers.fluentatts;
 *
 * import org.junit.Ignore;
 * import org.junit.Test;
 *
 * import static org.hamcrest.CoreMatchers.is;
 * import static org.hamcrest.MatcherAssert.assertThat;
 * // Use the factory method for syntactic sugaring and configurability!
 * import static org.objecttrouve.testing.matchers.ConvenientMatchers.a;
 * import static org.objecttrouve.testing.matchers.fluentatts.Attribute.attribute;
 *
 * public class Example {
 *
 * static class Result {
 * private final String stringValue;
 * private final int intValue;
 * private final boolean boolValue;
 *
 * Result(final String stringValue, final int intValue, final boolean boolValue) {
 * this.stringValue = stringValue;
 * this.intValue = intValue;
 * this.boolValue = boolValue;
 * }
 *
 *
 * public String getStringValue() {
 * return stringValue;
 * }
 *
 * public int getIntValue() {
 * return intValue;
 * }
 *
 * public boolean isBoolValue() {
 * return boolValue;
 * }
 * }
 *
 * static Result methodWithResult(final String s, final int i, final boolean b){
 * return new Result(s, i, b);
 * }
 *
 * private static final Attribute&lt;Result, String&gt; stringValue = attribute("stringValue", Result::getStringValue);
 * private static final Attribute&lt;Result, Integer&gt; intValue = attribute("intValue", Result::getIntValue);
 * private static final Attribute&lt;Result, Boolean&gt; boolValue = attribute("booleanValue", Result::isBoolValue);
 *
 * {@literal @}Test
 * public void testSomething(){
 *
 * final Result result = methodWithResult("2=", 1, false);
 *
 * assertThat(result, is(//
 * a(Result.class)//
 * .with(stringValue, "1=") //
 * .with(intValue, is(2)) //
 * .with(boolValue, true)
 * ));
 * }
 *
 * }
 *
 *
 * </code>
 * </pre>
 *
 */
public class FluentAttributeMatcher<T> extends TypeSafeMatcher<T> {


    private final List<Expectation<T, ?>> expectations = new LinkedList<>();
    private final List<Result> results = new LinkedList<>();
    private final boolean tracking;

    /**
     * New instance.
     *
     * @param tracking attempt (expensively!) to create human-readable descriptions of attribute lambdas
     */
    public FluentAttributeMatcher(final boolean tracking) {
        this.tracking = tracking;
    }

    /**
     * Builder method to set up checking {@code Objects.equals(getter.apply(), expectedValue)}.
     *
     * @param expectedValue the expected value
     * @param getter        Function returning the value to be checked
     * @param <O>           type of the value returned by the getter
     * @return FluentAttributeMatcher
     */
    public <O> FluentAttributeMatcher<T> with(final Function<T, O> getter, final O expectedValue) {
        check(getter);
        expectations.add(new Expectation<>(null, getter, (actual) -> Objects.equals(actual, expectedValue), expectedValue, null));
        return this;
    }

    /**
     * Builder method to set up checking {@code Objects.equals(attribute.getGetter().apply(), expectedValue)}.
     * The name of the attribute is used in the description in case there is a mismatch.
     * If the @param expectedValue is a {@link org.hamcrest.Matcher}, delegates to {@link FluentAttributeMatcher#withMatching(org.objecttrouve.testing.matchers.fluentatts.Attribute, org.hamcrest.Matcher)}.
     *
     * @param expectedValue the expected value
     * @param attribute     {@link org.objecttrouve.testing.matchers.fluentatts.Attribute} describing the property to be checked.
     * @param <O>           type of the value returned by the getter
     * @return FluentAttributeMatcher
     */
    public <O> FluentAttributeMatcher<T> with(final Attribute<T, O> attribute, final Object expectedValue) {
        check(attribute);
        if (expectedValue instanceof Matcher) {
            //noinspection unchecked
            return withMatching(attribute, (Matcher<O>) expectedValue);
        } else {
            //noinspection unchecked
            return withValue(attribute, (O) expectedValue);
        }
    }

    /**
     * Builder method to set up checking {@code Objects.equals(attribute.getGetter().apply(), expectedValue)}.
     * The name of the attribute is used in the description in case there is a mismatch.
     *
     * @param expectedValue the expected value
     * @param attribute     {@link org.objecttrouve.testing.matchers.fluentatts.Attribute} describing the property to be checked.
     * @param <O>           type of the value returned by the getter
     * @return FluentAttributeMatcher
     */
    @SuppressWarnings("WeakerAccess")
    public <O> FluentAttributeMatcher<T> withValue(final Attribute<T, O> attribute, final O expectedValue) {
        check(attribute);
        expectations.add(new Expectation<>(attribute.getName(), attribute.getGetter(), (actual) -> Objects.equals(actual, expectedValue), expectedValue, null));
        return this;
    }

    /**
     * Builder method to set up checking {@code matcher.matches(getter.apply())}.
     *
     * @param matcher {@link org.hamcrest.Matcher} to be applied
     * @param getter  Function returning the value to be checked
     * @param <O>     type of the value returned by the getter
     * @return FluentAttributeMatcher
     */
    @SuppressWarnings("WeakerAccess")
    public <O> FluentAttributeMatcher<T> having(final Function<T, O> getter, final Matcher<O> matcher) {
        check(getter);
        check(matcher);
        expectations.add(new Expectation<>(null, getter, matcher::matches, null, matcher));
        return this;
    }

    /**<commit_msg>Deprecated self-describing 'with' and 'having'.<commit_after>/*
 * Released under the terms of the MIT License.
 *
 * Copyright (c) 2017 objecttrouve.org <<EMAIL>>
 *
 */

package org.objecttrouve.testing.matchers.fluentatts;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;

import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;

/**
 * <p>
 * {@link org.hamcrest.TypeSafeMatcher} implementation
 * offering a fluent-style lambda-accepting API
 * to match multiple properties of the <i>actual</i> object
 * simultaneously.
 * </p>
 * <p>
 * Example:
 * </p>
 *
 * <pre>
 * <code>
 *
 * package org.objecttrouve.testing.matchers.fluentatts;
 *
 * import org.junit.Ignore;
 * import org.junit.Test;
 *
 * import static org.hamcrest.CoreMatchers.is;
 * import static org.hamcrest.MatcherAssert.assertThat;
 * // Use the factory method for syntactic sugaring and configurability!
 * import static org.objecttrouve.testing.matchers.ConvenientMatchers.a;
 * import static org.objecttrouve.testing.matchers.fluentatts.Attribute.attribute;
 *
 * public class Example {
 *
 * static class Result {
 * private final String stringValue;
 * private final int intValue;
 * private final boolean boolValue;
 *
 * Result(final String stringValue, final int intValue, final boolean boolValue) {
 * this.stringValue = stringValue;
 * this.intValue = intValue;
 * this.boolValue = boolValue;
 * }
 *
 *
 * public String getStringValue() {
 * return stringValue;
 * }
 *
 * public int getIntValue() {
 * return intValue;
 * }
 *
 * public boolean isBoolValue() {
 * return boolValue;
 * }
 * }
 *
 * static Result methodWithResult(final String s, final int i, final boolean b){
 * return new Result(s, i, b);
 * }
 *
 * private static final Attribute&lt;Result, String&gt; stringValue = attribute("stringValue", Result::getStringValue);
 * private static final Attribute&lt;Result, Integer&gt; intValue = attribute("intValue", Result::getIntValue);
 * private static final Attribute&lt;Result, Boolean&gt; boolValue = attribute("booleanValue", Result::isBoolValue);
 *
 * {@literal @}Test
 * public void testSomething(){
 *
 * final Result result = methodWithResult("2=", 1, false);
 *
 * assertThat(result, is(//
 * a(Result.class)//
 * .with(stringValue, "1=") //
 * .with(intValue, is(2)) //
 * .with(boolValue, true)
 * ));
 * }
 *
 * }
 *
 *
 * </code>
 * </pre>
 *
 */
public class FluentAttributeMatcher<T> extends TypeSafeMatcher<T> {


    private final List<Expectation<T, ?>> expectations = new LinkedList<>();
    private final List<Result> results = new LinkedList<>();
    private final boolean tracking;

    /**
     * New instance.
     *
     * @param tracking attempt (expensively!) to create human-readable descriptions of attribute lambdas
     */
    public FluentAttributeMatcher(final boolean tracking) {
        this.tracking = tracking;
    }

    /**
     * Builder method to set up checking {@code Objects.equals(getter.apply(), expectedValue)}.
     *
     * @param expectedValue the expected value
     * @param getter        Function returning the value to be checked
     * @param <O>           type of the value returned by the getter
     * @return FluentAttributeMatcher
     * @deprecated Method will be removed with version 1.0.0. Use {@link FluentAttributeMatcher#with(org.objecttrouve.testing.matchers.fluentatts.Attribute, java.lang.Object)}.
     */
    @Deprecated
    public <O> FluentAttributeMatcher<T> with(final Function<T, O> getter, final O expectedValue) {
        check(getter);
        expectations.add(new Expectation<>(null, getter, (actual) -> Objects.equals(actual, expectedValue), expectedValue, null));
        return this;
    }

    /**
     * Builder method to set up checking {@code Objects.equals(attribute.getGetter().apply(), expectedValue)}.
     * The name of the attribute is used in the description in case there is a mismatch.
     * If the @param expectedValue is a {@link org.hamcrest.Matcher}, delegates to {@link FluentAttributeMatcher#withMatching(org.objecttrouve.testing.matchers.fluentatts.Attribute, org.hamcrest.Matcher)}.
     *
     * @param expectedValue the expected value
     * @param attribute     {@link org.objecttrouve.testing.matchers.fluentatts.Attribute} describing the property to be checked.
     * @param <O>           type of the value returned by the getter
     * @return FluentAttributeMatcher
     */
    public <O> FluentAttributeMatcher<T> with(final Attribute<T, O> attribute, final Object expectedValue) {
        check(attribute);
        if (expectedValue instanceof Matcher) {
            //noinspection unchecked
            return withMatching(attribute, (Matcher<O>) expectedValue);
        } else {
            //noinspection unchecked
            return withValue(attribute, (O) expectedValue);
        }
    }

    /**
     * Builder method to set up checking {@code Objects.equals(attribute.getGetter().apply(), expectedValue)}.
     * The name of the attribute is used in the description in case there is a mismatch.
     *
     * @param expectedValue the expected value
     * @param attribute     {@link org.objecttrouve.testing.matchers.fluentatts.Attribute} describing the property to be checked.
     * @param <O>           type of the value returned by the getter
     * @return FluentAttributeMatcher
     */
    @SuppressWarnings("WeakerAccess")
    public <O> FluentAttributeMatcher<T> withValue(final Attribute<T, O> attribute, final O expectedValue) {
        check(attribute);
        expectations.add(new Expectation<>(attribute.getName(), attribute.getGetter(), (actual) -> Objects.equals(actual, expectedValue), expectedValue, null));
        return this;
    }

    /**
     * Builder method to set up checking {@code matcher.matches(getter.apply())}.
     *
     * @param matcher {@link org.hamcrest.Matcher} to be applied
     * @param getter  Function returning the value to be checked
     * @param <O>     type of the value returned by the getter
     * @return FluentAttributeMatcher
     * @deprecated Method will be removed with version 1.0.0. Use {@link FluentAttributeMatcher#with(org.objecttrouve.testing.matchers.fluentatts.Attribute, java.lang.Object)}.
     */
    @SuppressWarnings("WeakerAccess")
    @Deprecated
    public <O> FluentAttributeMatcher<T> having(final Function<T, O> getter, final Matcher<O> matcher) {
        check(getter);
        check(matcher);
        expectations.add(new Expectation<>(null, getter, matcher::matches, null, matcher));
        return this;
    }

    /**
{'fraction_non_alphanumeric': 0.11552234158492916, 'fraction_numerical': 0.001712595360423478, 'mean_word_length': 3.4716324399582317, 'pattern_counts': {'":': 0, '<': 83, '<?xml version=': 0, '>': 87, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3960890', 'n_tokens_mistral': 3669, 'n_tokens_neox': 3649, 'n_words': 1052}