/*
 * Copyright 2015 Urs Metz
 *
 * 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 org.pitest.mutationtest.engine.gregor.mutators;

import org.junit.Before;
import org.junit.Test;
import org.pitest.functional.predicate.True;
import org.pitest.mutationtest.engine.Mutant;
import org.pitest.mutationtest.engine.gregor.MethodInfo;
import org.pitest.mutationtest.engine.gregor.MutatorTestBase;

import java.util.concurrent.Callable;

import static org.pitest.mutationtest.engine.gregor.mutators.NakedReceiverMutator.NAKED_RECEIVER;

public class NakedReceiverMutatorTest extends MutatorTestBase {

  @Before
  public void setupEngineToUseReplaceMethodWithArgumentOfSameTypeAsReturnValueMutator() {
    createTesteeWith(True.<MethodInfo> all(), NAKED_RECEIVER);
  }

  @Test
  public void shouldReplaceMethodCallOnString() throws Exception {
    final Mutant mutant = getFirstMutant(HasStringMethodCall.class);
    assertMutantCallableReturns(new HasStringMethodCall("EXAMPLE"), mutant,
        "EXAMPLE");
  }

  @Test
  public void shouldNotReplaceMethodCallWhenDifferentReturnType()
      throws Exception {
    assertNoMutants(HasMethodWithDifferentReturnType.class);
  }

  @Test
  public void shouldNotMutateVoidMethodCall()
      throws Exception {
    assertNoMutants(HasVoidMethodCall.class);
  }

  private static class HasStringMethodCall implements Callable<String> {
    private String arg;

    public HasStringMethodCall(String arg) {
      this.arg = arg;
    }

    public String call() throws Exception {
      return arg.toLowerCase();
    }
  }

  private static class HasMethodWithDifferentReturnType {
    public int call() throws Exception {
      return "".length();
    }
  }

  private static class HasVoidMethodCall {
    public void call() throws Exception {
    }
  }

}

@@ -916,29 +916,108 @@
 til.
-concurrent.Callable;%0A
+ArrayList;%0Aimport java.util.concurrent.Callable;%0A%0Aimport static java.util.Collections.singletonList;
 %0Aimp
@@ -1315,17 +1315,16 @@
 hodInfo%3E
- 
 all(), N
@@ -1807,22 +1807,16 @@
 odCall()
-%0A     
  throws 
@@ -1874,24 +1874,366 @@
 lass);%0A  %7D%0A%0A
+  @Test%0A  public void willReplaceCallToMethodWithDifferentGenericTypeDueToTypeErasure()%0A      throws Exception %7B%0A    Mutant mutant = getFirstMutant(CallsMethodsWithGenericTypes.class);%0A    Foo%3CString%3E receiver = new Foo%3CString%3E(%223%22);%0A    assertMutantCallableReturns(new CallsMethodsWithGenericTypes(receiver),%0A        mutant, receiver);%0A  %7D%0A%0A
   private st
@@ -2711,10 +2711,511 @@
  %7D%0A  %7D%0A%0A
+  private static class CallsMethodsWithGenericTypes%0A      implements Callable%3CFoo%3C?%3E%3E %7B%0A    private Foo%3CString%3E myArg;%0A%0A    public CallsMethodsWithGenericTypes(Foo%3CString%3E myArg) %7B%0A      this.myArg = myArg;%0A    %7D%0A%0A    public Foo%3C?%3E call() %7B%0A      return myArg.returnsFooInteger();%0A    %7D%0A  %7D%0A%0A  private static class Foo%3CT%3E extends ArrayList%3CT%3E %7B%0A%0A    public Foo(T arg) %7B%0A      super(singletonList(arg));%0A    %7D%0A%0A    public Foo%3CInteger%3E returnsFooInteger() %7B%0A      return new Foo%3CInteger%3E(2);%0A    %7D%0A  %7D%0A%0A
 %7D%0A

test for generically typed receiver