<commit_before>package xyz.capybara.clamav.commands.scan;

import xyz.capybara.clamav.commands.scan.result.ScanResult;
import xyz.capybara.clamav.exceptions.InvalidResponseException;
import xyz.capybara.clamav.exceptions.ScanFailureException;
import xyz.capybara.clamav.commands.Command;
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collector;

public abstract class ScanCommand extends Command<ScanResult> {

    private static final Pattern RESPONSE_OK = Pattern.compile(
            "(.+) OK$",
            Pattern.UNIX_LINES
    );
    private static final Pattern RESPONSE_VIRUS_FOUND = Pattern.compile(
            "(.+) FOUND$",
            Pattern.MULTILINE & Pattern.UNIX_LINES
    );
    private static final Pattern RESPONSE_ERROR = Pattern.compile(
            "(.+) ERROR",
            Pattern.UNIX_LINES
    );
    private static final Pattern RESPONSE_VIRUS_FOUND_LINE = Pattern.compile(
            "(.+: )?(?<filePath>.+): (?<virus>.+) FOUND$",
            Pattern.UNIX_LINES
    );

    @Override
    protected ScanResult parseResponse(String responseString) {
        if (RESPONSE_OK.matcher(responseString).matches()) {
            return new ScanResult(ScanResult.Status.OK);
        }
        if (RESPONSE_VIRUS_FOUND.matcher(responseString).find()) {
            // add every found viruses to the scan result, grouped by infected file
            Map<String, Collection<String>> foundViruses = Arrays.stream(responseString.split("\n"))
                    .map(line -> {
                        Matcher matcher = RESPONSE_VIRUS_FOUND_LINE.matcher(line);
                        assert matcher.matches();
                        return new VirusInfo(matcher.group("filePath"), matcher.group("virus"));
                    })
                    .collect(new VirusInfoCollector());
            return new ScanResult(ScanResult.Status.VIRUS_FOUND, foundViruses);
        }
        if (RESPONSE_ERROR.matcher(responseString).matches()) {
            throw new ScanFailureException(responseString);
        }

        throw new InvalidResponseException(responseString);
    }

    @Getter
    @AllArgsConstructor
    private class VirusInfo {
        private String filePath, name;
    }

    private class VirusInfoCollector
            implements Collector<VirusInfo, Map<String, Collection<String>>, Map<String, Collection<String>>> {
<commit_msg>Fix #1<commit_after>package xyz.capybara.clamav.commands.scan;

import xyz.capybara.clamav.commands.scan.result.ScanResult;
import xyz.capybara.clamav.exceptions.InvalidResponseException;
import xyz.capybara.clamav.exceptions.ScanFailureException;
import xyz.capybara.clamav.commands.Command;
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collector;

public abstract class ScanCommand extends Command<ScanResult> {

    private static final Pattern RESPONSE_OK = Pattern.compile(
            "(.+) OK$",
            Pattern.UNIX_LINES
    );
    private static final Pattern RESPONSE_VIRUS_FOUND = Pattern.compile(
            "(.+) FOUND$",
            Pattern.MULTILINE & Pattern.UNIX_LINES
    );
    private static final Pattern RESPONSE_ERROR = Pattern.compile(
            "(.+) ERROR",
            Pattern.UNIX_LINES
    );
    private static final Pattern RESPONSE_VIRUS_FOUND_LINE = Pattern.compile(
            "(.+: )?(?<filePath>.+): (?<virus>.+) FOUND$",
            Pattern.UNIX_LINES
    );

    @Override
    protected ScanResult parseResponse(String responseString) {
        if (RESPONSE_OK.matcher(responseString).matches()) {
            return new ScanResult(ScanResult.Status.OK);
        }
        if (RESPONSE_VIRUS_FOUND.matcher(responseString).find()) {
            // add every found viruses to the scan result, grouped by infected file
            Map<String, Collection<String>> foundViruses = Arrays.stream(responseString.split("\n"))
                    .map(line -> {
                        Matcher matcher = RESPONSE_VIRUS_FOUND_LINE.matcher(line);
                        if (!matcher.matches()) {
                            throw new InvalidResponseException(responseString);
                        }
                        return new VirusInfo(matcher.group("filePath"), matcher.group("virus"));
                    })
                    .collect(new VirusInfoCollector());
            return new ScanResult(ScanResult.Status.VIRUS_FOUND, foundViruses);
        }
        if (RESPONSE_ERROR.matcher(responseString).matches()) {
            throw new ScanFailureException(responseString);
        }

        throw new InvalidResponseException(responseString);
    }

    @Getter
    @AllArgsConstructor
    private class VirusInfo {
        private String filePath, name;
    }

    private class VirusInfoCollector
            implements Collector<VirusInfo, Map<String, Collection<String>>, Map<String, Collection<String>>> {

{'fraction_non_alphanumeric': 0.10187767242981967, 'fraction_numerical': 0.00018590816136828406, 'mean_word_length': 2.728343728343728, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 25, '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': '1889761', 'n_tokens_mistral': 1561, 'n_tokens_neox': 1501, 'n_words': 286}