code: package de.tu_darmstadt.stg.mubench.utils;
  
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.fail;
  
  import java.io.ByteArrayInputStream;
  import java.nio.charset.StandardCharsets;
  import java.nio.file.Files;
  import java.nio.file.Paths;
  
  import org.junit.Test;
  
  public class MethodExtractorTest {
  
  	@Test
  	public void findsMethodByName() throws Exception {
  		testFindsMethod("class C {\n"
  				+ "  public void m() {\n"
  				+ "  }\n"
  				+ "}",
  				
  				"m()",
  				
  				"  public void m() {\n"
  				+ "  }");
  	}
  	
  	@Test
  	public void findsMethodBySignature() throws Exception {
  		testFindsMethod("class C{\n"
  				+ "  void m(int i) {}\n"
  				+ "  void m(Object o) {}\n"
  				+ "}",
  				
  				"m(int)",
  				
  				"  void m(int i) {}");
  	}
  	
  	@Test
  	public void findsMethodBySignatureSimpleTypeName() throws Exception {
  		testFindsMethod("class C{\n"
  				+ "  void m(java.lang.List l) {}\n"
  				+ "  void m(Object o) {}\n"
  				+ "}",
  				
  				"m(List)",
  				
  				"  void m(java.lang.List l) {}");
  	}
  	
  	@Test
  	public void findsMethodByMultipleParameterSignature() throws Exception {
  		testFindsMethod("class C{\n"
  				+ "  void m(A a, B b) {}\n"
  				+ "}",
  				
  				"m(A, B)",
  				
  				"  void m(A a, B b) {}");
  	}
  
  	@Test
  	public void findsMethodWithArrayParameter() throws Exception {
  		testFindsMethod("class C{\n"
  				+ "  void m(int[] is) {}\n"
  				+ "}",
  
  				"m(int[])",
  
  				"  void m(int[] is) {}");
  	}
  
  	@Test
  	public void findsMethodWithArrayParameterAlternativeSyntax() throws Exception {
  		testFindsMethod("class C{\n"
  						+ "  void m(int is[]) {}\n"
  						+ "}",
  
  				"m(int[])",
  
  				"  void m(int is[]) {}");
  	}
  
  	@Test
  	public void findsMethodWithVarArgsParameter() throws Exception {
  		testFindsMethod("class C{\n"
  						+ "  void m(int... is) {}\n"
  						+ "}",
  
  				"m(int[])",
  
  				"  void m(int... is) {}");
  	}
  
  	@Test
  	public void findsMethodWithGenericParameter() throws Exception {
  		testFindsMethod("class C{\n"
  				+ "  void m(A<B> a) {}\n"
  				+ "}",
  				
  				"m(A)",
  				
  				"  void m(A<B> a) {}");
  	}
  
      @Test
      public void findsMethodWithGenericParameter2() throws Exception {
          testFindsMethod("class C{\n"
                          + "  void m(A<B> a) {}\n"
                          + "}",
  
                  "m(A<B>)",
  
                  "  void m(A<B> a) {}");
      }
  
      @Test
      public void findsMethodWithGenericParameter3() throws Exception {
          testFindsMethod("class C{\n"
                          + "  void m(A a) {}\n"
                          + "}",
  
                  "m(A<B>)",
  
                  "  void m(A a) {}");
      }
  
  	@Test
  	public void findsMethodWithInnerTypeParameter() throws Exception {
  		testFindsMethod("class C {\n" +
  				"  class I {}\n" +
  				"  void m(I i) {}\n" +
  				"}",
  
  				"m(C$I)",
  
  				"  void m(I i) {}");
  	}
  
  	@Test
  	public void findsMethodWithFinalParameter() throws Exception {
  		testFindsMethod("class C {\n" +
  				"  void m(final A a) {}\n" +
  				"}",
  
  				"m(A)",
  
  				"  void m(final A a) {}");
  	}
  
  	@Test
  	public void findsStaticMethod() throws Exception {
  		testFindsMethod("class C {\n" +
  				"  static void m() {}\n" +
  				"}",
  
  				"m()",
  
  				"  static void m() {}");
  	}
  
  	@Test
  	public void findsConstructorByClassName() throws Exception {
  		testFindsMethod("class C{\n"
  				+ "  C() {}\n"
  				+ "}",
  				
  				"C()",
  				
  				"  C() {}");
  	}
  	
  	@Test
  	public void findsConstructorByInitIdentifier() throws Exception {
  		testFindsMethod("class C{\n"
  				+ "  C() {}\n"
  				+ "}",
  				
  				"<init>()",
  				
  				"  C() {}");
  	}
  	
  	@Test
  	public void findsMethodInInnerClass() throws Exception {
  		testFindsMethod("class C {\n"
  				+ "  class I {\n"
  				+ "    void m() {}\n"
  				+ "  }\n"
  				+ "}",
  				
  				"m()",
  				
  				"    void m() {}");
  	}
  	
  	@Test
  	public void findsMethodInAnonymousClass() throws Exception {
  		testFindsMethod("class C {\n"
  				+ "  void m() {\n"
  				+ "    new Object() {\n"
  				+ "      void n() {}\n"
  				+ "    };\n"
  				+ "  }\n"
  				+ "}",
  				
  				"n()",
  				
  				"      void n() {}");
  	}
  
  	@Test
  	public void findsMethodInAnonymousClassInConstructor() throws Exception {
  		testFindsMethod("class C {\n"
  						+ "  C() {\n"
  						+ "    new Object() {\n"
  						+ "      void n() {}\n"
  						+ "    };\n"
  						+ "  }\n"
  						+ "}",
  
  				"n()",
  
  				"      void n() {}");
  	}
  
  	@Test
  	public void findsConstructorOfNonStaticInnerClass() throws Exception {
  		testFindsMethod("class C {\n"
  						+ "  class I {\n"
  						+ "    I() {}\n"
  						+ "  }\n"
  						+ "}",
  
  				"I(C)",
  
  				"    I() {}");
  	}
  
  	@Test
  	public void returnsDeclaringType() throws Exception {
  		testFindsDeclaringType("class C {\n"
  				+ "  void m() {}\n"
  				+ "}",
  				
  				"m()",
  				
  				"C");
  	}
  	
  	@Test
  	public void returnsDeclaringTypeInInnerType() throws Exception {
  		testFindsDeclaringType("class C {\n"
  				+ "  class I {\n"
  				+ "    void m() {}\n"
  				+ "  }\n"
  				+ "}",
  				
  				"m()",
  				
  				"C.I");
  	}
  	
  	@Test
  	public void returnsDeclaringTypeAfterInnerType() throws Exception {
  		testFindsDeclaringType("class C {\n"
  				+ "  class I {}\n"
  				+ "  void m() {}\n"
  				+ "}",
  				
  				"m()",
  				
  				"C");
  	}
  
  	@Test
  	public void includesBody() throws Exception {
  		testFindsMethod("class C {\n"
  				+ "  public void m() {\n"
  				+ "    if (true) {\n"
  				+ "      m();\n"
  				+ "    }\n"
  				+ "  }\n"
  				+ "}",
  				
  				"m()",
  				
  				"  public void m() {\n"
  				+ "    if (true) {\n"
  				+ "      m();\n"
  				+ "    }\n"
  				+ "  }");
  	}
  
  	@Test
  	public void includesComment() throws Exception {
  		testFindsMethod("class C {\n"
  				+ "  /* comment */\n"
  				+ "  public void m() {}\n"
  				+ "}",
  				
  				"m()",
  				
  				"  /* comment */\n"
  				+ "  public void m() {}");
  	}
  
  	@Test
  	public void includesJavaDocComment() throws Exception {
  		testFindsMethod("class C {\n"
  				+ "  /**\n"
  				+ "   * comment\n"
  				+ "   */\n"
  				+ "  public void m() {}\n"
  				+ "}",
  				
  				"m()",
  				
  				"  /**\n"
  				+ "   * comment\n"
  				+ "   */\n"
  				+ "  public void m() {}");
  	}
  	
  	@Test
  	public void returnsLineNumber() throws Exception {
  		testFindsLineNumber("class C {\n"
  				+ "  void m() {}\n"
  				+ "}",
  				
  				"m()",
  				
  				"2");
  	}
  	
  	@Test
  	public void returnsLineNumberOfComment() throws Exception {
  		testFindsLineNumber("class C {\n"
  				+ "  /* comment */\n"
  				+ "  void m() {}\n"
  				+ "}",
  				
  				"m()",
  				
  				"2");
  	}
  	
  	@Test
  	public void returnsAllCandidates() throws Exception {
  		String output = runUUT("class C {\n"
  				+ "  void m(){}\n"
  				+ "  class I {\n"
  				+ "    void m(){}\n"
  				+ "  }\n"
  				+ "}",
  				
  				"m()");
  		String[] candidates = output.split("===");
  		assertEquals(2, candidates.length);
  	}
  
  	@Test
  	public void handlesWhitespaceAfterMethodName() throws Exception {
  		testFindsMethod("class HTTPFrame {\n"
  						+ "    public Reply browse (Request request) {}\n"
  						+ "}",
  				"browse(Request)",
  				"    public Reply browse (Request request) {}");
  	}
  
  	@Test
  	public void handlesGenericsInParameterType() throws Exception {
  		testFindsMethod("class Tarjan<T> {\n"
  						+ "    private void run(T v) {}\n"
  						+ "}",
  				"run(Object)",
  				"    private void run(T v) {}");
  	}
  
  	@Test
  	public void handlesGenericArrayTypes() throws Exception {
  		testFindsMethod("class Utils {\n"
  						+ "    public static XmlClass[] classesToXmlClasses(Class<?>[] classes) {}\n"
  						+ "}",
  				"classesToXmlClasses(Class[])",
  				"    public static XmlClass[] classesToXmlClasses(Class<?>[] classes) {}");
  	}
  
  	@Test
  	public void handlesNestedTypeParameters() throws Exception {
  		testFindsMethod("class C {\n"
  						+ "    void foo(Object<T1<?>, T2>[] c) {}\n"
  						+ "}",
  				"foo(Object[])",
  				"    void foo(Object<T1<?>, T2>[] c) {}");
  	}
  
  	@Test
  	public void handlesStaticInitializationBlock() throws Exception {
  		testFindsMethod("class C {\n"
  						+ "    static {}\n"
  						+ "}",
  				"<clinit>()",
  				"    static {}");
  	}
  
  	@Test
  	public void handlesDefaultConstructor() throws Exception {
  		testFindsMethod("class C {}",
  				"<init>()",
  				"C() { /* compiler-generated default constructor -- may contain field initialization code */ }");
  	}
  
  	@Test
  	public void handlesStaticInitializationBlockOnSourceCodeDetection() throws Exception {
  		testFindsMethod("class C {\n"
  						+ "    static {}\n"
  						+ "}",
  				"static()",
  				"    static {}");
  	}
  
  	@Test
  	public void acceptsEnumAsIdentifier() throws Exception {
  		testFindsMethod("class C {\n"
  						+ "    void foo() {\n"
  						+ "        Object enum;\n"
  						+ "    }\n"
  						+ "}",
  				"foo()",
  						"    void foo() {\n"
  						+ "        Object enum;\n"
  						+ "    }");
  	}
  
  	@Test
  	public void fallsBackToMatchingOnlyByMethodName() throws Exception {
  		testFindsMethod("class C {\n"
  						+ "    void foo(int i) {\n"
  						+ "    }\n"
  						+ "}",
  				"foo()",
  				        "    void foo(int i) {\n"
  						+ "    }");
  	}
  
  	private void testFindsMethodFromFile(String filePath, String methodSignature, String expectedOutput) throws Exception {
  		String input = new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8);
  		testFindsMethod(input, methodSignature, expectedOutput);
  	}
  
  	private void testFindsMethod(String input, String methodSignature, String expectedOutput) throws Exception {
  		String output = runUUT(input, methodSignature);
          String[] data = output.split(":", 3);
          if (data.length < 3) {
              fail("No method found.");
          }
          String methodCode = data[2];
  		assertEquals(expectedOutput, methodCode);
  	}
  	
  	private void testFindsDeclaringType(String input, String methodSignature, String expectedDeclaringType) throws Exception {
  		String output = runUUT(input, methodSignature);
  		String declaringType = output.split(":", 3)[1];
  		assertEquals(expectedDeclaringType, declaringType);
  	}
  	
  	private void testFindsLineNumber(String input, String methodSignature, String expectedLineNumber) throws Exception {
  		String output = runUUT(input, methodSignature);
  		String lineNumber = output.split(":", 3)[0];
  		assertEquals(expectedLineNumber, lineNumber);
  	}
  
  	private String runUUT(String input, String methodSignature) throws Exception {
  		MethodExtractor methodExtractor = new MethodExtractor();
  		ByteArrayInputStream inputStream = new ByteArrayInputStream(input.getBytes());
  		return methodExtractor.extract(inputStream, methodSignature);
  	}
  }
  