/*
 * Copyright 2017, 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 io.spine.option;

import com.google.common.base.Joiner;
import com.google.protobuf.DescriptorProtos.DescriptorProto;
import com.google.protobuf.DescriptorProtos.MessageOptions;
import com.google.protobuf.GeneratedMessage.GeneratedExtension;
import com.google.protobuf.StringValue;
import org.junit.Test;

import java.util.Arrays;
import java.util.Collection;

import static io.spine.option.OptionsProto.enrichment;
import static io.spine.option.RawListParser.getValueSeparator;
import static io.spine.option.UnknownOptions.getUnknownOptionValue;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class RawListParserShould {

    private static final String OPTION_PART = "PART";

    private final OptionParser<DescriptorProto, String> parser = new AListParser(enrichment);

    @Test
    public void return_empty_collection_if_option_is_not_present() {
        final DescriptorProto definitionWithoutOption = StringValue.getDescriptor()
                                                                   .toProto();
        final Collection<String> result = parser.parse(definitionWithoutOption);
        assertTrue(result.isEmpty());
    }

    @SuppressWarnings("ConstantConditions") // Purpose of the test.
    @Test(expected = IllegalArgumentException.class)
    public void not_allow_null_option_value() {
        final String nullStr = null;
        parser.parse(nullStr);
    }

    @Test(expected = IllegalArgumentException.class)
    public void not_allow_empty_option_value() {
        parser.parse("");
    }

    @Test(expected = IllegalStateException.class)
    public void not_allow_blank_value() {
        final String blank = "   ";
        final Iterable<String> values = Arrays.asList(blank, "non-blank");
        final String optionValue = Joiner.on(getValueSeparator())
                                         .join(values);
        parser.parse(optionValue);
    }

    @Test
    public void split_option_value_and_remove_spaces() {
        final Collection<String> expectedValues = asList(OPTION_PART, OPTION_PART);
        final String spaceBeforeSeparator = ' ' + getValueSeparator();
        final String optionValue = Joiner.on(spaceBeforeSeparator)
                                         .join(expectedValues);
        final Collection<String> parsedValues = parser.parse(optionValue);
        assertEquals(expectedValues, parsedValues);
    }

    private static class AListParser extends RawListParser<MessageOptions, DescriptorProto, String> {

        private AListParser(GeneratedExtension<MessageOptions, String> option) {
            super(option);
        }

        @Override
        protected String getOptionValue(DescriptorProto descriptor, int optionNumber) {
            return getUnknownOptionValue(descriptor, optionNumber);
        }

        @Override
        protected Collection<String> wrapParts(Collection<String> parts) {
            return parts;
        }
    }
}

@@ -1074,16 +1074,54 @@
 Joiner;%0A
+import com.google.protobuf.BoolValue;%0A
 import c
@@ -1297,16 +1297,63 @@
 ension;%0A
+import com.google.protobuf.GeneratedMessageV3;%0A
 import c
@@ -1412,33 +1412,8 @@
 t;%0A%0A
-import java.util.Arrays;%0A
 impo
@@ -1560,76 +1560,8 @@
 or;%0A
-import static io.spine.option.UnknownOptions.getUnknownOptionValue;%0A
 impo
@@ -2785,23 +2785,16 @@
 alues = 
-Arrays.
 asList(b
@@ -3081,195 +3081,503 @@
 ng%3E 
-expectedValues = asList(OPTION_PART, OPTION_PART
+result = parser.parse(AListParser.MESSAGE_WITH_OPTION);%0A        assertEquals(AListParser.EXPECTED_RESULT, result
 );%0A    
+%7D%0A%0A
     
-final String spaceBeforeSeparator = ' ' + getValueSeparator();%0A        final String optionValue = Joiner.on(spaceBeforeSepara
+private static class AListParser extends RawListParser%3CMessageOptions, DescriptorProto, String%3E %7B%0A%0A        /**%0A         * If this descriptor is passed to %7B@link RawListParser#parse(GeneratedMessageV3)%7D,%0A         * %7B@link #OPTION_VALUE_WITH_SPACES%7D will be returned.%0A         */%0A        private static final DescriptorProto MESSAGE_WITH_OPTION = BoolValue.getDescrip
 tor
+(
 )%0A  
@@ -3619,266 +3619,382 @@
     
+                                  
-.join(expectedValues);%0A        final Collection%3CString%3E parsedValues = parser.parse(optionValue);%0A        assertEquals(expectedValues, parsedValues);%0A    %7D%0A%0A    private static class AListParser extends RawListParser%3CMessageOptions, DescriptorProto, String%3E %7B
+ .toProto();%0A        private static final String OPTION_VALUE_WITH_SPACES =%0A                %22   %22 + OPTION_PART + %22  , %22 + OPTION_PART + %22    %22;%0A%0A        /**%0A         * The expected result for parsing %7B@link #MESSAGE_WITH_OPTION%7D.%0A         */%0A        private static final Iterable%3CString%3E EXPECTED_RESULT = asList(OPTION_PART, OPTION_PART);
 %0A%0A  
@@ -4102,32 +4102,101 @@
 on);%0A        %7D%0A%0A
+        @SuppressWarnings(%22ReturnOfNull%22) // Contract of the method.%0A
         @Overrid
@@ -4308,55 +4308,120 @@
 urn 
-getUnknownOptionValue(descriptor, optionNumber)
+descriptor.equals(MESSAGE_WITH_OPTION)%0A                    ? OPTION_VALUE_WITH_SPACES%0A                    : null
 ;%0A  

Add missing test case for `RawListParser`