<commit_before>/*
 * Copyright 2022 the original author or authors.
 *
 * 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 org.gradle.integtests.fixtures.logging.comparison;

import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

public class ExhaustiveLinesSearcher {
    private boolean matchBlankLines = false;
    private boolean showLessLikelyMatches = false;
    private boolean useUnifiedDiff = false;

    /**
     * Instructs empty lines to be considered matches when exhaustively building the list of potential matches.
     * <p>
     * Enabling this option could really explode the number of potential matches for common output cases
     * where blank lines exist in both the expected and actual lines.
     *
     * @return {@code this)
     */
    public ExhaustiveLinesSearcher matchBlankLines() {
        matchBlankLines = true;
        return this;
    }

    /**
     * Show potential matches which don't match as many expected lines as the best match.
     *
     * @return {@code this)
     */
    public ExhaustiveLinesSearcher showLessLikelyMatches() {
        showLessLikelyMatches = true;
        return this;
    }

    /**
     * Display the most likely potential match according to the git diff algorithm.
     * <p>
     * Enabling this option will only show a single match, regardless of how many potential matches
     * containing the same number of matching lines are found.
     *
     * @return {@code this}
     */
    public ExhaustiveLinesSearcher useUnifiedDiff() {
        useUnifiedDiff = true;
        return this;
    }

    public void assertLinesContainedIn(List<String> expectedLines, List<String> actualLines) throws LineSearchFailures.AbstractLineListComparisonFailure {
        if (expectedLines.isEmpty() && actualLines.isEmpty()) {
            return;
        }

        if (actualLines.size() < expectedLines.size()) {
            LineSearchFailures.insufficientSize(expectedLines, actualLines);
        }

        if (!findFirstCompleteMatch(expectedLines, actualLines).isPresent()) {
            exhaustiveSearch(expectedLines, actualLines);
        }
    }

    public void assertSameLines(List<String> expectedLines, List<String> actualLines) {
        if (expectedLines.isEmpty() && actualLines.isEmpty()) {
            return;
        }

        if (expectedLines.size() != actualLines.size()) {
            LineSearchFailures.differentSizes(expectedLines, actualLines);
        }

        if (!findFirstCompleteMatch(expectedLines, actualLines).orElse(-1).equals(0)) {
            exhaustiveSearch(expectedLines, actualLines);
        }
    }

    /**
     * Quickly attempts to find a complete match of the expected lines in the actual lines.
     * @param expectedLines
     * @param actualLines
     * @return the index of the first matching line, or {@link Optional#empty()} if no match was found
     */
    private Optional<Integer> findFirstCompleteMatch(List<String> expectedLines, List<String> actualLines) {
        for (int actualIdx = 0; actualIdx < actualLines.size(); actualIdx++) {
            if (isMatchingIndex(expectedLines, actualLines, actualIdx)) {
                return Optional.of(actualIdx);
            }
        }
        return Optional.empty();
    }

    /**
     * Checks whether the given actual line matches the expected line at the given actual index.
     * @param expectedLines
     * @param actualLines
     * @param actualMatchStartIdx
     * @return {@code true} if the actual index is a valid potential match position for the given number of expected lines,
     *  and the actual lines matches the corresponding expected lines beginning at that index
     */
    private boolean isMatchingIndex(List<String> expectedLines, List<String> actualLines, int actualMatchStartIdx) {
        for (int expectedIdx = 0; expectedIdx < expectedLines.size(); expectedIdx++) {<commit_msg>Prefer equals operator for primitives<commit_after>/*
 * Copyright 2022 the original author or authors.
 *
 * 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 org.gradle.integtests.fixtures.logging.comparison;

import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

public class ExhaustiveLinesSearcher {
    private boolean matchBlankLines = false;
    private boolean showLessLikelyMatches = false;
    private boolean useUnifiedDiff = false;

    /**
     * Instructs empty lines to be considered matches when exhaustively building the list of potential matches.
     * <p>
     * Enabling this option could really explode the number of potential matches for common output cases
     * where blank lines exist in both the expected and actual lines.
     *
     * @return {@code this)
     */
    public ExhaustiveLinesSearcher matchBlankLines() {
        matchBlankLines = true;
        return this;
    }

    /**
     * Show potential matches which don't match as many expected lines as the best match.
     *
     * @return {@code this)
     */
    public ExhaustiveLinesSearcher showLessLikelyMatches() {
        showLessLikelyMatches = true;
        return this;
    }

    /**
     * Display the most likely potential match according to the git diff algorithm.
     * <p>
     * Enabling this option will only show a single match, regardless of how many potential matches
     * containing the same number of matching lines are found.
     *
     * @return {@code this}
     */
    public ExhaustiveLinesSearcher useUnifiedDiff() {
        useUnifiedDiff = true;
        return this;
    }

    public void assertLinesContainedIn(List<String> expectedLines, List<String> actualLines) throws LineSearchFailures.AbstractLineListComparisonFailure {
        if (expectedLines.isEmpty() && actualLines.isEmpty()) {
            return;
        }

        if (actualLines.size() < expectedLines.size()) {
            LineSearchFailures.insufficientSize(expectedLines, actualLines);
        }

        if (!findFirstCompleteMatch(expectedLines, actualLines).isPresent()) {
            exhaustiveSearch(expectedLines, actualLines);
        }
    }

    public void assertSameLines(List<String> expectedLines, List<String> actualLines) {
        if (expectedLines.isEmpty() && actualLines.isEmpty()) {
            return;
        }

        if (expectedLines.size() != actualLines.size()) {
            LineSearchFailures.differentSizes(expectedLines, actualLines);
        }

        if (findFirstCompleteMatch(expectedLines, actualLines).orElse(-1) != 0) {
            exhaustiveSearch(expectedLines, actualLines);
        }
    }

    /**
     * Quickly attempts to find a complete match of the expected lines in the actual lines.
     * @param expectedLines
     * @param actualLines
     * @return the index of the first matching line, or {@link Optional#empty()} if no match was found
     */
    private Optional<Integer> findFirstCompleteMatch(List<String> expectedLines, List<String> actualLines) {
        for (int actualIdx = 0; actualIdx < actualLines.size(); actualIdx++) {
            if (isMatchingIndex(expectedLines, actualLines, actualIdx)) {
                return Optional.of(actualIdx);
            }
        }
        return Optional.empty();
    }

    /**
     * Checks whether the given actual line matches the expected line at the given actual index.
     * @param expectedLines
     * @param actualLines
     * @param actualMatchStartIdx
     * @return {@code true} if the actual index is a valid potential match position for the given number of expected lines,
     *  and the actual lines matches the corresponding expected lines beginning at that index
     */
    private boolean isMatchingIndex(List<String> expectedLines, List<String> actualLines, int actualMatchStartIdx) {
        for (int expectedIdx = 0; expectedIdx < expectedLines.size(); expectedIdx++) {
{'fraction_non_alphanumeric': 0.08121053777487482, 'fraction_numerical': 0.0028303940779446984, 'mean_word_length': 3.0293859649122807, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '146938', 'n_tokens_mistral': 2356, 'n_tokens_neox': 2327, 'n_words': 827}