package org.tinylog.impl.backend;

import java.util.List;

import javax.inject.Inject;

import org.junit.jupiter.api.Test;
import org.tinylog.core.Level;
import org.tinylog.core.test.log.CaptureLogEntries;
import org.tinylog.core.test.log.Log;

import static org.assertj.core.api.Assertions.assertThat;

@CaptureLogEntries
class LevelConfigurationTest {

	@Inject
	private Log log;

	/**
	 * Verifies parsing an empty level configuration without any passed severity levels.
	 */
	@Test
	void empty() {
		LevelConfiguration configuration = new LevelConfiguration(List.of());
		assertThat(configuration.getTags()).containsExactlyInAnyOrder("tinylog");
		assertThat(configuration.getUntaggedLevel()).isEqualTo(Level.TRACE);
		assertThat(configuration.getDefaultTaggedLevel()).isEqualTo(Level.TRACE);
		assertThat(configuration.getTaggedLevel("foo")).isEqualTo(Level.TRACE);
		assertThat(configuration.getTaggedLevel("tinylog")).isEqualTo(Level.WARN);
	}

	/**
	 * Verifies parsing a level configuration with a single untagged severity level.
	 */
	@Test
	void generalLevel() {
		LevelConfiguration configuration = new LevelConfiguration(List.of("debug"));
		assertThat(configuration.getTags()).containsExactlyInAnyOrder("tinylog");
		assertThat(configuration.getUntaggedLevel()).isEqualTo(Level.DEBUG);
		assertThat(configuration.getDefaultTaggedLevel()).isEqualTo(Level.DEBUG);
		assertThat(configuration.getTaggedLevel("foo")).isEqualTo(Level.DEBUG);
		assertThat(configuration.getTaggedLevel("tinylog")).isEqualTo(Level.WARN);
	}

	/**
	 * Verifies parsing a level configuration with a single custom tagged severity level.
	 */
	@Test
	void taggedLevel() {
		LevelConfiguration configuration = new LevelConfiguration(List.of("foo@error"));
		assertThat(configuration.getTags()).containsExactlyInAnyOrder("foo", "tinylog");
		assertThat(configuration.getUntaggedLevel()).isEqualTo(Level.OFF);
		assertThat(configuration.getDefaultTaggedLevel()).isEqualTo(Level.OFF);
		assertThat(configuration.getTaggedLevel("foo")).isEqualTo(Level.ERROR);
		assertThat(configuration.getTaggedLevel("tinylog")).isEqualTo(Level.WARN);
	}

	/**
	 * Verifies parsing a level configuration with a single tagged severity level for tinylog internal log entries.
	 */
	@Test
	void tinylogLevel() {
		LevelConfiguration configuration = new LevelConfiguration(List.of("tinylog@trace"));
		assertThat(configuration.getTags()).containsExactlyInAnyOrder("tinylog");
		assertThat(configuration.getUntaggedLevel()).isEqualTo(Level.OFF);
		assertThat(configuration.getDefaultTaggedLevel()).isEqualTo(Level.OFF);
		assertThat(configuration.getTaggedLevel("foo")).isEqualTo(Level.OFF);
		assertThat(configuration.getTaggedLevel("tinylog")).isEqualTo(Level.TRACE);
	}

	/**
	 * Verifies parsing a level configuration with a single severity level for the any placeholder {@code '*'}.
	 */
	@Test
	void anyPlaceholderLevel() {
		LevelConfiguration configuration = new LevelConfiguration(List.of("*@debug"));
		assertThat(configuration.getTags()).containsExactlyInAnyOrder("tinylog");
		assertThat(configuration.getUntaggedLevel()).isEqualTo(Level.DEBUG);
		assertThat(configuration.getDefaultTaggedLevel()).isEqualTo(Level.DEBUG);
		assertThat(configuration.getTaggedLevel("foo")).isEqualTo(Level.DEBUG);
		assertThat(configuration.getTaggedLevel("tinylog")).isEqualTo(Level.WARN);
	}

