/*
 * Copyright 2020, TeamDev. All rights reserved.
 *
 * Redistribution and use in source and/or binary forms, with or without
 * modification, must retain the above copyright notice and the following
 * disclaimer.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package io.spine.testing.logging;

import com.google.common.truth.Subject;
import com.google.common.truth.TruthFailureSubject;
import io.spine.testing.SubjectTest;
import io.spine.testing.TestValues;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.logging.Level;
import java.util.logging.LogRecord;

import static com.google.common.truth.ExpectFailure.assertThat;
import static io.spine.testing.logging.LogRecordSubject.NO_LOG_RECORD;
import static io.spine.testing.logging.LogRecordSubject.records;

@DisplayName("LogRecordSubject should have")
class LogRecordSubjectTest extends SubjectTest<LogRecordSubject, LogRecord> {

    private LogRecord record;
    private String msg;
    private Level level;
    private Throwable throwable;
    private Object[] parameters;

    @Override
    protected Subject.Factory<LogRecordSubject, LogRecord> subjectFactory() {
        return records();
    }

    @BeforeEach
    void createRecord() {
        msg = "Test log message" + TestValues.randomString();
        level = Level.FINE;
        record = new LogRecord(level, msg);
        throwable = new RuntimeException("Testing LogRecordSubject handling of Throwable");
        parameters = new Object[] { '0', "1", 2, 3L, 4.0f, 5.0d, true };
        record.setParameters(parameters);
        record.setThrown(throwable);
    }

    @Test
    @DisplayName("the check for no logged records")
    void noRecords() {
        AssertionError failure = expectFailure(whenTesting -> whenTesting.that(null)
                                                                         .hasLevelThat());
        assertThat(failure)
                .factKeys()
                .contains(NO_LOG_RECORD);
    }

    @Test
    void hasMessageThat() {
        assertWithSubjectThat(record)
                .hasMessageThat()
                .isEqualTo(msg);

        String notExpected = TestValues.randomString();

        AssertionError failure = expectFailure(
                whenTesting -> whenTesting.that(record)
                                          .hasMessageThat()
                                          .isEqualTo(notExpected)
        );
        TruthFailureSubject assertFailure = assertThat(failure);
        assertFailure.factKeys()
                     .containsAnyOf(EXPECTED, BUT_WAS);
    }

    @Test
    void hasLevelThat() {
        assertWithSubjectThat(record)
                .hasLevelThat()
                .isEqualTo(level);

        expectSomeFailure(
                whenTesting -> whenTesting.that(record)
                                          .hasLevelThat()
                                          .isEqualTo(Level.OFF)
        );
    }

    @Test
    void isDebug() {
        assertWithSubjectThat(record)
                .isDebug();

        expectSomeFailure(whenTesting -> whenTesting.that(record)
                                                    .isError());
    }

    @Test
    void isError() {
        record.setLevel(Level.SEVERE);
        assertWithSubjectThat(record)
                .isError();

        expectSomeFailure(whenTesting -> whenTesting.that(record)
                                                    .isDebug());
    }

    @Test
    void hasParametersThat() {
        assertWithSubjectThat(record)
                .hasParametersThat()
                .asList()
                .containsExactlyElementsIn(parameters);

        expectSomeFailure(whenTesting -> whenTesting.that(record)
                                                    .hasParametersThat()
                                                    .isEmpty());
    }

    @Test
    void hasThrowableThat() {
        assertWithSubjectThat(record)
                .hasThrowableThat()
                .isInstanceOf(throwable.getClass());

        expectSomeFailure(whenTesting -> whenTesting.that(record)
                                                    .hasThrowableThat()
                                                    .isNull());
    }
}

@@ -5047,11 +5047,909 @@
 );%0A    %7D
+%0A%0A    @Test%0A    void hasMethodThat() %7B%0A        String method = %22hasMethodThat%22;%0A        record.setSourceMethodName(method);%0A        assertWithSubjectThat(record)%0A                .hasMethodThat()%0A                .isEqualTo(method);%0A        expectSomeFailure(whenTesting -%3E whenTesting.that(record)%0A                                                    .hasMethodThat()%0A                                                    .isEmpty());%0A    %7D%0A%0A    @Test%0A    void hasClassThat() %7B%0A        String className = LogRecordSubjectTest.class.getName();%0A        record.setSourceClassName(className);%0A        assertWithSubjectThat(record)%0A                .hasClassThat()%0A                .isEqualTo(className);%0A        expectSomeFailure(whenTesting -%3E whenTesting.that(record)%0A                                                    .hasClassThat()%0A                                                    .isEmpty());%0A    %7D
 %0A%7D%0A

Test new assertions