/*
 * Copyright 2015-2018 the original author or authors.
 *
 * All rights reserved. This program and the accompanying materials are
 * made available under the terms of the Eclipse Public License v2.0 which
 * accompanies this distribution and is available at
 *
 * http://www.eclipse.org/legal/epl-v20.html
 */

package org.junit.jupiter.api;

import static org.junit.jupiter.api.AssertionTestUtils.assertMessageEquals;
import static org.junit.jupiter.api.AssertionTestUtils.expectAssertionFailedError;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;

import java.io.IOException;

import org.junit.jupiter.api.function.Executable;
import org.junit.jupiter.api.function.ThrowingSupplier;
import org.opentest4j.AssertionFailedError;

/**
 * Unit tests for JUnit Jupiter {@link Assertions}.
 *
 * @since 5.2
 */
class AssertDoesNotThrowAssertionsTests {

	private static final Executable nix = () -> {
	};

	private static final ThrowingSupplier<String> something = () -> "enigma";

	// --- executable ----------------------------------------------------------

	@Test
	void assertDoesNotThrowAnythingWithExecutable() {
		assertDoesNotThrow(nix);
	}

	@Test
	void assertDoesNotThrowAnythingWithExecutableAndMessage() {
		assertDoesNotThrow(nix, "message");
	}

	@Test
	void assertDoesNotThrowAnythingWithExecutableAndMessageSupplier() {
		assertDoesNotThrow(nix, () -> "message");
	}

	@Test
	void assertDoesNotThrowWithExecutableThatThrowsACheckedException() {
		try {
			assertDoesNotThrow((Executable) () -> {
				throw new IOException();
			});
			expectAssertionFailedError();
		}
		catch (AssertionFailedError ex) {
			assertMessageEquals(ex, "Unexpected exception thrown: " + IOException.class.getName());
		}
	}

	@Test
	void assertDoesNotThrowWithExecutableThatThrowsARuntimeException() {
		try {
			assertDoesNotThrow((Executable) () -> {
				throw new IllegalStateException();
			});
			expectAssertionFailedError();
		}
		catch (AssertionFailedError ex) {
			assertMessageEquals(ex, "Unexpected exception thrown: " + IllegalStateException.class.getName());
		}
	}

	@Test
	void assertDoesNotThrowWithExecutableThatThrowsAnError() {
		try {
			assertDoesNotThrow((Executable) AssertionTestUtils::recurseIndefinitely);
			expectAssertionFailedError();
		}
		catch (AssertionFailedError ex) {
			assertMessageEquals(ex, "Unexpected exception thrown: " + StackOverflowError.class.getName());
		}
	}

	@Test
	void assertDoesNotThrowWithExecutableThatThrowsAnExceptionWithMessageString() {
		try {
			assertDoesNotThrow((Executable) () -> {
				throw new IllegalStateException();
			}, "Custom message");
			expectAssertionFailedError();
		}
		catch (AssertionFailedError ex) {
			assertMessageEquals(ex,
				"Custom message ==> Unexpected exception thrown: " + IllegalStateException.class.getName());
		}
	}

	@Test
	void assertDoesNotThrowWithExecutableThatThrowsAnExceptionWithMessageSupplier() {
		try {
			assertDoesNotThrow((Executable) () -> {
				throw new IllegalStateException();
			}, () -> "Custom message");
			expectAssertionFailedError();
		}
		catch (AssertionFailedError ex) {
			assertMessageEquals(ex,
				"Custom message ==> Unexpected exception thrown: " + IllegalStateException.class.getName());
		}
	}

	// --- supplier ------------------------------------------------------------

	@Test
	void assertDoesNotThrowAnythingWithSupplier() {
		assertEquals("enigma", assertDoesNotThrow(something));
	}

	@Test
	void assertDoesNotThrowAnythingWithSupplierAndMessage() {
		assertEquals("enigma", assertDoesNotThrow(something, "message"));
	}

	@Test
	void assertDoesNotThrowAnythingWithSupplierAndMessageSupplier() {
		assertEquals("enigma", assertDoesNotThrow(something, () -> "message"));
	}

	@Test
	void assertDoesNotThrowWithSupplierThatThrowsACheckedException() {
		try {
			assertDoesNotThrow((ThrowingSupplier<?>) () -> {
				throw new IOException();
			});
			expectAssertionFailedError();
		}
		catch (AssertionFailedError ex) {
			assertMessageEquals(ex, "Unexpected exception thrown: " + IOException.class.getName());
		}
	}

	@Test
	void assertDoesNotThrowWithSupplierThatThrowsARuntimeException() {
		try {
			assertDoesNotThrow((ThrowingSupplier<?>) () -> {
				throw new IllegalStateException();
			});
			expectAssertionFailedError();
		}
		catch (AssertionFailedError ex) {
			assertMessageEquals(ex, "Unexpected exception thrown: " + IllegalStateException.class.getName());
		}
	}

	@Test
	void assertDoesNotThrowWithSupplierThatThrowsAnError() {
		try {
			assertDoesNotThrow((ThrowingSupplier<?>) () -> {
				throw new StackOverflowError();
			});
			expectAssertionFailedError();
		}
		catch (AssertionFailedError ex) {
			assertMessageEquals(ex, "Unexpected exception thrown: " + StackOverflowError.class.getName());
		}
	}

	@Test
	void assertDoesNotThrowWithSupplierThatThrowsAnExceptionWithMessageString() {
		try {
			assertDoesNotThrow((ThrowingSupplier<?>) () -> {
				throw new IllegalStateException();
			}, "Custom message");
			expectAssertionFailedError();
		}
		catch (AssertionFailedError ex) {
			assertMessageEquals(ex,
				"Custom message ==> Unexpected exception thrown: " + IllegalStateException.class.getName());
		}
	}

	@Test
	void assertDoesNotThrowWithSupplierThatThrowsAnExceptionWithMessageSupplier() {
		try {
			assertDoesNotThrow((ThrowingSupplier<?>) () -> {
				throw new IllegalStateException();
			}, () -> "Custom message");
			expectAssertionFailedError();
		}
		catch (AssertionFailedError ex) {
			assertMessageEquals(ex,
				"Custom message ==> Unexpected exception thrown: " + IllegalStateException.class.getName());
		}
	}

}

@@ -654,16 +654,56 @@
 ception;
+%0Aimport java.util.concurrent.FutureTask;
 %0A%0Aimport
@@ -1095,16 +1095,531 @@
 igma%22;%0A%0A
+%09@Test%0A%09void assertDoesNotThrowWithFutureMethodReference() %7B%0A%09%09FutureTask%3CString%3E future = new FutureTask%3C%3E(() -%3E %7B%0A%09%09%09return %22foo%22;%0A%09%09%7D);%0A%09%09future.run();%0A%0A%09%09String result;%0A%0A%09%09// Current compiler's type inference%0A%09%09result = assertDoesNotThrow(future::get);%0A%09%09assertEquals(%22foo%22, result);%0A%0A%09%09// Explicitly as an Executable%0A%09%09assertDoesNotThrow((Executable) future::get);%0A%0A%09%09// Explicitly as a ThrowingSupplier%0A%09%09result = assertDoesNotThrow((ThrowingSupplier%3CString%3E) future::get);%0A%09%09assertEquals(%22foo%22, result);%0A%09%7D%0A%0A
 %09// --- 

Test status quo for method references passed to assertDoesNotThrow()