/*
 * Copyright 2019 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.time;

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

/**
 * Tests for {@link InvalidJavaTimeConstant}.
 *
 * @author kak@google.com (Kurt Alfred Kluever)
 */
@RunWith(JUnit4.class)
public class InvalidJavaTimeConstantTest {

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

  @Test
  public void cornerCases() {
    compilationHelper
        .addSourceLines(
            "test/TestCase.java",
            "package test;",
            "import java.time.LocalDateTime;",
            "import java.time.LocalTime;",
            "public class TestCase {",
            "  // BUG: Diagnostic contains: MonthOfYear (valid values 1 - 12): 0",
            "  private static final LocalDateTime LDT0 = LocalDateTime.of(0, 0, 0, 0, 0);",
            "  private static final LocalDateTime LDT1 = LocalDateTime.of(0, 1, 1, 0, 0);",
            "  private static final LocalTime LT = LocalTime.ofNanoOfDay(12345678);",
            "}")
        .doTest();
  }

  @Test
  public void localDate_areOk() {
    compilationHelper
        .addSourceLines(
            "test/TestCase.java",
            "package test;",
            "import java.time.LocalDate;",
            "import java.time.Month;",
            "public class TestCase {",
            "  private static final LocalDate LD0 = LocalDate.of(1985, 5, 31);",
            "  private static final LocalDate LD1 = LocalDate.of(1985, Month.MAY, 31);",
            // we can't catch this since it's not a literal
            "  private static final LocalDate LD2 = LocalDate.of(1985, getBadMonth(), 31);",
            "  private static int getBadMonth() { return 13; }",
            "  private static final LocalDate EPOCH_DAY_ZERO = LocalDate.ofEpochDay(0);",
            "  private static final LocalDate EPOCH_DAY_LARGE = LocalDate.ofEpochDay(123467);",
            "}")
        .doTest();
  }

  @Test
  public void localDate_withBadDays() {
    compilationHelper
        .addSourceLines(
            "test/TestCase.java",
            "package test;",
            "import java.time.LocalDate;",
            "import java.time.Month;",
            "public class TestCase {",
            "  // BUG: Diagnostic contains: DayOfMonth (valid values 1 - 28/31): 32",
            "  private static final LocalDate LD0 = LocalDate.of(1985, 5, 32);",
            "  // BUG: Diagnostic contains: DayOfMonth (valid values 1 - 28/31): 32",
            "  private static final LocalDate LD1 = LocalDate.of(1985, Month.MAY, 32);",
            "}")
        .doTest();
  }

  @Test
  public void localDate_withBadMonths() {
    compilationHelper
        .addSourceLines(
            "test/TestCase.java",
            "package test;",
            "import java.time.LocalDate;",
            "public class TestCase {",
            "  // BUG: Diagnostic contains: MonthOfYear (valid values 1 - 12): -1",
            "  private static final LocalDate LD0 = LocalDate.of(1985, -1, 31);",
            "  // BUG: Diagnostic contains: MonthOfYear (valid values 1 - 12): 0",
            "  private static final LocalDate LD1 = LocalDate.of(1985, 0, 31);",
            "  // BUG: Diagnostic contains: MonthOfYear (valid values 1 - 12): 13",
            "  private static final LocalDate LD2 = LocalDate.of(1985, 13, 31);",
            "}")
        .doTest();
  }

  @Test
  public void localDate_withBadYears() {
    compilationHelper
        .addSourceLines(
            "test/TestCase.java",
            "package test;",
            "import java.time.LocalDate;",
            "import java.time.Year;",
            "public class TestCase {",
            "  // BUG: Diagnostic contains: Year (valid values -999999999 - 999999999):"
                + " -1000000000",
            "  private static final LocalDate LD0 = LocalDate.of(Year.MIN_VALUE - 1, 5, 31);",
            "  // BUG: Diagnostic contains: Year (valid values -999999999 - 999999999): 1000000000",
            "  private static final LocalDate LD1 = LocalDate.of(Year.MAX_VALUE + 1, 5, 31);",
            "}")
        .doTest();
  }

  @Test
  public void localDate_withBadDayOfMonth() {
    compilationHelper
        .addSourceLines(
            "test/TestCase.java",
            "package test;",
            "import java.time.LocalDate;",
            "public class TestCase {",
            "  private static LocalDate foo(LocalDate localDate) {",
            "    // BUG: Diagnostic contains: DayOfMonth (valid values 1 - 28/31): 0",
            "    return localDate.withDayOfMonth(0);",
            "  }",
            "}")
        .doTest();
  }

  @Test
  public void localTime_withBadHour() {
    compilationHelper
        .addSourceLines(
            "test/TestCase.java",
            "package test;",
            "import java.time.LocalTime;",
            "public class TestCase {",
            "  private static LocalTime foo(LocalTime localTime) {",
            "    // BUG: Diagnostic contains: HourOfDay (valid values 0 - 23): 25",
            "    return localTime.withHour(25);",
            "  }",
            "}")
        .doTest();
  }

  @Test
  public void dayOfWeek_withBadDay() {
    compilationHelper
        .addSourceLines(
            "test/TestCase.java",
            "package test;",
            "import java.time.DayOfWeek;",
            "public class TestCase {",
            "  // BUG: Diagnostic contains: DayOfWeek (valid values 1 - 7): 8",
            "  private static final DayOfWeek DOW = DayOfWeek.of(8);",
            "}")
        .doTest();
  }
}
