/*
 * Copyright 2016, 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.projection;

import com.google.common.collect.ImmutableSet;
import com.google.protobuf.BoolValue;
import com.google.protobuf.Int32Value;
import com.google.protobuf.Message;
import com.google.protobuf.StringValue;
import org.junit.Before;
import org.junit.Test;
import org.spine3.base.EventContext;
import org.spine3.server.event.Subscribe;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.spine3.base.Identifiers.newUuid;
import static org.spine3.protobuf.Values.newIntegerValue;
import static org.spine3.protobuf.Values.newStringValue;

@SuppressWarnings("InstanceMethodNamingConvention")
public class ProjectionShould {

    private TestProjection projection;

    @Before
    public void setUp() {
        projection = new TestProjection(newUuid());
    }

    @Test
    public void handle_events() {
        final String stringValue = newUuid();
        projection.handle(newStringValue(stringValue), EventContext.getDefaultInstance());
        assertTrue(projection.getState()
                             .getValue()
                             .contains(stringValue));

        final Integer integerValue = 1024;
        projection.handle(newIntegerValue(integerValue), EventContext.getDefaultInstance());
        assertTrue(projection.getState()
                             .getValue()
                             .contains(String.valueOf(integerValue)));
    }

    @Test(expected = IllegalStateException.class)
    public void throw_exception_if_no_handler_for_event() {
        projection.handle(BoolValue.getDefaultInstance(), EventContext.getDefaultInstance());
    }

    @Test
    public void return_event_classes_which_it_handles() {
        final ImmutableSet<Class<? extends Message>> classes = Projection.getEventClasses(TestProjection.class);

        assertEquals(2, classes.size());
        assertTrue(classes.contains(StringValue.class));
        assertTrue(classes.contains(Int32Value.class));
    }

    private static class TestProjection extends Projection<String, StringValue> {

        protected TestProjection(String id) {
            super(id);
        }

        @Subscribe
        public void on(StringValue event, EventContext ignored) {
            final StringValue newSate = createNewState("stringState", event.getValue());
            incrementState(newSate);
        }

        @Subscribe
        public void on(Int32Value event) {
            final StringValue newSate = createNewState("integerState", String.valueOf(event.getValue()));
            incrementState(newSate);
        }

        private StringValue createNewState(String type, String value) {
            final String currentState = getState().getValue();
            final String result = currentState + (currentState.length() > 0 ? " + " : "") +
                    type + '(' + value + ')' + System.lineSeparator();
            return newStringValue(result);
        }
    }
}

@@ -2882,17 +2882,51 @@
 tEquals(
-2
+TestProjection.HANDLING_EVENT_COUNT
 , classe
@@ -3135,24 +3135,140 @@
 ngValue%3E %7B%0A%0A
+        /** The number of events this class handles. */%0A        private static final int HANDLING_EVENT_COUNT = 2;%0A%0A
         prot

Extract a constant.