Repository: focus-shift/jollyday (java)

Issue:
Whit Sunday missing in Liechtenstein
### Affected country

Liechtenstein

### Affected public holiday

Whit Sunday

### Source of the information

https://en.wikipedia.org/wiki/Public_holidays_in_Liechtenstein

### More information

_No response_

Pull request description:
Improve Liechtenstein
closes #478

Patch:
diff --git a/jollyday-core/src/main/resources/holidays/Holidays_li.xml b/jollyday-core/src/main/resources/holidays/Holidays_li.xml
index f46d5038..6a41a73d 100644
--- a/jollyday-core/src/main/resources/holidays/Holidays_li.xml
+++ b/jollyday-core/src/main/resources/holidays/Holidays_li.xml
@@ -5,7 +5,7 @@
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="https://focus_shift.de/jollyday/schema/holiday https://focus_shift.de/jollyday/schema/holiday/holiday.xsd">
   <Holidays>
-    <Fixed month="JANUARY" day="1" descriptionPropertiesKey="NEW_YEAR"/>
+    <Fixed month="JANUARY" day="1" validFrom="1967" descriptionPropertiesKey="NEW_YEAR"/>
     <Fixed month="JANUARY" day="6" descriptionPropertiesKey="EPIPHANY"/>
     <Fixed month="FEBRUARY" day="2" descriptionPropertiesKey="CANDLEMAS"/>
     <Fixed month="MARCH" day="19" descriptionPropertiesKey="ST_JOSEPH"/>
@@ -14,13 +14,18 @@
     <Fixed month="SEPTEMBER" day="8" descriptionPropertiesKey="NATIVITY_LADY"/>
     <Fixed month="NOVEMBER" day="1" descriptionPropertiesKey="ALL_SAINTS"/>
     <Fixed month="DECEMBER" day="8" descriptionPropertiesKey="IMMACULATE_CONCEPTION"/>
-    <Fixed month="DECEMBER" day="24" descriptionPropertiesKey="CHRISTMAS_EVE"/>
     <Fixed month="DECEMBER" day="25" descriptionPropertiesKey="CHRISTMAS"/>
     <Fixed month="DECEMBER" day="26" descriptionPropertiesKey="STEPHENS"/>
     <ChristianHoliday type="EASTER" descriptionPropertiesKey="christian.EASTER"/>
-    <ChristianHoliday type="EASTER_MONDAY" descriptionPropertiesKey="christian.EASTER_MONDAY"/>
+    <ChristianHoliday type="EASTER_MONDAY" validFrom="1642" descriptionPropertiesKey="christian.EASTER_MONDAY"/>
+    <ChristianHoliday type="WHIT_SUNDAY" descriptionPropertiesKey="christian.WHIT_SUNDAY"/>
     <ChristianHoliday type="ASCENSION_DAY" descriptionPropertiesKey="christian.ASCENSION_DAY"/>
     <ChristianHoliday type="WHIT_MONDAY" descriptionPropertiesKey="christian.WHIT_MONDAY"/>
     <ChristianHoliday type="CORPUS_CHRISTI" descriptionPropertiesKey="christian.CORPUS_CHRISTI"/>
   </Holidays>
+
+  <Sources>
+    <Source>https://en.wikipedia.org/wiki/Public_holidays_in_Liechtenstein</Source>
+    <Source>https://www.llb.li/de/kontakt/bankfeiertage</Source>
+  </Sources>
 </Configuration>


