<commit_before>package org.jbehave.core.reporters;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Transformer;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.jbehave.core.configuration.Keywords;
import org.jbehave.core.failures.UUIDExceptionWrapper;
import org.jbehave.core.model.ExamplesTable;
import org.jbehave.core.model.GivenStories;
import org.jbehave.core.model.GivenStory;
import org.jbehave.core.model.Meta;
import org.jbehave.core.model.Narrative;
import org.jbehave.core.model.OutcomesTable;
import org.jbehave.core.model.OutcomesTable.Outcome;
import org.jbehave.core.model.Scenario;
import org.jbehave.core.model.Story;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;

import static org.apache.commons.lang.StringEscapeUtils.escapeHtml;
import static org.apache.commons.lang.StringEscapeUtils.escapeXml;
import static org.jbehave.core.steps.StepCreator.PARAMETER_VALUE_END;
import static org.jbehave.core.steps.StepCreator.PARAMETER_VALUE_NEWLINE;
import static org.jbehave.core.steps.StepCreator.PARAMETER_VALUE_START;

/**
 * <p>
 * Abstract story reporter that outputs to a PrintStream.
 * </p>
 * <p>
 * The output of the reported event is configurable via:
 * <ul>
 * <li>custom output patterns, providing only the patterns that differ from
 * default</li>
 * <li>keywords localised for different languages, providing the i18n Locale</li>
 * <li>flag to report failure trace</li>
 * </ul>
 * </p>
 * <p>
 * Let's look at example of providing custom output patterns, e.g. for the
 * failed event. <br/>
 * we'd need to provide the custom pattern, say we want to have something like
 * "(step being executed) <<< FAILED", keyed on the method name:
 * 
 * <pre>
 * Properties patterns = new Properties();
 * patterns.setProperty(&quot;failed&quot;, &quot;{0} &lt;&lt;&lt; {1}&quot;);
 * </pre>
 * 
 * The pattern is by default processed and formatted by the
 * {@link MessageFormat}. Both the {@link #format(String key, String defaultPattern, Object... args)} and
 * {@link #lookupPattern(String key, String defaultPattern)} methods are override-able and a different formatter
 * or pattern lookup can be used by subclasses.
 * </p>
 * <p>
 * If the keyword "FAILED" (or any other keyword used by the reporter) needs to
 * be expressed in a different language, all we need to do is to provide an
 * instance of {@link org.jbehave.core.i18n.LocalizedKeywords} using the appropriate {@link Locale}, e.g.
 * 
 * <pre>
 * Keywords keywords = new LocalizedKeywords(new Locale(&quot;it&quot;));
 * </pre>
 * 
 * </p>
 */
public abstract class PrintStreamOutput implements StoryReporter {

    private static final String EMPTY = "";

    public enum Format { TXT, HTML, XML }
    
    private final Format format;    
    private final PrintStream output;
    private final Properties outputPatterns;
    private final Keywords keywords;
    private boolean reportFailureTrace;
    private Throwable cause;

    
    protected PrintStreamOutput(Format format, PrintStream output, Properties outputPatterns,
            Keywords keywords, boolean reportFailureTrace) {
        this.format = format;
        this.output = output;
        this.outputPatterns = outputPatterns;
        this.keywords = keywords;
        this.reportFailureTrace = reportFailureTrace;   
    }

    public void successful(String step) {
        print(format("successful", "{0}\n", step));
    }

    public void ignorable(String step) {
        print(format("ignorable", "{0}\n", step));
    }

    public void pending(String step) {
        print(format("pending", "{0} ({1})\n", step, keywords.pending()));
    }

    public void notPerformed(String step) {
        print(format("notPerformed", "{0} ({1})\n", step, keywords.notPerformed()));
    }

