/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.class2greylist;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import static java.util.Collections.emptySet;

import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;

import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;

import java.io.IOException;
import java.util.Map;

public class CovariantReturnTypeMultiHandlerTest extends AnnotationHandlerTestBase {


    @Before
    public void setup() throws IOException {
        // To keep the test simpler and more concise, we don't use the real
        // @CovariantReturnType annotation here, but use our own @Annotation
        // and @Annotation.Multi that have the same semantics. It doesn't have
        // to match the real annotation, just have the same properties
        // (returnType and value).
        mJavac.addSource("annotation.Annotation", Joiner.on('\n').join(
                "package annotation;",
                "import static java.lang.annotation.RetentionPolicy.CLASS;",
                "import java.lang.annotation.Repeatable;",
                "import java.lang.annotation.Retention;",
                "@Repeatable(Annotation.Multi.class)",
                "@Retention(CLASS)",
                "public @interface Annotation {",
                "  Class<?> returnType();",
                "  @Retention(CLASS)",
                "  @interface Multi {",
                "    Annotation[] value();",
                "  }",
                "}"));
    }

    @Test
    public void testReturnTypeMulti() throws IOException {
        mJavac.addSource("a.b.Class", Joiner.on('\n').join(
                "package a.b;",
                "import annotation.Annotation;",
                "public class Class {",
                "  @Annotation(returnType=Integer.class)",
                "  @Annotation(returnType=Long.class)",
                "  public String method() {return null;}",
                "}"));
        assertThat(mJavac.compile()).isTrue();

        Map<String, AnnotationHandler> handlerMap =
                ImmutableMap.of("Lannotation/Annotation$Multi;",
                        new CovariantReturnTypeMultiHandler(
                                mConsumer,
                                ImmutableSet.of("La/b/Class;->method()Ljava/lang/String;"),
                                "Lannotation/Annotation;"));
        new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();

        assertNoErrors();
        ArgumentCaptor<String> whitelist = ArgumentCaptor.forClass(String.class);
        verify(mConsumer, times(2)).whitelistEntry(whitelist.capture());
        assertThat(whitelist.getAllValues()).containsExactly(
                "La/b/Class;->method()Ljava/lang/Integer;",
                "La/b/Class;->method()Ljava/lang/Long;"
        );
    }

    @Test
    public void testReturnTypeMultiNotPublicApi() throws IOException {
        mJavac.addSource("a.b.Class", Joiner.on('\n').join(
                "package a.b;",
                "import annotation.Annotation;",
                "public class Class {",
                "  @Annotation(returnType=Integer.class)",
                "  @Annotation(returnType=Long.class)",
                "  public String method() {return null;}",
                "}"));
        assertThat(mJavac.compile()).isTrue();

        Map<String, AnnotationHandler> handlerMap =
                ImmutableMap.of("Lannotation/Annotation$Multi;",
                        new CovariantReturnTypeMultiHandler(
                                mConsumer,
                                emptySet(),
                                "Lannotation/Annotation;"));
        new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();

        verify(mStatus, atLeastOnce()).error(any(), any());
    }
}