Test patch:
diff --git a/jollyday-tests/src/test/java/de/focus_shift/jollyday/tests/country/HolidayLITest.java b/jollyday-tests/src/test/java/de/focus_shift/jollyday/tests/country/HolidayLITest.java
new file mode 100644
index 00000000..f4a511d5
--- /dev/null
+++ b/jollyday-tests/src/test/java/de/focus_shift/jollyday/tests/country/HolidayLITest.java
@@ -0,0 +1,195 @@
+package de.focus_shift.jollyday.tests.country;
+
+import de.focus_shift.jollyday.core.Holiday;
+import de.focus_shift.jollyday.core.HolidayManager;
+import net.jqwik.api.ForAll;
+import net.jqwik.api.Property;
+import net.jqwik.time.api.constraints.YearRange;
+
+import java.time.LocalDate;
+import java.time.Year;
+import java.util.Set;
+
+import static de.focus_shift.jollyday.core.HolidayCalendar.LIECHTENSTEIN;
+import static de.focus_shift.jollyday.core.HolidayType.OFFICIAL_HOLIDAY;
+import static de.focus_shift.jollyday.core.ManagerParameters.create;
+import static java.time.Month.AUGUST;
+import static java.time.Month.DECEMBER;
+import static java.time.Month.FEBRUARY;
+import static java.time.Month.JANUARY;
+import static java.time.Month.MARCH;
+import static java.time.Month.MAY;
+import static java.time.Month.NOVEMBER;
+import static java.time.Month.SEPTEMBER;
+import static org.assertj.core.api.Assertions.assertThat;
+
+class HolidayLITest extends AbstractCountryTestBase {
+
+  @Property
+  void ensuresThatNewYearIsOnFirstJanuaryAndNotConfiguredUntil1966(@ForAll @YearRange(max = 1966) Year year) {
+    final HolidayManager holidayManager = HolidayManager.getInstance(create(LIECHTENSTEIN));
+    final Set<Holiday> holidays = holidayManager.getHolidays(year.getValue());
+    assertThat(holidays)
+      .isNotEmpty()
+      .doesNotContain(new Holiday(LocalDate.of(year.getValue(), JANUARY, 1), "NEW_YEAR", OFFICIAL_HOLIDAY));
+  }
+
+  @Property
+  void ensuresThatNewYearIsOnFirstJanuaryIsConfiguredSince1967(@ForAll @YearRange(min = 1967) Year year) {
+    final HolidayManager holidayManager = HolidayManager.getInstance(create(LIECHTENSTEIN));
+    final Set<Holiday> holidays = holidayManager.getHolidays(year.getValue());
+    assertThat(holidays)
+      .isNotEmpty()
+      .contains(new Holiday(LocalDate.of(year.getValue(), JANUARY, 1), "NEW_YEAR", OFFICIAL_HOLIDAY));
+  }
+
+  @Property
+  void ensuresThatEpiphanyConfigured(@ForAll @YearRange Year year) {
+    final HolidayManager holidayManager = HolidayManager.getInstance(create(LIECHTENSTEIN));
+    final Set<Holiday> holidays = holidayManager.getHolidays(year.getValue());
+    assertThat(holidays)
+      .isNotEmpty()
+      .contains(new Holiday(LocalDate.of(year.getValue(), JANUARY, 6), "EPIPHANY", OFFICIAL_HOLIDAY));
+  }
+
+  @Property
+  void ensuresThatCandlemasConfigured(@ForAll @YearRange Year year) {
+    final HolidayManager holidayManager = HolidayManager.getInstance(create(LIECHTENSTEIN));
+    final Set<Holiday> holidays = holidayManager.getHolidays(year.getValue());
+    assertThat(holidays)
+      .isNotEmpty()
+      .contains(new Holiday(LocalDate.of(year.getValue(), FEBRUARY, 2), "CANDLEMAS", OFFICIAL_HOLIDAY));
+  }
+
+  @Property
+  void ensuresThatStJosephIsConfigured(@ForAll @YearRange Year year) {
+    final HolidayManager holidayManager = HolidayManager.getInstance(create(LIECHTENSTEIN));
+    final Set<Holiday> holidays = holidayManager.getHolidays(year.getValue());
+    assertThat(holidays)
+      .isNotEmpty()
+      .contains(new Holiday(LocalDate.of(year.getValue(), MARCH, 19), "ST_JOSEPH", OFFICIAL_HOLIDAY));
+  }
+
+  @Property
+  void ensuresThatMayDayIsConfigured(@ForAll @YearRange Year year) {
+    final HolidayManager holidayManager = HolidayManager.getInstance(create(LIECHTENSTEIN));
+    final Set<Holiday> holidays = holidayManager.getHolidays(year.getValue());
+    assertThat(holidays)
+      .isNotEmpty()
+      .contains(new Holiday(LocalDate.of(year.getValue(), MAY, 1), "MAY_DAY", OFFICIAL_HOLIDAY));
+  }
+
+  @Property
+  void ensuresThatAssumptionDayIsConfigured(@ForAll @YearRange Year year) {
+    final HolidayManager holidayManager = HolidayManager.getInstance(create(LIECHTENSTEIN));
+    final Set<Holiday> holidays = holidayManager.getHolidays(year.getValue());
+    assertThat(holidays)
+      .isNotEmpty()
+      .contains(new Holiday(LocalDate.of(year.getValue(), AUGUST, 15), "ASSUMPTION_DAY", OFFICIAL_HOLIDAY));
+  }
+
+  @Property
+  void ensuresThatNativityLadyIsConfigured(@ForAll @YearRange Year year) {
+    final HolidayManager holidayManager = HolidayManager.getInstance(create(LIECHTENSTEIN));
+    final Set<Holiday> holidays = holidayManager.getHolidays(year.getValue());
+    assertThat(holidays)
+      .isNotEmpty()
+      .contains(new Holiday(LocalDate.of(year.getValue(), SEPTEMBER, 8), "NATIVITY_LADY", OFFICIAL_HOLIDAY));
+  }
+
+  @Property
+  void ensuresThatAllSaintsIsConfigured(@ForAll @YearRange Year year) {
+    final HolidayManager holidayManager = HolidayManager.getInstance(create(LIECHTENSTEIN));
+    final Set<Holiday> holidays = holidayManager.getHolidays(year.getValue());
+    assertThat(holidays)
+      .isNotEmpty()
+      .contains(new Holiday(LocalDate.of(year.getValue(), NOVEMBER, 1), "ALL_SAINTS", OFFICIAL_HOLIDAY));
+  }
+
+  @Property
+  void ensuresThatImmaculateConceptionIsConfigured(@ForAll @YearRange Year year) {
+    final HolidayManager holidayManager = HolidayManager.getInstance(create(LIECHTENSTEIN));
+    final Set<Holiday> holidays = holidayManager.getHolidays(year.getValue());
+    assertThat(holidays)
+      .isNotEmpty()
+      .contains(new Holiday(LocalDate.of(year.getValue(), DECEMBER, 8), "IMMACULATE_CONCEPTION", OFFICIAL_HOLIDAY));
+  }
+
+  @Property
+  void ensuresThatChristmasIsConfigured(@ForAll @YearRange Year year) {
+    final HolidayManager holidayManager = HolidayManager.getInstance(create(LIECHTENSTEIN));
+    final Set<Holiday> holidays = holidayManager.getHolidays(year.getValue());
+    assertThat(holidays)
+      .isNotEmpty()
+      .contains(new Holiday(LocalDate.of(year.getValue(), DECEMBER, 25), "CHRISTMAS", OFFICIAL_HOLIDAY));
+  }
+
+  @Property
+  void ensuresThatStephensIsConfigured(@ForAll @YearRange Year year) {
+    final HolidayManager holidayManager = HolidayManager.getInstance(create(LIECHTENSTEIN));
+    final Set<Holiday> holidays = holidayManager.getHolidays(year.getValue());
+    assertThat(holidays)
+      .isNotEmpty()
+      .contains(new Holiday(LocalDate.of(year.getValue(), DECEMBER, 26), "STEPHENS", OFFICIAL_HOLIDAY));
+  }
+
+  @Property
+  void ensuresThatEasterIsConfigured(@ForAll @YearRange Year year) {
+    final HolidayManager holidayManager = HolidayManager.getInstance(create(LIECHTENSTEIN));
+    final Set<Holiday> holidays = holidayManager.getHolidays(year.getValue());
+    assertThat(holidays)
+      .isNotEmpty()
+      .extracting(Holiday::getPropertiesKey)
+      .contains("christian.EASTER");
+  }
+
+  @Property
+  void ensuresThatEasterMondayIsNotConfiguredUntil1641(@ForAll @YearRange(min = 1000, max = 1641) Year year) {
+    final HolidayManager holidayManager = HolidayManager.getInstance(create(LIECHTENSTEIN));
+    final Set<Holiday> holidays = holidayManager.getHolidays(year.getValue());
+    assertThat(holidays)
+      .isNotEmpty()
+      .extracting(Holiday::getPropertiesKey)
+      .doesNotContain("christian.EASTER_MONDAY");
+  }
+
+  @Property
+  void ensuresThatEasterMondayIsConfiguredSince1642(@ForAll @YearRange(min = 1642) Year year) {
+    final HolidayManager holidayManager = HolidayManager.getInstance(create(LIECHTENSTEIN));
+    final Set<Holiday> holidays = holidayManager.getHolidays(year.getValue());
+    assertThat(holidays)
+      .isNotEmpty()
+      .extracting(Holiday::getPropertiesKey)
+      .contains("christian.EASTER_MONDAY");
+  }
+
+  @Property
+  void ensuresThatAscensionDayIsConfigured(@ForAll @YearRange Year year) {
+    final HolidayManager holidayManager = HolidayManager.getInstance(create(LIECHTENSTEIN));
+    final Set<Holiday> holidays = holidayManager.getHolidays(year.getValue());
+    assertThat(holidays)
+      .isNotEmpty()
+      .extracting(Holiday::getPropertiesKey)
+      .contains("christian.ASCENSION_DAY");
+  }
+
+  @Property
+  void ensuresThatGoodFridayIsConfigured(@ForAll @YearRange Year year) {
+    final HolidayManager holidayManager = HolidayManager.getInstance(create(LIECHTENSTEIN));
+    final Set<Holiday> holidays = holidayManager.getHolidays(year.getValue());
+    assertThat(holidays)
+      .isNotEmpty()
+      .extracting(Holiday::getPropertiesKey)
+      .contains("christian.WHIT_MONDAY");
+  }
+
+  @Property
+  void ensuresThatWhitSundayIsConfiguredInAland(@ForAll @YearRange Year year) {
+    final HolidayManager holidayManager = HolidayManager.getInstance(create(LIECHTENSTEIN));
+    final Set<Holiday> holidays = holidayManager.getHolidays(year.getValue(), "01");
+    assertThat(holidays)
+      .isNotEmpty()
+      .extracting(Holiday::getPropertiesKey)
+      .contains("christian.CORPUS_CHRISTI");
+  }
+}