    public void failed(String step, Throwable storyFailure) {
        this.cause = storyFailure;
        // storyFailure be used if a subclass has rewritten the "failed" pattern to have a {3} as WebDriverHtmlOutput (jbehave-web) does.
        if (storyFailure instanceof UUIDExceptionWrapper) {
            print(format("failed", "{0} ({1})\n({2})\n", step, keywords.failed(), storyFailure.getCause(), ((UUIDExceptionWrapper) storyFailure).getUUID()));
        } else {
            throw new ClassCastException("field storyFailure should be an instance of UUIDExceptionWrapper, but is not.");
        }
    }

    public void failedOutcomes(String step, OutcomesTable table) {
    	failed(step, table.failureCause());
        print(table);
    }
    
	private void print(OutcomesTable table) {
		print(format("outcomesTableStart", "\n"));
        List<Outcome<?>> rows = table.getOutcomes();
        print(format("outcomesTableHeadStart", "|"));
        //TODO i18n outcome fields
        for (String field : table.getOutcomeFields()) {
            print(format("outcomesTableHeadCell", "{0}|", field));
        }
        print(format("outcomesTableHeadEnd", "\n"));
        print(format("outcomesTableBodyStart", EMPTY));
        for (Outcome<?> outcome : rows) {
            print(format("outcomesTableRowStart", "|", outcome.isVerified()?"verified":"notVerified"));
            print(format("outcomesTableCell", "{0}|", outcome.getDescription()));
            print(format("outcomesTableCell", "{0}|", outcome.getValue()));
            print(format("outcomesTableCell", "{0}|", outcome.getMatcher()));
            print(format("outcomesTableCell", "{0}|", outcome.isVerified()));
            print(format("outcomesTableRowEnd", "\n"));
        }
        print(format("outcomesTableBodyEnd", "\n"));
        print(format("outcomesTableEnd", "\n"));
	}

    public void storyNotAllowed(Story story, String filter) {
        print(format("filter", "{0}\n", filter));
    }

    public void beforeStory(Story story, boolean givenStory) {
        print(format("beforeStory", "{0}\n({1})\n", story.getDescription().asString(), story.getPath()));
        if (!story.getMeta().isEmpty()) {
            Meta meta = story.getMeta();
            print(meta);
        }
    }

    public void narrative(Narrative narrative) {
        if (!narrative.isEmpty()) {
            print(format("narrative", "{0}\n{1} {2}\n{3} {4}\n{5} {6}\n", keywords.narrative(), keywords.inOrderTo(),
                    narrative.inOrderTo(), keywords.asA(), narrative.asA(), keywords.iWantTo(), narrative.iWantTo()));
        }
    }

    private void print(Meta meta) {
        print(format("metaStart", "{0}\n", keywords.meta()));
        for (String name : meta.getPropertyNames() ){
            print(format("metaProperty", "{0}{1} {2}", keywords.metaProperty(), name, meta.getProperty(name)));                
        }
        print(format("metaEnd", "\n"));
    }

    public void afterStory(boolean givenStory) {
        print(format("afterStory", "\n"));
        output.flush();
        output.close();
    }

    public void givenStories(GivenStories givenStories) {
        print(format("givenStoriesStart", "{0}\n", keywords.givenStories()));
        for (GivenStory givenStory : givenStories.getStories()) {
            print(format("givenStory", "{0} {1}\n", givenStory.asString(), (givenStory.hasAnchor() ? givenStory.getParameters() : "")));
        }
        print(format("givenStoriesEnd", "\n"));
    }

    public void givenStories(List<String> storyPaths) {
        givenStories(new GivenStories(StringUtils.join(storyPaths, ",")));
    }

    public void scenarioNotAllowed(Scenario scenario, String filter) {
        print(format("filter", "{0}\n", filter));
    }

