<commit_before>package de.tobiasroeser.lambdatest.testng;

import static de.tobiasroeser.lambdatest.internal.Util.find;

import java.io.PrintStream;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;

import org.testng.Assert;
import org.testng.SkipException;
import org.testng.TestException;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import de.tobiasroeser.lambdatest.internal.AnsiColor;
import de.tobiasroeser.lambdatest.internal.AnsiColor.Color;

/**
 * Inherit from this class to create a new test suite and use the
 * {@link FreeSpec#test} method to add test cases.
 * <p/>
 * Besides the typically <code>assertXXX</code> methods from {@link Assert},
 * which are already in scope when inherit from this class, you can use the
 * following methods:
 * <ul>
 * <li>{@link FreeSpec#intercept(Class, RunnableWithException)} and
 * {@link FreeSpec#intercept(Class, String, RunnableWithException)} to intercept
 * and assert expected exceptions.</li>
 * <li>{@link FreeSpec#pending()} to mark a test case as pending</li>
 * </ul>
 * 
 * {@link FreeSpec#intercept(Class, String, RunnableWithException)}
 * 
 * TODO: example
 *
 */
public class FreeSpec extends Assert {

	private List<Object[]> testCases = new LinkedList<>();
	private boolean testNeverRun = true;

	/**
	 * Adds a test to the test suite.
	 * 
	 * @param name
	 *            The name of the new test.
	 * @param testCase
	 *            The test case. It should return when it is successful, else it
	 *            should throw an exception. Exceptions of type
	 *            {@link TestException} which are typically thrown by
	 *            Assert.assertXXX methods (e.g.
	 *            {@link Assert#assertEquals(String, String)}) are specially
	 *            recognized by TestNG.
	 */
	public void test(final String name, final RunnableWithException testCase) {
		final String testName = getClass().getSimpleName() + ": " + name;

		if (find(testCases, tc -> testName.equals(tc[0])).isDefined()) {
			System.out.println("Test with non-unique name added: " + testName);
		}
		this.testCases.add(new Object[] { testName, testCase });
	}

	/**
	 * Marks the test as pending. Instructions after <code>pending()</code> will
	 * not be executed and TestNG marks the test as skipped.
	 */
	public void pending() {
		throw new SkipException("Pending");
	}

	/**
	 * Intercept exceptions of type <code>exceptionType</code> and fail if no
	 * such exception or an exception with an incompatible type was thrown.
	 * 
	 * @param exceptionType
	 *            The exception type to intercept.
	 * @throws TextException
	 *             If no exception or an exception with an incompatible type was
	 *             thrown.
	 */
	public void intercept(final Class<? extends Exception> exceptionType,
			final RunnableWithException throwing) throws Exception {
		intercept(exceptionType, ".*", throwing);
	}