	/**
	 * Verifies parsing a level configuration with a single severity level for the plus placeholder {@code '+'}.
	 */
	@Test
	void plusPlaceholderLevel() {
		LevelConfiguration configuration = new LevelConfiguration(List.of("+@debug"));
		assertThat(configuration.getTags()).containsExactlyInAnyOrder("tinylog");
		assertThat(configuration.getUntaggedLevel()).isEqualTo(Level.OFF);
		assertThat(configuration.getDefaultTaggedLevel()).isEqualTo(Level.DEBUG);
		assertThat(configuration.getTaggedLevel("foo")).isEqualTo(Level.DEBUG);
		assertThat(configuration.getTaggedLevel("tinylog")).isEqualTo(Level.WARN);
	}

	/**
	 * Verifies parsing a level configuration with a single severity level for the minus placeholder {@code '-'}.
	 */
	@Test
	void minusPlaceholderLevel() {
		LevelConfiguration configuration = new LevelConfiguration(List.of("-@debug"));
		assertThat(configuration.getTags()).containsExactlyInAnyOrder("tinylog");
		assertThat(configuration.getUntaggedLevel()).isEqualTo(Level.DEBUG);
		assertThat(configuration.getDefaultTaggedLevel()).isEqualTo(Level.OFF);
		assertThat(configuration.getTaggedLevel("foo")).isEqualTo(Level.OFF);
		assertThat(configuration.getTaggedLevel("tinylog")).isEqualTo(Level.WARN);
	}

	/**
	 * Verifies parsing a level configuration with multiple severity levels.
	 */
	@Test
	void multipleLevels() {
		List<String> levels = List.of("debug", "+@info", "foo@trace", "tinylog@error");
		LevelConfiguration configuration = new LevelConfiguration(levels);
		assertThat(configuration.getTags()).containsExactlyInAnyOrder("foo", "tinylog");
		assertThat(configuration.getUntaggedLevel()).isEqualTo(Level.DEBUG);
		assertThat(configuration.getDefaultTaggedLevel()).isEqualTo(Level.INFO);
		assertThat(configuration.getTaggedLevel("foo")).isEqualTo(Level.TRACE);
		assertThat(configuration.getTaggedLevel("tinylog")).isEqualTo(Level.ERROR);
	}

	/**
	 * Verifies parsing a level configuration with an invalid severity level.
	 */
	@Test
	void invalidLevel() {
		LevelConfiguration configuration = new LevelConfiguration(List.of("foo"));

		assertThat(log.consume()).anySatisfy(entry -> {
			assertThat(entry.getLevel()).isEqualTo(Level.ERROR);
			assertThat(entry.getMessage()).contains("foo");
		});

		assertThat(configuration.getTags()).containsExactlyInAnyOrder("tinylog");
		assertThat(configuration.getUntaggedLevel()).isEqualTo(Level.TRACE);
		assertThat(configuration.getDefaultTaggedLevel()).isEqualTo(Level.TRACE);
		assertThat(configuration.getTaggedLevel("foo")).isEqualTo(Level.TRACE);
		assertThat(configuration.getTaggedLevel("tinylog")).isEqualTo(Level.WARN);
	}

}

@@ -28,16 +28,46 @@
 ckend;%0A%0A
+import java.util.Collections;%0A
 import j
@@ -81,16 +81,16 @@
 l.List;%0A
-
 %0Aimport 
@@ -268,16 +268,65 @@
 g.Log;%0A%0A
+import com.google.common.collect.ImmutableList;%0A%0A
 import s
@@ -634,23 +634,37 @@
 uration(
+Collections.empty
 List
-.of
 ());%0A%09%09a
@@ -1220,23 +1220,41 @@
 uration(
+Collections.singleton
 List
-.of
 (%22debug%22
@@ -1817,31 +1817,49 @@
 nfiguration(
+Collections.singleton
 List
-.of
 (%22foo@error%22
@@ -2456,23 +2456,41 @@
 uration(
+Collections.singleton
 List
-.of
 (%22tinylo
@@ -3090,23 +3090,41 @@
 uration(
+Collections.singleton
 List
-.of
 (%22*@debu
@@ -3725,23 +3725,41 @@
 uration(
+Collections.singleton
 List
-.of
 (%22+@debu
@@ -4360,23 +4360,41 @@
 uration(
+Collections.singleton
 List
-.of
 (%22-@debu
@@ -4913,16 +4913,25 @@
 evels = 
+Immutable
 List.of(
@@ -5609,23 +5609,41 @@
 uration(
+Collections.singleton
 List
-.of
 (%22foo%22))

Remove List.of() calls as they do not exist in Java 8