    public void beforeScenario(String title) {
        cause = null;
        print(format("beforeScenario", "{0} {1}\n", keywords.scenario(), title));
    }<commit_msg>JBEHAVE-394:  Reverted speculative fix, which turned out not to be relevant.<commit_after>package org.jbehave.core.reporters;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Transformer;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.jbehave.core.configuration.Keywords;
import org.jbehave.core.failures.UUIDExceptionWrapper;
import org.jbehave.core.model.ExamplesTable;
import org.jbehave.core.model.GivenStories;
import org.jbehave.core.model.GivenStory;
import org.jbehave.core.model.Meta;
import org.jbehave.core.model.Narrative;
import org.jbehave.core.model.OutcomesTable;
import org.jbehave.core.model.OutcomesTable.Outcome;
import org.jbehave.core.model.Scenario;
import org.jbehave.core.model.Story;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;

import static org.apache.commons.lang.StringEscapeUtils.escapeHtml;
import static org.apache.commons.lang.StringEscapeUtils.escapeXml;
import static org.jbehave.core.steps.StepCreator.PARAMETER_VALUE_END;
import static org.jbehave.core.steps.StepCreator.PARAMETER_VALUE_NEWLINE;
import static org.jbehave.core.steps.StepCreator.PARAMETER_VALUE_START;

/**
 * <p>
 * Abstract story reporter that outputs to a PrintStream.
 * </p>
 * <p>
 * The output of the reported event is configurable via:
 * <ul>
 * <li>custom output patterns, providing only the patterns that differ from
 * default</li>
 * <li>keywords localised for different languages, providing the i18n Locale</li>
 * <li>flag to report failure trace</li>
 * </ul>
 * </p>
 * <p>
 * Let's look at example of providing custom output patterns, e.g. for the
 * failed event. <br/>
 * we'd need to provide the custom pattern, say we want to have something like
 * "(step being executed) <<< FAILED", keyed on the method name:
 * 
 * <pre>
 * Properties patterns = new Properties();
 * patterns.setProperty(&quot;failed&quot;, &quot;{0} &lt;&lt;&lt; {1}&quot;);
 * </pre>
 * 
 * The pattern is by default processed and formatted by the
 * {@link MessageFormat}. Both the {@link #format(String key, String defaultPattern, Object... args)} and
 * {@link #lookupPattern(String key, String defaultPattern)} methods are override-able and a different formatter
 * or pattern lookup can be used by subclasses.
 * </p>
 * <p>
 * If the keyword "FAILED" (or any other keyword used by the reporter) needs to
 * be expressed in a different language, all we need to do is to provide an
 * instance of {@link org.jbehave.core.i18n.LocalizedKeywords} using the appropriate {@link Locale}, e.g.
 * 
 * <pre>
 * Keywords keywords = new LocalizedKeywords(new Locale(&quot;it&quot;));
 * </pre>
 * 
 * </p>
 */
public abstract class PrintStreamOutput implements StoryReporter {

    private static final String EMPTY = "";

    public enum Format { TXT, HTML, XML }
    
    private final Format format;    
    private final PrintStream output;
    private final Properties outputPatterns;
    private final Keywords keywords;
    private boolean reportFailureTrace;
    private Throwable cause;

    
    protected PrintStreamOutput(Format format, PrintStream output, Properties outputPatterns,
            Keywords keywords, boolean reportFailureTrace) {
        this.format = format;
        this.output = output;
        this.outputPatterns = outputPatterns;
        this.keywords = keywords;
        this.reportFailureTrace = reportFailureTrace;   
    }

    public void successful(String step) {
        print(format("successful", "{0}\n", step));
    }

    public void ignorable(String step) {
        print(format("ignorable", "{0}\n", step));
    }

    public void pending(String step) {
        print(format("pending", "{0} ({1})\n", step, keywords.pending()));
    }

    public void notPerformed(String step) {
        print(format("notPerformed", "{0} ({1})\n", step, keywords.notPerformed()));
    }

    public void failed(String step, Throwable storyFailure) {
        this.cause = storyFailure;
        // storyFailure be used if a subclass has rewritten the "failed" pattern to have a {3} as WebDriverHtmlOutput (jbehave-web) does.
        if (storyFailure instanceof UUIDExceptionWrapper) {
            print(format("failed", "{0} ({1})\n({2})\n", step, keywords.failed(), storyFailure.getCause(), ((UUIDExceptionWrapper) storyFailure).getUUID()));
        } else {
            throw new ClassCastException("field storyFailure should be an instance of UUIDExceptionWrapper, but is not.");
        }
    }