	/**
	 * Intercept exceptions of type <code>exceptionType</code> and fail if no
	 * such exception or an exception with an incompatible type was thrown or it
	 * the message does not match a given pattern.
	 * 
	 * @param exceptionType
	 *            The exception type to intercept.
	 * @param messageRegex
	 *            A regular expression pattern to match the expected message.
	 *            See {@link Pattern} for details.
	 * @throws TextException
	 *             If no exception or an exception with an incompatible type was
	 *             thrown or if the message of the exception does not match the
	 *             expected pattern.
	 */
	public void intercept(final Class<? extends Exception> exceptionType,
			String messageRegex, final RunnableWithException throwing)
			throws Exception {
		try {
			throwing.run();
		} catch (Exception e) {
			if (exceptionType.isAssignableFrom(e.getClass())) {
				final String msg = e.getMessage();
				final boolean matches;
				{
					if (".*".equals(messageRegex)) {
						matches = true;
					} else {
						if (msg == null) {
							matches = false;
						} else {
							matches = Pattern.matches(messageRegex, msg);
						}
					}<commit_msg>Updated JavaDoc.<commit_after>package de.tobiasroeser.lambdatest.testng;

import static de.tobiasroeser.lambdatest.internal.Util.find;

import java.io.PrintStream;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;

import org.testng.Assert;
import org.testng.SkipException;
import org.testng.TestException;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import de.tobiasroeser.lambdatest.internal.AnsiColor;
import de.tobiasroeser.lambdatest.internal.AnsiColor.Color;

/**
 * Inherit from this class to create a new test suite and use the
 * {@link FreeSpec#test} method to add test cases.
 * <p>
 * Besides the typically <code>assertXXX</code> methods from {@link Assert},
 * which are already in scope when inherit from this class, you can use the
 * following methods:
 * <ul>
 * <li>{@link FreeSpec#intercept(Class, RunnableWithException)} and
 * {@link FreeSpec#intercept(Class, String, RunnableWithException)} to intercept
 * and assert expected exceptions.</li>
 * <li>{@link FreeSpec#pending()} to mark a test case as pending</li>
 * </ul>
 * 
 * TODO: example
 *
 */
public class FreeSpec extends Assert {

	private List<Object[]> testCases = new LinkedList<>();
	private boolean testNeverRun = true;

	/**
	 * Adds a test to the test suite.
	 * 
	 * @param name
	 *            The name of the new test.
	 * @param testCase
	 *            The test case. It should return when it is successful, else it
	 *            should throw an exception. Exceptions of type
	 *            {@link TestException} which are typically thrown by
	 *            Assert.assertXXX methods (e.g.
	 *            {@link Assert#assertEquals(String, String)}) are specially
	 *            recognized by TestNG.
	 */
	public void test(final String name, final RunnableWithException testCase) {
		final String testName = getClass().getSimpleName() + ": " + name;

		if (find(testCases, tc -> testName.equals(tc[0])).isDefined()) {
			System.out.println("Test with non-unique name added: " + testName);
		}
		this.testCases.add(new Object[] { testName, testCase });
	}

	/**
	 * Marks the test as pending. Instructions after <code>pending()</code> will
	 * not be executed and TestNG marks the test as skipped.
	 */
	public void pending() {
		throw new SkipException("Pending");
	}

	/**
	 * Intercept exceptions of type <code>exceptionType</code> and fail if no
	 * such exception or an exception with an incompatible type was thrown.
	 * 
	 * @param exceptionType
	 *            The exception type to intercept.
	 * @param throwing
	 *            The execution block which is expected to throw the exception.
	 * @throws Exception
	 *             If no exception was thrown or an exception with an
	 *             incompatible type was thrown.
	 */
	public void intercept(final Class<? extends Exception> exceptionType,
			final RunnableWithException throwing) throws Exception {
		intercept(exceptionType, ".*", throwing);
	}

	/**
	 * Intercept exceptions of type <code>exceptionType</code> and fail if no
	 * such exception or an exception with an incompatible type was thrown or it
	 * the message does not match a given pattern.
	 * 
	 * @param exceptionType
	 *            The exception type to intercept.
	 * @param messageRegex
	 *            A regular expression pattern to match the expected message.
	 *            See {@link Pattern} for details.
	 * @param throwing
	 *            The execution block which is expected to throw the exception.
	 * @throws Exception
	 *             If no exception was thrown or an exception with an
	 *             incompatible type was thrown or if the message of the
	 *             exception did not match the expected pattern.
	 */
	public void intercept(final Class<? extends Exception> exceptionType,
			String messageRegex, final RunnableWithException throwing)
			throws Exception {
		try {
			throwing.run();
		} catch (Exception e) {
			if (exceptionType.isAssignableFrom(e.getClass())) {
				final String msg = e.getMessage();
				final boolean matches;
				{
					if (".*".equals(messageRegex)) {
						matches = true;
					} else {
						if (msg == null) {
							matches = false;
						} else {
							matches = Pattern.matches(messageRegex, msg);
						}
					}
{'fraction_non_alphanumeric': 0.09734199645599527, 'fraction_numerical': 0.00023626698168930892, 'mean_word_length': 3.1117047110247693, 'pattern_counts': {'":': 2, '<': 41, '<?xml version=': 0, '>': 43, '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': '4739059', 'n_tokens_mistral': 2550, 'n_tokens_neox': 2288, 'n_words': 829}