/*
 * Copyright 2022 The Error Prone Authors.
 *
 * 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.google.errorprone.bugpatterns.checkreturnvalue;

import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;

import com.google.common.collect.ImmutableSet;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Tests for {@link Api}. */
@RunWith(JUnit4.class)
public final class ApiTest {

  private static final ImmutableSet<String> UNPARSEABLE_APIS =
      ImmutableSet.of(
          "",
          "#()",
          "#(java.lang.String)",
          "#foo()",
          "#foo(java.lang.String)",
          "java.lang.String",
          "java.lang.String##foo()",
          "java.lang.String#fo#o()",
          "java.lang.String#()",
          "java.lang.String#foo)()",
          "java.lang.String#foo)(",
          "java.lang.String#<init>(,)",
          "java.lang.String#<>()",
          "java.lang.String#hi<>()",
          "java.lang.String#<>hi()",
          "java.lang.String#hi<init>()",
          "java.lang.String#<init>hi()",
          "java.lang.String#<iniT>()",
          "java.lang.String#<init>((java.lang.String)",
          "java.lang.String#<init>(java.lang.String",
          "java.lang.String#<init>(java.lang.String,)",
          "java.lang.String#<init>(,java.lang.String)",
          "java.lang.String#<init>(java.lang.String))");

  @Test
  public void parseApi_badInputs() {
    // TODO(b/223670489): would be nice to use expectThrows() here
    for (String badApi : UNPARSEABLE_APIS) {
      assertThrows(
          "Api.parse(\"" + badApi + "\")", IllegalArgumentException.class, () -> Api.parse(badApi));
    }
  }

  @Test
  public void parseApi_constructorWithoutParams() {
    String string = "com.google.async.promisegraph.testing.TestPromiseGraphModule#<init>()";
    Api api = Api.parse(string);
    assertThat(api.className())
        .isEqualTo("com.google.async.promisegraph.testing.TestPromiseGraphModule");
    assertThat(api.methodName()).isEqualTo("<init>");
    assertThat(api.parameterTypes()).isEmpty();
    assertThat(api.isConstructor()).isTrue();
    assertThat(api.toString()).isEqualTo(string);
  }

  @Test
  public void parseApi_constructorWithParams() {
    String string = "com.google.api.client.http.GenericUrl#<init>(java.lang.String)";
    Api api = Api.parse(string);
    assertThat(api.className()).isEqualTo("com.google.api.client.http.GenericUrl");
    assertThat(api.methodName()).isEqualTo("<init>");
    assertThat(api.parameterTypes()).containsExactly("java.lang.String").inOrder();
    assertThat(api.isConstructor()).isTrue();
    assertThat(api.toString()).isEqualTo(string);
  }

  @Test
  public void parseApi_methodWithoutParams() {
    String string = "com.google.api.services.drive.model.File#getId()";
    Api api = Api.parse(string);
    assertThat(api.className()).isEqualTo("com.google.api.services.drive.model.File");
    assertThat(api.methodName()).isEqualTo("getId");
    assertThat(api.parameterTypes()).isEmpty();
    assertThat(api.isConstructor()).isFalse();
    assertThat(api.toString()).isEqualTo(string);
  }

  @Test
  public void parseApi_methodWithParamsAndSpaces() {
    String string =
        "com.google.android.libraries.stitch.binder.Binder"
            + "#get(android.content.Context,java.lang.Class)";
    Api api = Api.parse(string);
    assertThat(api.methodName()).isEqualTo("get");
    assertThat(api.parameterTypes())
        .containsExactly("android.content.Context", "java.lang.Class")
        .inOrder();
    assertThat(api.isConstructor()).isFalse();
    assertThat(api.toString()).isEqualTo(string);
  }

  @Test
  public void parseApi_methodWithArray_b219754967() {
    IllegalArgumentException thrown =
        assertThrows(
            "b/219754967 - cannot parse array signatures",
            IllegalArgumentException.class,
            () ->
                Api.parse(
                    "com.google.inject.util.Modules.OverriddenModuleBuilder"
                        + "#with(com.google.inject.Module[])"));
    assertThat(thrown).hasMessageThat().contains("'[' is not a valid identifier");
  }
}

@@ -4710,11 +4710,566 @@
 r%22);%0A  %7D
+%0A%0A  @Test%0A  public void parseApi_methodWithVarargs_b231250004() %7B%0A    String string = %22com.beust.jcommander.JCommander#%3Cinit%3E(java.lang.Object,java.lang.String...)%22;%0A    Api api = Api.parse(string);%0A    assertThat(api.className()).isEqualTo(%22com.beust.jcommander.JCommander%22);%0A    assertThat(api.methodName()).isEqualTo(%22%3Cinit%3E%22);%0A    assertThat(api.parameterTypes())%0A        .containsExactly(%22java.lang.Object%22, %22java.lang.String...%22)%0A        .inOrder();%0A    assertThat(api.isConstructor()).isTrue();%0A    assertThat(api.toString()).isEqualTo(string);%0A  %7D
 %0A%7D%0A

Add a test that demonstrates the Api parses var-args correctly.