    public void failedOutcomes(String step, OutcomesTable table) {
    	failed(step, table.failureCause());
        print(table);
    }
    
	private void print(OutcomesTable table) {
		print(format("outcomesTableStart", "\n"));
        List<Outcome<?>> rows = table.getOutcomes();
        print(format("outcomesTableHeadStart", "|"));
        //TODO i18n outcome fields
        for (String field : table.getOutcomeFields()) {
            print(format("outcomesTableHeadCell", "{0}|", field));
        }
        print(format("outcomesTableHeadEnd", "\n"));
        print(format("outcomesTableBodyStart", EMPTY));
        for (Outcome<?> outcome : rows) {
            print(format("outcomesTableRowStart", "|", outcome.isVerified()?"verified":"notVerified"));
            print(format("outcomesTableCell", "{0}|", outcome.getDescription()));
            print(format("outcomesTableCell", "{0}|", outcome.getValue()));
            print(format("outcomesTableCell", "{0}|", outcome.getMatcher()));
            print(format("outcomesTableCell", "{0}|", outcome.isVerified()));
            print(format("outcomesTableRowEnd", "\n"));
        }
        print(format("outcomesTableBodyEnd", "\n"));
        print(format("outcomesTableEnd", "\n"));
	}

    public void storyNotAllowed(Story story, String filter) {
        print(format("filter", "{0}\n", filter));
    }

    public void beforeStory(Story story, boolean givenStory) {
        print(format("beforeStory", "{0}\n({1})\n", story.getDescription().asString(), story.getPath()));
        if (!story.getMeta().isEmpty()) {
            Meta meta = story.getMeta();
            print(meta);
        }
    }

    public void narrative(Narrative narrative) {
        if (!narrative.isEmpty()) {
            print(format("narrative", "{0}\n{1} {2}\n{3} {4}\n{5} {6}\n", keywords.narrative(), keywords.inOrderTo(),
                    narrative.inOrderTo(), keywords.asA(), narrative.asA(), keywords.iWantTo(), narrative.iWantTo()));
        }
    }

    private void print(Meta meta) {
        print(format("metaStart", "{0}\n", keywords.meta()));
        for (String name : meta.getPropertyNames() ){
            print(format("metaProperty", "{0}{1} {2}", keywords.metaProperty(), name, meta.getProperty(name)));                
        }
        print(format("metaEnd", "\n"));
    }

    public void afterStory(boolean givenStory) {
        print(format("afterStory", "\n"));
    }

    public void givenStories(GivenStories givenStories) {
        print(format("givenStoriesStart", "{0}\n", keywords.givenStories()));
        for (GivenStory givenStory : givenStories.getStories()) {
            print(format("givenStory", "{0} {1}\n", givenStory.asString(), (givenStory.hasAnchor() ? givenStory.getParameters() : "")));
        }
        print(format("givenStoriesEnd", "\n"));
    }

    public void givenStories(List<String> storyPaths) {
        givenStories(new GivenStories(StringUtils.join(storyPaths, ",")));
    }

    public void scenarioNotAllowed(Scenario scenario, String filter) {
        print(format("filter", "{0}\n", filter));
    }

    public void beforeScenario(String title) {
        cause = null;
        print(format("beforeScenario", "{0} {1}\n", keywords.scenario(), title));
    }
{'fraction_non_alphanumeric': 0.13962147067949116, 'fraction_numerical': 0.005522804840210983, 'mean_word_length': 3.581011938601478, 'pattern_counts': {'":': 2, '<': 59, '<?xml version=': 0, '>': 53, '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': '3405513', 'n_tokens_mistral': 4709, 'n_tokens_neox': 4608, 'n_words': 1154}