/*
 * Copyright 2021, TeamDev. All rights reserved.
 *
 * 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
 *
 * 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.reflect;

import io.spine.reflect.given.MethodHolder;
import io.spine.reflect.given.ObjMethodHolder;
import kotlin.reflect.KCallable;
import kotlin.reflect.KParameter;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Optional;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static kotlin.reflect.KParameter.Kind.INSTANCE;
import static kotlin.reflect.KParameter.Kind.VALUE;

@DisplayName("`J2Kt` should")
class J2KtTest {

    @Test
    @DisplayName("find a static method in a class")
    void findStatic() throws NoSuchMethodException {
        String name = "staticMethod";
        Method method = MethodHolder.class.getDeclaredMethod(name, int.class);
        Optional<KCallable<?>> found = J2Kt.findKotlinMethod(method);
        assertThat(found)
                .isPresent();
        KCallable<?> ktMethod = found.get();
        assertThat(ktMethod.getName())
                .isEqualTo(name);
        List<KParameter> params = ktMethod.getParameters();
        assertThat(params)
                .hasSize(2);
        assertThat(params.get(0).getKind())
                .isEqualTo(INSTANCE);
        assertThat(params.get(1).getKind())
                .isEqualTo(VALUE);
    }

    @Test
    @DisplayName("find a instance method a single argument in a class")
    void findInstance() throws NoSuchMethodException {
        String name = "instanceMethod";
        Method method = MethodHolder.class.getDeclaredMethod(name, String.class);
        Optional<KCallable<?>> found = J2Kt.findKotlinMethod(method);
        assertThat(found)
                .isPresent();
        KCallable<?> ktMethod = found.get();
        assertThat(ktMethod.getName())
                .isEqualTo(name);
        List<KParameter> params = ktMethod.getParameters();
        assertThat(params)
                .hasSize(2);
        assertThat(params.get(0).getKind())
                .isEqualTo(INSTANCE);
        assertThat(params.get(1).getKind())
                .isEqualTo(VALUE);
    }

    @Test
    @DisplayName("find a instance method with no arguments in a class")
    void findInstanceNoArg() throws NoSuchMethodException {
        String name = "noParamMethod";
        Method method = MethodHolder.class.getDeclaredMethod(name);
        Optional<KCallable<?>> found = J2Kt.findKotlinMethod(method);
        assertThat(found)
                .isPresent();
        KCallable<?> ktMethod = found.get();
        assertThat(ktMethod.getName())
                .isEqualTo(name);
        List<KParameter> params = ktMethod.getParameters();
        assertThat(params)
                .hasSize(1);
        assertThat(params.get(0).getKind())
                .isEqualTo(INSTANCE);
    }

    @Test
    @DisplayName("find a static method in an object")
    void findStaticInObj() throws NoSuchMethodException {
        String name = "staticObjMethod";
        Method method = ObjMethodHolder.class.getDeclaredMethod(name);
        Optional<KCallable<?>> found = J2Kt.findKotlinMethod(method);
        assertThat(found)
                .isPresent();
        KCallable<?> ktMethod = found.get();
        assertThat(ktMethod.getName())
                .isEqualTo(name);
        List<KParameter> params = ktMethod.getParameters();
        assertThat(params)
                .hasSize(1);
        assertThat(params.get(0).getKind())
                .isEqualTo(INSTANCE);
    }

    @Test
    @DisplayName("find a instance method in an object")
    void findInstanceInObj() throws NoSuchMethodException {
        String name = "instanceObjMethod";
        Method method = ObjMethodHolder.class.getDeclaredMethod(name);
        Optional<KCallable<?>> found = J2Kt.findKotlinMethod(method);
        assertThat(found)
                .isPresent();
        KCallable<?> ktMethod = found.get();
        assertThat(ktMethod.getName())
                .isEqualTo(name);
        List<KParameter> params = ktMethod.getParameters();
        assertThat(params)
                .hasSize(1);
        assertThat(params.get(0).getKind())
                .isEqualTo(INSTANCE);
    }
}

@@ -1417,24 +1417,63 @@
 KParameter;%0A
+import kotlin.reflect.KParameter.Kind;%0A
 import org.j
@@ -1502,16 +1502,16 @@
 ayName;%0A
-
 import o
@@ -1738,115 +1738,8 @@
 hat;
-%0Aimport static kotlin.reflect.KParameter.Kind.INSTANCE;%0Aimport static kotlin.reflect.KParameter.Kind.VALUE;
 %0A%0A@D
@@ -2439,32 +2439,37 @@
      .isEqualTo(
+Kind.
 INSTANCE);%0A     
@@ -2526,32 +2526,37 @@
      .isEqualTo(
+Kind.
 VALUE);%0A    %7D%0A%0A 
@@ -3236,32 +3236,37 @@
      .isEqualTo(
+Kind.
 INSTANCE);%0A     
@@ -3331,16 +3331,21 @@
 EqualTo(
+Kind.
 VALUE);%0A
@@ -4023,32 +4023,37 @@
      .isEqualTo(
+Kind.
 INSTANCE);%0A    %7D
@@ -4711,32 +4711,37 @@
      .isEqualTo(
+Kind.
 INSTANCE);%0A    %7D
@@ -5378,32 +5378,32 @@
 t(0).getKind())%0A
-
                 
@@ -5413,16 +5413,21 @@
 EqualTo(
+Kind.
 INSTANCE

Fix a "BadImport"