/*
 * Copyright 2015, TeamDev Ltd. 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 org.spine3.server.storage.filesystem;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.spine3.base.EventRecord;
import org.spine3.test.project.ProjectId;

import java.util.Iterator;
import java.util.List;

import static com.google.common.collect.Lists.newArrayList;
import static org.junit.Assert.*;
import static org.spine3.server.storage.filesystem.Helper.cleanTestData;
import static org.spine3.server.storage.filesystem.Helper.configure;
import static org.spine3.util.testutil.EventRecordFactory.projectCreated;
import static org.spine3.util.testutil.EventRecordFactory.projectStarted;
import static org.spine3.util.testutil.EventRecordFactory.taskAdded;

@SuppressWarnings({"InstanceMethodNamingConvention", "DuplicateStringLiteralInspection", "ConstantConditions"})
public class FileSystemEventStorageShould {

    private static final FileSystemEventStorage STORAGE = new FileSystemEventStorage();

    private ProjectId id;

    @Before
    public void setUpTest() {

        STORAGE.releaseResources();
        configure(FileSystemEventStorageShould.class);
        cleanTestData();

        id = ProjectId.newBuilder().setId("project_id").build();
    }

    @After
    public void tearDownTest() {
        STORAGE.releaseResources();
    }

    @Test
    public void return_iterator_over_empty_collection_if_read_all_records_from_empty_storage() {

        final Iterator<EventRecord> iterator = STORAGE.allEvents();
        assertFalse(iterator.hasNext());
    }

    @Test(expected = NullPointerException.class)
    public void throw_exception_if_try_to_write_null() {
        STORAGE.write(null);
    }

    @Test
    public void save_and_read_events() {

        final EventRecord expected = projectCreated(id);
        STORAGE.store(expected);

        final Iterator<EventRecord> iterator = STORAGE.allEvents();

        assertTrue(iterator.hasNext());

        final EventRecord actual = iterator.next();

        assertEventRecordsAreEqual(expected, actual);

        assertFalse(iterator.hasNext());
    }

    @Test
    public void return_iterator_pointed_to_first_element_if_read_all_events_several_times() {

        final List<EventRecord> expectedRecords = newArrayList(projectCreated(id), projectStarted(id), taskAdded(id));

        for (EventRecord r : expectedRecords) {
            STORAGE.store(r);
        }

        final Iterator<EventRecord> iteratorFirst = STORAGE.allEvents();
        final List<EventRecord> actualRecordsFirst = newArrayList(iteratorFirst);
        assertEventRecordListsAreEqual(expectedRecords, actualRecordsFirst);

        final Iterator<EventRecord> iteratorSecond = STORAGE.allEvents();
        final List<EventRecord> actualRecordsSecond = newArrayList(iteratorSecond);
        assertEventRecordListsAreEqual(expectedRecords, actualRecordsSecond);
    }

    private static void assertEventRecordListsAreEqual(List<EventRecord> expectedRecords, List<EventRecord> actualRecords) {
        if (expectedRecords.size() != actualRecords.size()) {
            fail("Expected records are not equal to actual");
        }
        for (int i = 0; i < expectedRecords.size(); i++) {
            assertEventRecordsAreEqual(expectedRecords.get(i), actualRecords.get(i));
        }
    }

    @SuppressWarnings("TypeMayBeWeakened")
    private static void assertEventRecordsAreEqual(EventRecord expected, EventRecord actual) {
        assertEquals(expected.getEvent(), actual.getEvent());
        assertEquals(expected.getContext(), actual.getContext());
    }
}

@@ -3951,23 +3951,16 @@
 expected
-Records
 , List%3CE
@@ -3977,23 +3977,16 @@
 %3E actual
-Records
 ) %7B%0A    
@@ -3997,31 +3997,24 @@
 if (expected
-Records
 .size() != a
@@ -4018,23 +4018,16 @@
 = actual
-Records
 .size())
@@ -4068,32 +4068,94 @@
 rds 
-are not equal to actual%22
+count: %22 + expected.size() + %22 is not equal to actual records count: %22 + actual.size()
 );%0A 
@@ -4199,23 +4199,16 @@
 expected
-Records
 .size();
@@ -4262,23 +4262,16 @@
 expected
-Records
 .get(i),
@@ -4277,23 +4277,16 @@
 , actual
-Records
 .get(i))

Rename variables and improve error message.