From 746b36e80d112444dcdfa0fdfbd93d15e7a8dcae Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Thu, 23 Jan 2025 21:48:29 +0100 Subject: [PATCH] Improve tests * Dedup using parameterized tests * Make ``now`` controllable --- .../extractor/localization/TimeAgoParser.java | 16 +- .../localization/TimeAgoPatternsManager.java | 15 ++ .../localization/TimeAgoParserTest.java | 229 ++++++++---------- 3 files changed, 126 insertions(+), 134 deletions(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/localization/TimeAgoParser.java b/extractor/src/main/java/org/schabi/newpipe/extractor/localization/TimeAgoParser.java index edf03e370..619de9e74 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/localization/TimeAgoParser.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/localization/TimeAgoParser.java @@ -28,8 +28,22 @@ public class TimeAgoParser { * language word separator. */ public TimeAgoParser(final PatternsHolder patternsHolder) { + this(patternsHolder, OffsetDateTime.now(ZoneOffset.UTC)); + } + + /** + * Creates a helper to parse upload dates in the format '2 days ago'. + *

+ * Instantiate a new {@link TimeAgoParser} every time you extract a new batch of items. + *

+ * + * @param patternsHolder An object that holds the "time ago" patterns, special cases, and the + * language word separator. + * @param now The current time + */ + public TimeAgoParser(final PatternsHolder patternsHolder, final OffsetDateTime now) { this.patternsHolder = patternsHolder; - now = OffsetDateTime.now(ZoneOffset.UTC); + this.now = now; } /** diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/localization/TimeAgoPatternsManager.java b/extractor/src/main/java/org/schabi/newpipe/extractor/localization/TimeAgoPatternsManager.java index 19b697661..47889a5d3 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/localization/TimeAgoPatternsManager.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/localization/TimeAgoPatternsManager.java @@ -3,6 +3,8 @@ package org.schabi.newpipe.extractor.localization; import org.schabi.newpipe.extractor.timeago.PatternsHolder; import org.schabi.newpipe.extractor.timeago.PatternsManager; +import java.time.OffsetDateTime; + import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -26,4 +28,17 @@ public final class TimeAgoPatternsManager { return new TimeAgoParser(holder); } + + @Nullable + public static TimeAgoParser getTimeAgoParserFor( + @Nonnull final Localization localization, + @Nonnull final OffsetDateTime now) { + final PatternsHolder holder = getPatternsFor(localization); + + if (holder == null) { + return null; + } + + return new TimeAgoParser(holder, now); + } } diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/localization/TimeAgoParserTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/localization/TimeAgoParserTest.java index a5d3e9cbb..db45e807b 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/localization/TimeAgoParserTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/localization/TimeAgoParserTest.java @@ -1,151 +1,114 @@ package org.schabi.newpipe.extractor.localization; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.schabi.newpipe.extractor.localization.TimeAgoParserTest.ParseTimeAgoTestData.greaterThanDay; +import static org.schabi.newpipe.extractor.localization.TimeAgoParserTest.ParseTimeAgoTestData.lessThanDay; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.schabi.newpipe.extractor.exceptions.ParsingException; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import java.time.Duration; +import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.temporal.ChronoUnit; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Stream; -public class TimeAgoParserTest { - private static TimeAgoParser parser; - private static OffsetDateTime now; - - @BeforeAll - public static void setUp() { - parser = TimeAgoPatternsManager.getTimeAgoParserFor(Localization.DEFAULT); - now = OffsetDateTime.now(ZoneOffset.UTC); +class TimeAgoParserTest { + public static Stream parseTimeAgo() { + return Stream.of( + lessThanDay(Duration.ofSeconds(1), "1 second", "1 sec"), + lessThanDay(Duration.ofSeconds(12), "12 second", "12 sec"), + lessThanDay(Duration.ofMinutes(1), "1 minute", "1 min"), + lessThanDay(Duration.ofMinutes(23), "23 minutes", "23 min"), + lessThanDay(Duration.ofHours(1), "1 hour", "1 hr"), + lessThanDay(Duration.ofHours(8), "8 hour", "8 hr"), + greaterThanDay(d -> d.minusDays(1), "1 day", "1 day"), + greaterThanDay(d -> d.minusDays(3), "3 days", "3 day"), + greaterThanDay(d -> d.minusWeeks(1), "1 week", "1 wk"), + greaterThanDay(d -> d.minusWeeks(3), "3 weeks", "3 wk"), + greaterThanDay(d -> d.minusMonths(1), "1 month", "1 mo"), + greaterThanDay(d -> d.minusMonths(3), "3 months", "3 mo"), + greaterThanDay(d -> d.minusYears(1).minusDays(1), "1 year", "1 yr"), + greaterThanDay(d -> d.minusYears(3).minusDays(1), "3 years", "3 yr") + ).map(Arguments::of); } - @Test - void parseTimeAgo() throws ParsingException { - assertTimeWithin1s( - now.minusSeconds(1), - parser.parse("1 second ago").offsetDateTime() - ); - assertTimeWithin1s( - now.minusSeconds(12), - parser.parse("12 second ago").offsetDateTime() - ); - assertTimeWithin1s( - now.minusMinutes(1), - parser.parse("1 minute ago").offsetDateTime() - ); - assertTimeWithin1s( - now.minusMinutes(23), - parser.parse("23 minutes ago").offsetDateTime() - ); - assertTimeWithin1s( - now.minusHours(1), - parser.parse("1 hour ago").offsetDateTime() - ); - assertTimeWithin1s( - now.minusHours(8), - parser.parse("8 hours ago").offsetDateTime() - ); - assertEquals( - now.minusDays(1).truncatedTo(ChronoUnit.HOURS), - parser.parse("1 day ago").offsetDateTime() - ); - assertEquals( - now.minusDays(3).truncatedTo(ChronoUnit.HOURS), - parser.parse("3 days ago").offsetDateTime() - ); - assertEquals( - now.minusWeeks(1).truncatedTo(ChronoUnit.HOURS), - parser.parse("1 week ago").offsetDateTime() - ); - assertEquals( - now.minusWeeks(3).truncatedTo(ChronoUnit.HOURS), - parser.parse("3 weeks ago").offsetDateTime() - ); - assertEquals( - now.minusMonths(1).truncatedTo(ChronoUnit.HOURS), - parser.parse("1 month ago").offsetDateTime() - ); - assertEquals( - now.minusMonths(3).truncatedTo(ChronoUnit.HOURS), - parser.parse("3 months ago").offsetDateTime() - ); - assertEquals( - now.minusYears(1).minusDays(1).truncatedTo(ChronoUnit.HOURS), - parser.parse("1 year ago").offsetDateTime() - ); - assertEquals( - now.minusYears(3).minusDays(1).truncatedTo(ChronoUnit.HOURS), - parser.parse("3 years ago").offsetDateTime() + @ParameterizedTest + @MethodSource + void parseTimeAgo(final ParseTimeAgoTestData testData) { + final OffsetDateTime now = OffsetDateTime.of( + LocalDateTime.of(2020, 1, 1, 1, 1, 1), + ZoneOffset.UTC); + final TimeAgoParser parser = Objects.requireNonNull( + TimeAgoPatternsManager.getTimeAgoParserFor(Localization.DEFAULT, now)); + + final OffsetDateTime expected = testData.getExpectedApplyToNow().apply(now); + + assertAll( + Stream.of( + testData.getTextualDateLong(), + testData.getTextualDateShort()) + .map(textualDate -> () -> assertEquals( + expected, + parser.parse(textualDate).offsetDateTime(), + "Expected " + expected + " for " + textualDate + )) ); } - @Test - void parseTimeAgoShort() throws ParsingException { - final TimeAgoParser parser = TimeAgoPatternsManager.getTimeAgoParserFor(Localization.DEFAULT); - final OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC); + static class ParseTimeAgoTestData { + public static final String AGO_SUFFIX = " ago"; + private final Function expectedApplyToNow; + private final String textualDateLong; + private final String textualDateShort; - assertTimeWithin1s( - now.minusSeconds(1), - parser.parse("1 sec ago").offsetDateTime() - ); - assertTimeWithin1s( - now.minusSeconds(12), - parser.parse("12 sec ago").offsetDateTime() - ); - assertTimeWithin1s( - now.minusMinutes(1), - parser.parse("1 min ago").offsetDateTime() - ); - assertTimeWithin1s( - now.minusMinutes(23), - parser.parse("23 min ago").offsetDateTime() - ); - assertTimeWithin1s( - now.minusHours(1), - parser.parse("1 hr ago").offsetDateTime() - ); - assertTimeWithin1s( - now.minusHours(8), - parser.parse("8 hr ago").offsetDateTime() - ); - assertEquals( - now.minusDays(1).truncatedTo(ChronoUnit.HOURS), - parser.parse("1 day ago").offsetDateTime() - ); - assertEquals( - now.minusDays(3).truncatedTo(ChronoUnit.HOURS), - parser.parse("3 days ago").offsetDateTime() - ); - assertEquals( - now.minusWeeks(1).truncatedTo(ChronoUnit.HOURS), - parser.parse("1 wk ago").offsetDateTime() - ); - assertEquals( - now.minusWeeks(3).truncatedTo(ChronoUnit.HOURS), - parser.parse("3 wk ago").offsetDateTime() - ); - assertEquals( - now.minusMonths(1).truncatedTo(ChronoUnit.HOURS), - parser.parse("1 mo ago").offsetDateTime() - ); - assertEquals( - now.minusMonths(3).truncatedTo(ChronoUnit.HOURS), - parser.parse("3 mo ago").offsetDateTime() - ); - assertEquals( - now.minusYears(1).minusDays(1).truncatedTo(ChronoUnit.HOURS), - parser.parse("1 yr ago").offsetDateTime() - ); - assertEquals( - now.minusYears(3).minusDays(1).truncatedTo(ChronoUnit.HOURS), - parser.parse("3 yr ago").offsetDateTime() - ); - } + ParseTimeAgoTestData( + final Function expectedApplyToNow, + final String textualDateLong, + final String textualDateShort + ) { + this.expectedApplyToNow = expectedApplyToNow; + this.textualDateLong = textualDateLong; + this.textualDateShort = textualDateShort; + } - void assertTimeWithin1s(final OffsetDateTime expected, final OffsetDateTime actual) { - final long delta = Math.abs(expected.toEpochSecond() - actual.toEpochSecond()); - assertTrue(delta <= 1, String.format("Expected: %s\nActual: %s", expected, actual)); + public static ParseTimeAgoTestData lessThanDay( + final Duration duration, + final String textualDateLong, + final String textualDateShort + ) { + return new ParseTimeAgoTestData( + d -> d.minus(duration), + textualDateLong + AGO_SUFFIX, + textualDateShort + AGO_SUFFIX); + } + + public static ParseTimeAgoTestData greaterThanDay( + final Function expectedApplyToNow, + final String textualDateLong, + final String textualDateShort + ) { + return new ParseTimeAgoTestData( + d -> expectedApplyToNow.apply(d).truncatedTo(ChronoUnit.HOURS), + textualDateLong + AGO_SUFFIX, + textualDateShort + AGO_SUFFIX); + } + + public Function getExpectedApplyToNow() { + return expectedApplyToNow; + } + + public String getTextualDateLong() { + return textualDateLong; + } + + public String getTextualDateShort() { + return textualDateShort; + } } }