/*
 * Copyright 2016 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;

import com.google.errorprone.CompilationTestHelper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** {@link IdentityBinaryExpression}Test */
@RunWith(JUnit4.class)
public class IdentityBinaryExpressionTest {

  private final CompilationTestHelper compilationHelper =
      CompilationTestHelper.newInstance(IdentityBinaryExpression.class, getClass());

  @Test
  public void positive() {
    compilationHelper
        .addSourceLines(
            "Test.java",
            """
            class Test {
              boolean f(boolean a) {
                // BUG: Diagnostic contains:
                return a || a;
              }

              boolean g(boolean a) {
                // BUG: Diagnostic contains:
                return a && a;
              }

              boolean h(boolean a) {
                // BUG: Diagnostic contains:
                return f(a) && f(a);
              }

              boolean i(boolean a) {
                boolean r;
                // BUG: Diagnostic contains:
                r = a & a;
                // BUG: Diagnostic contains:
                r = a | a;
                return r;
              }

              int j(int x) {
                int r;
                // BUG: Diagnostic contains:
                r = x & x;
                // BUG: Diagnostic contains:
                r = x | x;
                return x;
              }
            }
            """)
        .doTest();
  }

  @Test
  public void negative() {
    compilationHelper
        .addSourceLines(
            "Test.java",
            """
            class Test {
              boolean f(boolean a, boolean b) {
                return a || b;
              }

              boolean g(boolean a, boolean b) {
                return a && b;
              }

              boolean h(boolean a, boolean b) {
                return a & b;
              }

              boolean i(boolean a, boolean b) {
                return a | b;
              }

              int j(int a, int b) {
                return a & b;
              }

              int k(int a, int b) {
                return a | b;
              }
            }
            """)
        .doTest();
  }

  @Test
  public void negativeLiteral() {
    compilationHelper
        .addSourceLines(
            "Test.java",
            """
            class Test {
              double f() {
                return 1.0 / 1.0;
              }
            }
            """)
        .doTest();
  }

  @Test
  public void fixes() {
    compilationHelper
        .addSourceLines(
            "in/Test.java",
            """
            class Test {
              void f(int a) {
                // BUG: Diagnostic contains: equivalent to `1`
                int r = a / a;
                // BUG: Diagnostic contains: equivalent to `0`
                r = a - a;
                // BUG: Diagnostic contains: equivalent to `0`
                r = a % a;
                // BUG: Diagnostic contains: equivalent to `true`
                boolean b = a >= a;
                // BUG: Diagnostic contains: equivalent to `true`
                b = a == a;
                // BUG: Diagnostic contains: equivalent to `true`
                b = a <= a;
                // BUG: Diagnostic contains: equivalent to `false`
                b = a > a;
                // BUG: Diagnostic contains: equivalent to `false`
                b = a < a;
                // BUG: Diagnostic contains: equivalent to `false`
                b = a != a;
                // BUG: Diagnostic contains: equivalent to `false`
                b = b ^ b;
              }
            }
            """)
        .doTest();
  }

  @Test
  public void negativeAssert() {
    compilationHelper
        .addSourceLines(
            "Test.java",
            """
            import static org.junit.Assert.assertTrue;
            import static org.junit.Assert.assertFalse;

            class Test {
              void f(int x) {
                assertTrue(x == x);
                assertFalse(x != x);
              }
            }
            """)
        .doTest();
  }

  @Test
  public void isNaN() {
    compilationHelper
        .addSourceLines(
            "Test.java",
            """
            class Test {
              boolean f(float a, Float b, double c, Double d) {
                boolean r = false;
                // BUG: Diagnostic contains: equivalent to `!Float.isNaN(a)`
                r |= a == a;
                // BUG: Diagnostic contains: equivalent to `Float.isNaN(a)`
                r |= a != a;
                // BUG: Diagnostic contains: equivalent to `!Float.isNaN(b)`
                r |= b == b;
                // BUG: Diagnostic contains: equivalent to `Float.isNaN(b)`
                r |= b != b;
                // BUG: Diagnostic contains: equivalent to `!Double.isNaN(c)`
                r |= c == c;
                // BUG: Diagnostic contains: equivalent to `Double.isNaN(c)`
                r |= c != c;
                // BUG: Diagnostic contains: equivalent to `!Double.isNaN(d)`
                r |= d == d;
                // BUG: Diagnostic contains: equivalent to `Double.isNaN(d)`
                r |= d != d;
                return r;
              }
            }
            """)
        .doTest();
  }
}
