/*
 * Copyright (c) 2018 Mockito contributors
 * This program is made available under the terms of the MIT License.
 */
package org.mockitousage.stubbing;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.withSettings;

import org.assertj.core.api.Assertions;
import org.junit.Test;
import org.mockito.Answers;

// Reproduces issue #1551
public class SmartNullsGenericBugTest {

    @Test
    public void smart_nulls_generic_bug_generic_T() {
        ConcreteDao concreteDao =
                mock(ConcreteDao.class, withSettings().defaultAnswer(Answers.RETURNS_SMART_NULLS));

        final Entity result = concreteDao.findById();

        Assertions.assertThat(result).as("#1551").isNotNull();
    }

    @Test
    public void smart_nulls_generic_bug_generic_M() {
        ConcreteDao concreteDao =
                mock(ConcreteDao.class, withSettings().defaultAnswer(Answers.RETURNS_SMART_NULLS));

        final String other = concreteDao.find();

        Assertions.assertThat(other).as("#1551 - CCannot resolve type").isNull();
    }

    @Test
    public void smart_nulls_generic_bug_generic_M_provided_in_args() {
        ConcreteDao concreteDao =
                mock(ConcreteDao.class, withSettings().defaultAnswer(Answers.RETURNS_SMART_NULLS));

        final String other = concreteDao.findArgs(1, "plop");

        Assertions.assertThat(other).as("#1551").isEqualTo("");
    }

    @Test
    public void smart_nulls_generic_bug_generic_M_provided_as_varargs() {
        ConcreteDao concreteDao =
                mock(ConcreteDao.class, withSettings().defaultAnswer(Answers.RETURNS_SMART_NULLS));

        final String other = concreteDao.findVarargs(42, "plip", "plop");

        Assertions.assertThat(other).as("#1551").isEqualTo("");
    }

    static class AbstractDao<T> {
        T findById() {
            return null;
        }

        <M> M find() {
            return null;
        }

        <M> M findArgs(int idx, M arg) {
            return null;
        }

        <M> M findVarargs(int idx, M... args) {
            return null;
        }
    }

    static class Entity {}

    static class ConcreteDao extends AbstractDao<Entity> {}
}
