From a9cb4807815b645b8bb1245f38a0824657ede6e3 Mon Sep 17 00:00:00 2001 From: FMorschel <52160996+FMorschel@users.noreply.github.com> Date: Thu, 7 Dec 2023 02:25:41 -0300 Subject: [PATCH 01/16] Big review for tests and statical analysis --- analysis_options.yaml | 6 +- lib/due_date.dart | 16 +- lib/fix_data/fix_date_validator.yaml | 134 +++++++ lib/src/constants.dart | 41 +++ lib/src/date_validator.dart | 59 +++- lib/src/due_date.dart | 21 +- lib/src/enums.dart | 80 ++++- lib/src/every.dart | 406 +++++++++++++-------- lib/src/extensions.dart | 4 +- lib/src/period.dart | 57 ++- lib/src/period_generator.dart | 31 +- pubspec.yaml | 10 +- test/date_validator_test.dart | 34 +- test/due_date_test.dart | 55 +-- test/enums_test.dart | 34 +- test/every_test.dart | 503 +++++++++++++++++++++++---- test/extensions_test.dart | 32 +- test/period_generator_test.dart | 180 +++++----- test/period_test.dart | 151 ++++---- 19 files changed, 1332 insertions(+), 522 deletions(-) create mode 100644 lib/fix_data/fix_date_validator.yaml create mode 100644 lib/src/constants.dart diff --git a/analysis_options.yaml b/analysis_options.yaml index a668208..2cfa6e0 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,4 +1,4 @@ -include: package:lints/recommended.yaml +include: package:very_good_analysis/analysis_options.yaml analyzer: plugins: @@ -68,6 +68,10 @@ dart_code_metrics: linter: rules: + omit_local_variable_types: false + avoid_equals_and_hash_code_on_mutable_classes: false + always_use_package_imports: false + public_member_api_docs: true always_declare_return_types: true always_put_required_named_parameters_first: true always_require_non_null_named_parameters: true diff --git a/lib/due_date.dart b/lib/due_date.dart index f5df691..2195733 100644 --- a/lib/due_date.dart +++ b/lib/due_date.dart @@ -10,7 +10,7 @@ /// [WeekdayOccurrence]s constants) and [EveryDayInYear]. /// /// The [Every] class is a base class that processes all the base operations for -/// [DueDateTime]. You can mix in one of the folowing mixins: +/// [DueDateTime]. You can mix in one of the following mixins: /// - [EveryWeek]; /// - [EveryMonth]; /// - [EveryYear]; @@ -23,16 +23,20 @@ /// class. library due_date; +import 'src/due_date.dart'; +import 'src/enums.dart' show WeekdayOccurrence; +import 'src/every.dart'; + export 'src/date_validator.dart'; export 'src/due_date.dart'; -export 'src/enums.dart' show Weekday, Month, Week, WeekdayOccurrence; +export 'src/enums.dart' show Month, Week, Weekday, WeekdayOccurrence; export 'src/every.dart'; export 'src/extensions.dart' show - DayInYear, AddDays, - WeekCalc, ClampInMonth, - PreviousNext, DateValidatorListExt, - EveryDateValidatorListExt; + DayInYear, + EveryDateValidatorListExt, + PreviousNext, + WeekCalc; diff --git a/lib/fix_data/fix_date_validator.yaml b/lib/fix_data/fix_date_validator.yaml new file mode 100644 index 0000000..2923017 --- /dev/null +++ b/lib/fix_data/fix_date_validator.yaml @@ -0,0 +1,134 @@ + +version: 1 +transforms: + - title: "Use 'Weekday.occurrencesIn' instead." + date: 2023-11-28 + bulkApply: true + element: + uris: ['package:due_date/due_date.dart', 'package:due_date/period.dart'] + method: 'occrurencesIn' + inClass: 'Weekday' + changes: + - kind: 'rename' + newName: 'occurrencesIn' + + - title: "Use 'DateValidator.filterValidDates' instead." + date: 2023-11-28 + bulkApply: true + element: + uris: ['package:due_date/due_date.dart', 'package:due_date/period.dart'] + method: 'validsIn' + inClass: 'DateValidator' + changes: + - kind: 'rename' + newName: 'filterValidDates' + + - title: "Use 'DateValidatorMixin.filterValidDates' instead." + date: 2023-11-28 + bulkApply: true + element: + uris: ['package:due_date/due_date.dart', 'package:due_date/period.dart'] + method: 'validsIn' + inClass: 'DateValidatorMixin' + changes: + - kind: 'rename' + newName: 'filterValidDates' + + - title: "Use 'DateValidatorWeekday.filterValidDates' instead." + date: 2023-11-28 + bulkApply: true + element: + uris: ['package:due_date/due_date.dart', 'package:due_date/period.dart'] + method: 'validsIn' + inClass: 'DateValidatorWeekday' + changes: + - kind: 'rename' + newName: 'filterValidDates' + + - title: "Use 'DateValidatorDueDayMonth.filterValidDates' instead." + date: 2023-11-28 + bulkApply: true + element: + uris: ['package:due_date/due_date.dart', 'package:due_date/period.dart'] + method: 'validsIn' + inClass: 'DateValidatorDueDayMonth' + changes: + - kind: 'rename' + newName: 'filterValidDates' + + - title: "Use 'DateValidatorWeekdayCountInMonth.filterValidDates' instead." + date: 2023-11-28 + bulkApply: true + element: + uris: ['package:due_date/due_date.dart', 'package:due_date/period.dart'] + method: 'validsIn' + inClass: 'DateValidatorWeekdayCountInMonth' + changes: + - kind: 'rename' + newName: 'filterValidDates' + + - title: "Use 'DateValidatorDayInYear.filterValidDates' instead." + date: 2023-11-28 + bulkApply: true + element: + uris: ['package:due_date/due_date.dart', 'package:due_date/period.dart'] + method: 'validsIn' + inClass: 'DateValidatorDayInYear' + changes: + - kind: 'rename' + newName: 'filterValidDates' + + - title: "Use 'DateValidatorListMixin.filterValidDates' instead." + date: 2023-11-28 + bulkApply: true + element: + uris: ['package:due_date/due_date.dart', 'package:due_date/period.dart'] + method: 'validsIn' + inClass: 'DateValidatorListMixin' + changes: + - kind: 'rename' + newName: 'filterValidDates' + + - title: "Use 'DateValidatorIntersection.filterValidDates' instead." + date: 2023-11-28 + bulkApply: true + element: + uris: ['package:due_date/due_date.dart', 'package:due_date/period.dart'] + method: 'validsIn' + inClass: 'DateValidatorIntersection' + changes: + - kind: 'rename' + newName: 'filterValidDates' + + - title: "Use 'DateValidatorUnion.filterValidDates' instead." + date: 2023-11-28 + bulkApply: true + element: + uris: ['package:due_date/due_date.dart', 'package:due_date/period.dart'] + method: 'validsIn' + inClass: 'DateValidatorUnion' + changes: + - kind: 'rename' + newName: 'filterValidDates' + + - title: "Use 'DateValidatorDifference.filterValidDates' instead." + date: 2023-11-28 + bulkApply: true + element: + uris: ['package:due_date/due_date.dart', 'package:due_date/period.dart'] + method: 'validsIn' + inClass: 'DateValidatorDifference' + changes: + - kind: 'rename' + newName: 'filterValidDates' + + - title: "Use 'DateValidatorDifference.filterValidDates' instead." + date: 2023-11-28 + bulkApply: true + element: + uris: ['package:due_date/due_date.dart', 'package:due_date/period.dart'] + method: 'validsIn' + inClass: 'DateValidatorDifference' + changes: + - kind: 'rename' + newName: 'filterValidDates' diff --git a/lib/src/constants.dart b/lib/src/constants.dart new file mode 100644 index 0000000..c2ad3d0 --- /dev/null +++ b/lib/src/constants.dart @@ -0,0 +1,41 @@ +import '../due_date.dart'; + +/// Simple class to delegate the work to a given [Every] base process. +/// For every one one of the everies that is a [LimitedEvery], the limit +/// will be passed. +class LimitedOrEveryHandler { + const LimitedOrEveryHandler._(); + + /// Returns the start date considering the given [every] base process. + /// If [every] is a [LimitedEvery], the [limit] will be passed on. + static DateTime startDate( + T every, + DateTime date, { + required DateTime? limit, + }) { + if (every is! LimitedEvery) return every.startDate(date); + return every.startDate(date, limit: limit); + } + + /// Returns the next date considering the given [every] base process. + /// If [every] is a [LimitedEvery], the [limit] will be passed on. + static DateTime next( + T every, + DateTime date, { + required DateTime? limit, + }) { + if (every is! LimitedEvery) return every.next(date); + return every.next(date, limit: limit); + } + + /// Returns the previous date considering the given [every] base process. + /// If [every] is a [LimitedEvery], the [limit] will be passed on. + static DateTime previous( + T every, + DateTime date, { + required DateTime? limit, + }) { + if (every is! LimitedEvery) return every.previous(date); + return every.previous(date, limit: limit); + } +} diff --git a/lib/src/date_validator.dart b/lib/src/date_validator.dart index 67f924a..27530d6 100644 --- a/lib/src/date_validator.dart +++ b/lib/src/date_validator.dart @@ -10,16 +10,46 @@ abstract class DateValidator { const DateValidator(); /// Returns true if the [date] is valid for this [DateValidator]. + /// + /// This is the opposite of [valid]. + /// Implementations that return true for invalid should also return false for + /// valid. bool valid(DateTime date); + /// Returns true if the [date] is invalid for this [DateValidator]. + /// + /// This is the opposite of [valid]. + /// Implementations that return true for invalid should also return false for + /// valid. + /// + /// Usually, this will be implemented as `!valid(date)` by + /// [DateValidatorMixin]. However, if there is a simpler way to check + /// for invalid dates, it can be implemented here. + bool invalid(DateTime date); + + @Deprecated("Use 'DateValidator.filterValidDates' instead.") + + /// Returns the valid dates for this [DateValidator] in [dates]. + Iterable validsIn(Iterable dates); + /// Returns the valid dates for this [DateValidator] in [dates]. - Iterable validsIn(List dates); + Iterable filterValidDates(Iterable dates); } -/// Mixin to easily implement the [DateValidator.validsIn] method. +/// Mixin to easily implement the [DateValidator.invalid], +/// [DateValidator.filterValidDates] and [DateValidator.filterValidDates] +/// methods. mixin DateValidatorMixin implements DateValidator { @override - Iterable validsIn(List dates) sync* { + bool invalid(DateTime date) => !valid(date); + + @override + @Deprecated("Use 'DateValidator.filterValidDates' instead.") + Iterable validsIn(Iterable dates) => + filterValidDates(dates); + + @override + Iterable filterValidDates(Iterable dates) sync* { for (final date in dates) { if (valid(date)) yield date; } @@ -312,21 +342,32 @@ class DateValidatorUnion extends DelegatingList /// one of the [validators]. class DateValidatorDifference extends DelegatingList with EquatableMixin, DateValidatorMixin, DateValidatorListMixin { - /// A [DateValidator] that validates a [DateTime] if the date is valid for only - /// one of the [validators]. + /// A [DateValidator] that validates a [DateTime] if the date is valid for + /// only one of the [validators]. const DateValidatorDifference(super.validators); @override bool valid(DateTime date) { - int valids = 0; + int validCount = 0; for (final validator in validators) { - if (validator.valid(date)) valids++; - if (valids > 1) return false; + if (validator.valid(date)) validCount++; + if (validCount > 1) return false; } - if (valids == 0) return false; + if (validCount == 0) return false; return true; } + @override + bool invalid(DateTime date) { + int validCount = 0; + for (final validator in validators) { + if (validator.valid(date)) validCount++; + if (validCount > 1) return true; + } + if (validCount == 0) return true; + return false; + } + @override // ignore: hash_and_equals, already implemented by EquatableMixin bool operator ==(Object other) { diff --git a/lib/src/due_date.dart b/lib/src/due_date.dart index 08af847..1a4c447 100644 --- a/lib/src/due_date.dart +++ b/lib/src/due_date.dart @@ -459,7 +459,7 @@ class DueDateTime extends DateTime with EquatableMixin { /// Returns this DueDateTime value in the UTC time zone. /// - /// Returns [this] if it is already in UTC. + /// Returns `this` if it is already in UTC. /// Otherwise this method is equivalent to: /// /// ```dart template:expression @@ -474,7 +474,7 @@ class DueDateTime extends DateTime with EquatableMixin { /// Returns this DueDateTime value in the local time zone. /// - /// Returns [this] if it is already in the local time zone. + /// Returns `this` if it is already in the local time zone. /// Otherwise this method is equivalent to: /// /// ```dart template:expression @@ -487,7 +487,7 @@ class DueDateTime extends DateTime with EquatableMixin { date: super.toLocal(), ); - /// Returns a new [DueDateTime] instance with [duration] added to [this]. + /// Returns a new [DueDateTime] instance with [duration] added to `this`. /// /// If [sameEvery] is true, keeps the current one. /// If is false, the [every] will change to the [day] of the generated date. @@ -501,9 +501,9 @@ class DueDateTime extends DateTime with EquatableMixin { /// ``` /// /// Notice that the duration being added is actually 50 * 24 * 60 * 60 - /// seconds. If the resulting `DueDateTime` has a different daylight saving offset - /// than `this`, then the result won't have the same time-of-day as `this`, and - /// may not even hit the calendar date 50 days later. + /// seconds. If the resulting `DueDateTime` has a different daylight saving + /// offset than `this`, then the result won't have the same time-of-day as + /// `this`, and may not even hit the calendar date 50 days later. /// /// Be careful when working with dates in local time. @override @@ -515,7 +515,8 @@ class DueDateTime extends DateTime with EquatableMixin { return DueDateTime.fromDate(date, every: sameEvery ? every : null); } - /// Returns a new [DueDateTime] instance with [duration] subtracted from [this]. + /// Returns a new [DueDateTime] instance with [duration] subtracted from + /// `this`. /// /// If [sameEvery] is true, keeps the current one. /// If is false, the [every] will change to the [day] of the generated date. @@ -529,9 +530,9 @@ class DueDateTime extends DateTime with EquatableMixin { /// ``` /// /// Notice that the duration being subtracted is actually 50 * 24 * 60 * 60 - /// seconds. If the resulting `DueDateTime` has a different daylight saving offset - /// than `this`, then the result won't have the same time-of-day as `this`, and - /// may not even hit the calendar date 50 days earlier. + /// seconds. If the resulting `DueDateTime` has a different daylight saving + /// offset than `this`, then the result won't have the same time-of-day as + /// `this`, and may not even hit the calendar date 50 days earlier. /// /// Be careful when working with dates in local time. @override diff --git a/lib/src/enums.dart b/lib/src/enums.dart index 0b3fd2c..dbd6147 100644 --- a/lib/src/enums.dart +++ b/lib/src/enums.dart @@ -5,28 +5,35 @@ import '../period.dart'; /// Weekday constants that are returned by [DateTime.weekday] method. enum Weekday implements Comparable { + /// Monday. monday(DateTime.monday, generator: WeekGenerator()), + /// Tuesday. tuesday( DateTime.tuesday, generator: WeekGenerator(weekStart: DateTime.tuesday), ), + /// Wednesday. wednesday( DateTime.wednesday, generator: WeekGenerator(weekStart: DateTime.wednesday), ), + /// Thursday. thursday( DateTime.thursday, generator: WeekGenerator(weekStart: DateTime.thursday), ), + /// Friday. friday( DateTime.friday, generator: WeekGenerator(weekStart: DateTime.friday), ), + /// Saturday. saturday( DateTime.saturday, isWeekend: true, generator: WeekGenerator(weekStart: DateTime.saturday), ), + /// Sunday. sunday( DateTime.sunday, isWeekend: true, @@ -77,16 +84,21 @@ enum Weekday implements Comparable { /// Whether this weekday is a workday. bool get isWorkday => !isWeekend; - /// Returns the ammount of weekdays correspondent to this on the given [month] + /// Returns the amount of weekdays correspondent to this on the given [month] /// of [year]. - int occrurencesIn(int year, int month) { - DateTime date = DateTime.utc(year, month, 1); + @Deprecated("Use 'Weekday.occurrencesIn' instead") + int occrurencesIn(int year, int month) => occurrencesIn(year, month); + + /// Returns the amount of weekdays correspondent to this on the given [month] + /// of [year]. + int occurrencesIn(int year, int month) { + DateTime date = DateTime.utc(year, month); int count = 0; do { if (date.weekday == dateTimeValue) { count++; } - date = date.add(Duration(days: 1)); + date = date.add(const Duration(days: 1)); } while (date.month == month); return count; } @@ -146,8 +158,6 @@ enum Weekday implements Comparable { return const EveryWeekday(saturday); case sunday: return const EveryWeekday(sunday); - default: - return EveryWeekday(this); } } @@ -168,8 +178,6 @@ enum Weekday implements Comparable { return const DateValidatorWeekday(saturday); case sunday: return const DateValidatorWeekday(sunday); - default: - return DateValidatorWeekday(this); } } @@ -204,17 +212,29 @@ enum Weekday implements Comparable { /// Month constants that are returned by [DateTime.month] method. enum Month implements Comparable { + /// January month constant. january(DateTime.january), + /// February month constant. february(DateTime.february), + /// March month constant. march(DateTime.march), + /// April month constant. april(DateTime.april), + /// May month constant. may(DateTime.may), + /// June month constant. june(DateTime.june), + /// July month constant. july(DateTime.july), + /// August month constant. august(DateTime.august), + /// September month constant. september(DateTime.september), + /// October month constant. october(DateTime.october), + /// November month constant. november(DateTime.november), + /// December month constant. december(DateTime.december); /// Month constants that are returned by [DateTime.month] method. @@ -313,16 +333,21 @@ enum Month implements Comparable { } } -/// Week occurences inside a month. +/// Week occurrences inside a month. /// /// The first week of the month is the one that contains the first day of the /// month. /// Sometimes the last week can be the same as the fourth. enum Week implements Comparable { + /// First week. first, + /// Second week. second, + /// Third week. third, + /// Fourth week. fourth, + /// Last week. last; /// Returns the [Week] constant that corresponds to the given [date]. @@ -416,7 +441,7 @@ enum Week implements Comparable { @override int compareTo(Week other) => index.compareTo(other.index); - /// Returns true if this is afrer [other]. + /// Returns true if this is after [other]. bool operator >(Week other) => index > other.index; /// Returns true if this is after or equal to [other]. @@ -466,210 +491,245 @@ enum Week implements Comparable { enum WeekdayOccurrence with DateValidatorMixin implements EveryWeekdayCountInMonth { + /// The first Monday of the month. firstMonday( EveryWeekdayCountInMonth( day: Weekday.monday, week: Week.first, ), ), + /// The first Tuesday of the month. firstTuesday( EveryWeekdayCountInMonth( day: Weekday.tuesday, week: Week.first, ), ), + /// The first Wednesday of the month. firstWednesday( EveryWeekdayCountInMonth( day: Weekday.wednesday, week: Week.first, ), ), + /// The first Thursday of the month. firstThursday( EveryWeekdayCountInMonth( day: Weekday.thursday, week: Week.first, ), ), + /// The first Friday of the month. firstFriday( EveryWeekdayCountInMonth( day: Weekday.friday, week: Week.first, ), ), + /// The first Saturday of the month. firstSaturday( EveryWeekdayCountInMonth( day: Weekday.saturday, week: Week.first, ), ), + /// The first Sunday of the month. firstSunday( EveryWeekdayCountInMonth( day: Weekday.sunday, week: Week.first, ), ), + /// The second Monday of the month. secondMonday( EveryWeekdayCountInMonth( day: Weekday.monday, week: Week.second, ), ), + /// The second Tuesday of the month. secondTuesday( EveryWeekdayCountInMonth( day: Weekday.tuesday, week: Week.second, ), ), + /// The second Wednesday of the month. secondWednesday( EveryWeekdayCountInMonth( day: Weekday.wednesday, week: Week.second, ), ), + /// The second Thursday of the month. secondThursday( EveryWeekdayCountInMonth( day: Weekday.thursday, week: Week.second, ), ), + /// The second Friday of the month. secondFriday( EveryWeekdayCountInMonth( day: Weekday.friday, week: Week.second, ), ), + /// The second Saturday of the month. secondSaturday( EveryWeekdayCountInMonth( day: Weekday.saturday, week: Week.second, ), ), + /// The second Sunday of the month. secondSunday( EveryWeekdayCountInMonth( day: Weekday.sunday, week: Week.second, ), ), + /// The third Monday of the month. thirdMonday( EveryWeekdayCountInMonth( day: Weekday.monday, week: Week.third, ), ), + /// The third Tuesday of the month. thirdTuesday( EveryWeekdayCountInMonth( day: Weekday.tuesday, week: Week.third, ), ), + /// The third Wednesday of the month. thirdWednesday( EveryWeekdayCountInMonth( day: Weekday.wednesday, week: Week.third, ), ), + /// The third Thursday of the month. thirdThursday( EveryWeekdayCountInMonth( day: Weekday.thursday, week: Week.third, ), ), + /// The third Friday of the month. thirdFriday( EveryWeekdayCountInMonth( day: Weekday.friday, week: Week.third, ), ), + /// The third Saturday of the month. thirdSaturday( EveryWeekdayCountInMonth( day: Weekday.saturday, week: Week.third, ), ), + /// The third Sunday of the month. thirdSunday( EveryWeekdayCountInMonth( day: Weekday.sunday, week: Week.third, ), ), + /// The fourth Monday of the month. fourthMonday( EveryWeekdayCountInMonth( day: Weekday.monday, week: Week.fourth, ), ), + /// The fourth Tuesday of the month. fourthTuesday( EveryWeekdayCountInMonth( day: Weekday.tuesday, week: Week.fourth, ), ), + /// The fourth Wednesday of the month. fourthWednesday( EveryWeekdayCountInMonth( day: Weekday.wednesday, week: Week.fourth, ), ), + /// The fourth Thursday of the month. fourthThursday( EveryWeekdayCountInMonth( day: Weekday.thursday, week: Week.fourth, ), ), + /// The fourth Friday of the month. fourthFriday( EveryWeekdayCountInMonth( day: Weekday.friday, week: Week.fourth, ), ), + /// The fourth Saturday of the month. fourthSaturday( EveryWeekdayCountInMonth( day: Weekday.saturday, week: Week.fourth, ), ), + /// The fourth Sunday of the month. fourthSunday( EveryWeekdayCountInMonth( day: Weekday.sunday, week: Week.fourth, ), ), + /// The last Monday of the month. lastMonday( EveryWeekdayCountInMonth( day: Weekday.monday, week: Week.last, ), ), + /// The last Tuesday of the month. lastTuesday( EveryWeekdayCountInMonth( day: Weekday.tuesday, week: Week.last, ), ), + /// The last Wednesday of the month. lastWednesday( EveryWeekdayCountInMonth( day: Weekday.wednesday, week: Week.last, ), ), + /// The last Thursday of the month. lastThursday( EveryWeekdayCountInMonth( day: Weekday.thursday, week: Week.last, ), ), + /// The last Friday of the month. lastFriday( EveryWeekdayCountInMonth( day: Weekday.friday, week: Week.last, ), ), + /// The last Saturday of the month. lastSaturday( EveryWeekdayCountInMonth( day: Weekday.saturday, week: Week.last, ), ), + /// The last Sunday of the month. lastSunday( EveryWeekdayCountInMonth( day: Weekday.sunday, diff --git a/lib/src/every.dart b/lib/src/every.dart index 206b567..4b656c2 100644 --- a/lib/src/every.dart +++ b/lib/src/every.dart @@ -1,5 +1,6 @@ import 'package:time/time.dart'; +import 'constants.dart'; import 'date_validator.dart'; import 'enums.dart'; import 'extensions.dart'; @@ -11,7 +12,8 @@ import 'extensions.dart'; /// /// See [EveryWeek], [EveryMonth], [EveryYear] for your base implementations. abstract class Every { - /// Abstract class that, when extended, processes [DateTime] with custom logic. + /// Abstract class that, when extended, processes [DateTime] with custom + /// logic. /// /// See [EveryWeekday], [EveryDueDayMonth], [EveryWeekdayCountInMonth] (also /// [WeekdayOccurrence]) and [EveryDayInYear] for complete base @@ -20,41 +22,68 @@ abstract class Every { /// See [EveryWeek], [EveryMonth], [EveryYear] for your base implementations. const Every(); + /// {@template startDate} /// Returns the next [DateTime] that matches the [Every] pattern. + /// + /// If the [date] is a [DateTime] that matches the [Every] pattern, the + /// [DateTime] will be returned. + /// {@endtemplate} DateTime startDate(DateTime date); + /// {@template next} /// Returns the next instance of the given [date] considering this [Every] /// base process. + /// + /// If the [date] is a [DateTime] that matches the [Every] pattern, a new + /// [DateTime] will be generated. + /// {@endtemplate} DateTime next(DateTime date); + /// {@template previous} /// Returns the previous instance of the given [date] considering this [Every] /// base process. + /// + /// If the [date] is a [DateTime] that matches the [Every] pattern, a new + /// [DateTime] will be generated. + /// {@endtemplate} DateTime previous(DateTime date); } /// Abstract class that forces the implementation of [Every] to have a /// limit parameter for the [startDate], [next] and [previous] methods. abstract class LimitedEvery extends Every { - /// Abstract class that, when extended, processes [DateTime] with custom logic. + /// Abstract class that, when extended, processes [DateTime] with custom + /// logic. /// - /// See [EveryWeekday], [EveryDueDayMonth], [EveryWeekdayCountInMonth] (also - /// [WeekdayOccurrence]) and [EveryDayInYear] for complete base - /// implementations. + /// Abstract class that forces the implementation of [Every] to have a + /// limit parameter for the [startDate], [next] and [previous] methods. + /// + /// See [EveryDateValidatorDifference], [EveryDateValidatorIntersection], + /// [EveryDateValidatorUnion], [EverySkipCountWrapper], [EveryOverrideWrapper] + /// and [EverySkipInvalidModifier] for complete base implementations. /// /// See [EveryWeek], [EveryMonth], [EveryYear] for your base implementations. const LimitedEvery(); - /// Returns the next [DateTime] that matches the [Every] pattern. + /// {@macro startDate} + /// + /// {@template limit} + /// If the generated [DateTime] is still not able to return the first call to + /// this function and it has passed the [limit], it will throw a + /// [DateTimeLimitReachedException]. + /// {@endtemplate} @override DateTime startDate(DateTime date, {DateTime? limit}); - /// Returns the next instance of the given [date] considering this [Every] - /// base process. + /// {@macro next} + /// + /// {@macro limit} @override DateTime next(DateTime date, {DateTime? limit}); - /// Returns the previous instance of the given [date] considering this [Every] - /// base process. + /// {@macro previous} + /// + /// {@macro limit} @override DateTime previous(DateTime date, {DateTime? limit}); } @@ -182,16 +211,35 @@ class EveryWeekday extends DateValidatorWeekday /// Returns the next date that fits the [weekday]. @override DateTime startDate(DateTime date) { - final day = weekday.fromWeekOf(date); - if (day.toUtc().date.isBefore(date.toUtc().date)) { - final nextDay = day.toUtc().add(const Duration(days: 1)); - if (date.isUtc) { - return nextDay.nextWeekday(weekday); - } else { - return nextDay.toLocal().nextWeekday(weekday); - } + if (valid(date)) return date; + return next(date); + } + + /// Returns the previous date that fits the [weekday]. + /// + /// Always returns the first [DateTime] that fits the [weekday], ignoring + /// the given [date] as an option. + @override + DateTime next(DateTime date) { + if (date.weekday < weekday.dateTimeValue) { + return weekday.fromWeekOf(date); } else { - return day; + return weekday + .fromWeekOf(date.lastDayOfWeek.add(const Duration(days: 1))); + } + } + + /// Returns the previous date that fits the [weekday]. + /// + /// Always returns the last [DateTime] that fits the [weekday], ignoring + /// the given [date] as an option. + @override + DateTime previous(DateTime date) { + if (date.weekday > weekday.dateTimeValue) { + return weekday.fromWeekOf(date); + } else { + return weekday + .fromWeekOf(date.firstDayOfWeek.subtract(const Duration(days: 1))); } } @@ -200,23 +248,26 @@ class EveryWeekday extends DateValidatorWeekday @override DateTime addWeeks(DateTime date, int weeks) { if (weeks == 0) return date; - if (!valid(date)) { - if (weeks.isNegative) { - if (date.weekday < weekday.dateTimeValue) { - date = date.firstDayOfWeek.subtract(const Duration(days: 1)); + int localWeeks = weeks; + DateTime localDate = date.copyWith(); + if (!valid(localDate)) { + if (localWeeks.isNegative) { + if (localDate.weekday < weekday.dateTimeValue) { + localDate = + localDate.firstDayOfWeek.subtract(const Duration(days: 1)); } - date = weekday.fromWeekOf(date); - weeks++; + localDate = weekday.fromWeekOf(localDate); + localWeeks++; } else { - if (date.weekday > weekday.dateTimeValue) { - date = date.lastDayOfWeek.add(const Duration(days: 1)); + if (localDate.weekday > weekday.dateTimeValue) { + localDate = localDate.lastDayOfWeek.add(const Duration(days: 1)); } - date = weekday.fromWeekOf(date); - weeks--; + localDate = weekday.fromWeekOf(localDate); + localWeeks--; } } - final day = date.toUtc().add(Duration(days: weeks * 7)); - return _solveFor(date, day); + final day = localDate.toUtc().add(Duration(days: localWeeks * 7)); + return _solveFor(localDate, day); } /// Returns a new [DateTime] where the week is the same([Week]) inside the @@ -297,22 +348,26 @@ class EveryDueDayMonth extends DateValidatorDueDayMonth @override DateTime addMonths(DateTime date, int months) { if (months == 0) return date; - if (!valid(date)) { - if (months.isNegative) { - if (date.day < dueDay) { - date = date.firstDayOfMonth.subtract(const Duration(days: 1)); + int localMonths = months; + DateTime localDate = date.copyWith(); + if (!valid(localDate)) { + if (localMonths.isNegative) { + if (localDate.day < dueDay) { + localDate = + localDate.firstDayOfMonth.subtract(const Duration(days: 1)); } - date = _thisMonthsDay(date); - months++; + localDate = _thisMonthsDay(localDate); + localMonths++; } else { - if (date.day > dueDay) { - date = date.lastDayOfMonth.add(const Duration(days: 1)); + if (localDate.day > dueDay) { + localDate = localDate.lastDayOfMonth.add(const Duration(days: 1)); } - date = _thisMonthsDay(date); - months--; + localDate = _thisMonthsDay(localDate); + localMonths--; } } - final day = date.copyWith(month: date.month + months, day: 1); + final day = + localDate.copyWith(month: localDate.month + localMonths, day: 1); return day.copyWith(day: dueDay).clamp(max: day.lastDayOfMonth); } @@ -349,7 +404,7 @@ class EveryDueDayMonth extends DateValidatorDueDayMonth } /// Class that processes [DateTime] so that the [addMonths] always returns the -/// next month's with the [week] occurence of the [day] ([DateTime.weekday] +/// next month's with the [week] occurrence of the [day] ([DateTime.weekday] /// is the [day]'s [Weekday.dateTimeValue]). /// /// E.g. @@ -381,15 +436,34 @@ class EveryWeekdayCountInMonth extends DateValidatorWeekdayCountInMonth /// - If the current [date] - [DateTime.day] is less than the [DateTime.month] /// [week], it's returned the same month with the [DateTime.day] being the /// [day] of the [week]. - /// - If the current [date] - [DateTime.day] is greater than the [DateTime.month] - /// [week], it's returned the next month with the [DateTime.day] being the - /// [day] of the [week]. + /// - If the current [date] - [DateTime.day] is greater than the + /// [DateTime.month], [week], it's returned the next month with the + /// [DateTime.day] being the [day] of the [week]. @override DateTime startDate(DateTime date) { if (valid(date)) return date; final thisMonthDay = week.weekdayOf( year: date.year, - month: date.day, + month: date.month, + day: day, + utc: date.isUtc, + ); + if (date.day < thisMonthDay.day) return thisMonthDay; + return next(date); + } + + /// Returns the next date that fits the [day] and the [week]. + /// - If the current [date] - [DateTime.day] is less than the [DateTime.month] + /// [week], it's returned the same month with the [DateTime.day] being the + /// [day] of the [week]. + /// - If the current [date] - [DateTime.day] is greater than the + /// [DateTime.month], [week], it's returned the next month with the + /// [DateTime.day] being the [day] of the [week]. + @override + DateTime next(DateTime date) { + final thisMonthDay = week.weekdayOf( + year: date.year, + month: date.month, day: day, utc: date.isUtc, ); @@ -402,41 +476,52 @@ class EveryWeekdayCountInMonth extends DateValidatorWeekdayCountInMonth ); } - /// Returns the [date] - [DateTime.month] + [months] with the [week] occurence - /// of the [day]. + /// Returns the previous date that fits the [day] and the [week]. + /// - If the current [date] - [DateTime.day] is less than the [DateTime.month] + /// [week], it's returned the same month with the [DateTime.day] being the + /// [day] of the [week]. + /// - If the current [date] - [DateTime.day] is greater than the + /// [DateTime.month], [week], it's returned the previous month with the + /// [DateTime.day] being the [day] of the [week]. + @override + DateTime previous(DateTime date) { + final thisMonthDay = week.weekdayOf( + year: date.year, + month: date.month, + day: day, + utc: date.isUtc, + ); + if (date.day > thisMonthDay.day) return thisMonthDay; + return week.weekdayOf( + year: date.year, + month: date.month - 1, + day: day, + utc: date.isUtc, + ); + } + + /// Returns the [date] - [DateTime.month] + [months] with the [week] + /// occurrence of the [day]. @override DateTime addMonths(DateTime date, int months) { - if (months == 0) return date; - if (!valid(date)) { - final thisMonthsDay = week.weekdayOf( - year: date.year, - month: date.month, - day: day, - utc: date.isUtc, - ); - if (months.isNegative) { - if (date.day < thisMonthsDay.day) { - date = date.firstDayOfMonth.subtract(const Duration(days: 1)); - months++; - } - } else { - if (date.day > thisMonthsDay.day) { - date = date.lastDayOfMonth.add(const Duration(days: 1)); - months--; - } + if (months == 0) return startDate(date); + int localMonths = months; + DateTime localDate = startDate(date); + if (localMonths.isNegative) { + while (localMonths < 0) { + localDate = previous(localDate); + localMonths++; + } + } else { + while (localMonths > 0) { + localDate = next(localDate); + localMonths--; } } - return week - .weekdayOf( - year: date.year, - month: date.month + months, - day: day, - utc: date.isUtc, - ) - .add(date.timeOfDay); + return localDate; } - /// Returns the [date] - [DateTime.year] + [years] with the [week] occurence + /// Returns the [date] - [DateTime.year] + [years] with the [week] occurrence /// of the [day]. /// /// Basically, it's the same as [addMonths] but with the months parameter @@ -480,6 +565,14 @@ class EveryDayInYear extends DateValidatorDayInYear } /// Returns the next date that fits the [dayInYear]. + /// - If the current [date] - [DayInYear.dayInYear] is equal to `zero`, + /// [date] is returned. + /// - If the current [date] - [DayInYear.dayInYear] is less than the + /// [dayInYear], it's returned the same year with the [DayInYear.dayInYear] + /// being the [dayInYear]. + /// - If the current [date] - [DayInYear.dayInYear] is greater than the + /// [dayInYear], it's returned the next year with the [DayInYear.dayInYear] + /// being the [dayInYear]. @override DateTime startDate(DateTime date) { if (valid(date)) return date; @@ -487,36 +580,71 @@ class EveryDayInYear extends DateValidatorDayInYear .add(Duration(days: dayInYear - 1)) .clamp(max: date.lastDayOfYear); if (date.dayInYear <= dayInYear) return thisYearDay; - return date.lastDayOfYear - .add(Duration(days: dayInYear)) + return next(date); + } + + /// Returns the next date that fits the [dayInYear]. + /// - If the current [date] - [DayInYear.dayInYear] is less than the + /// [dayInYear], it's returned the same year with the [DayInYear.dayInYear] + /// being the [dayInYear]. + /// - If the current [date] - [DayInYear.dayInYear] is greater than the + /// [dayInYear], it's returned the next year with the [DayInYear.dayInYear] + /// being the [dayInYear]. + @override + DateTime next(DateTime date) { + if (!date.isLeapYear && dayInYear == 366) { + return date.copyWith(year: date.year + 1).lastDayOfYear; + } + final thisYearDay = date.firstDayOfYear + .add(Duration(days: dayInYear - 1)) + .clamp(max: date.lastDayOfYear); + if (date.dayInYear < dayInYear) return thisYearDay; + return date + .copyWith(year: date.year + 1) + .firstDayOfYear + .add(Duration(days: dayInYear - 1)) .clamp(max: date.copyWith(year: date.year + 1).lastDayOfYear); } + /// Returns the previous date that fits the [dayInYear]. + /// - If the current [date] - [DayInYear.dayInYear] is greater than the + /// [dayInYear], it's returned the same year with the [DayInYear.dayInYear] + /// being the [dayInYear]. + /// - If the current [date] - [DayInYear.dayInYear] is less than the + /// [dayInYear], it's returned the previous year with the + /// [DayInYear.dayInYear] being the [dayInYear]. + @override + DateTime previous(DateTime date) { + final thisYearDay = date.firstDayOfYear + .add(Duration(days: dayInYear - 1)) + .clamp(max: date.lastDayOfYear); + if (date.dayInYear > dayInYear) return thisYearDay; + return date + .copyWith(year: date.year - 1) + .firstDayOfYear + .add(Duration(days: dayInYear - 1)) + .clamp(max: date.copyWith(year: date.year - 1).lastDayOfYear); + } + /// Returns a new [DateTime] where the year is [years] from this year and the /// [DateTime.day] is equal to [dayInYear]-1 added to January 1st. @override DateTime addYears(DateTime date, int years) { - if (years == 0) return date; - if (!valid(date)) { - final thisYearsDay = date.firstDayOfYear - .add(Duration(days: dayInYear - 1)) - .clamp(max: date.lastDayOfYear); - if (years.isNegative) { - if (date.day < thisYearsDay.day) { - date = date.firstDayOfYear.subtract(const Duration(days: 1)); - years++; - } - } else { - if (date.day > thisYearsDay.day) { - date = date.lastDayOfYear.add(const Duration(days: 1)); - years--; - } + if (years == 0) return startDate(date); + int localYears = years; + DateTime localDate = startDate(date); + if (localYears.isNegative) { + while (localYears < 0) { + localDate = previous(localDate); + localYears++; + } + } else { + while (localYears > 0) { + localDate = next(localDate); + localYears--; } } - return date.firstDayOfYear - .copyWith(year: date.year + years) - .add(Duration(days: dayInYear - 1)) - .clamp(max: date.copyWith(year: date.year + years).lastDayOfYear); + return localDate; } @override @@ -548,7 +676,9 @@ class EveryDateValidatorIntersection if ((limit != null) && (date.isAfter(limit) || (date == limit))) { throw DateTimeLimitReachedException(date: date, limit: limit); } - final startingDates = map((every) => _startDate(every, date, limit: limit)); + final startingDates = map( + (every) => LimitedOrEveryHandler.startDate(every, date, limit: limit), + ); final validDates = startingDates.where(valid); if (validDates.isNotEmpty) { final result = validDates.reduce(_reduceFuture); @@ -566,7 +696,8 @@ class EveryDateValidatorIntersection if ((limit != null) && (date.isAfter(limit) || (date == limit))) { throw DateTimeLimitReachedException(date: date, limit: limit); } - final nextDates = map((every) => _next(every, date, limit: limit)); + final nextDates = + map((every) => LimitedOrEveryHandler.next(every, date, limit: limit)); final validDates = nextDates.where(valid); if (validDates.isNotEmpty) { final result = validDates.reduce(_reduceFuture); @@ -584,7 +715,9 @@ class EveryDateValidatorIntersection if ((limit != null) && (date.isBefore(limit) || (date == limit))) { throw DateTimeLimitReachedException(date: date, limit: limit); } - final previousDates = map((every) => _previous(every, date, limit: limit)); + final previousDates = map( + (every) => LimitedOrEveryHandler.previous(every, date, limit: limit), + ); final validDates = previousDates.where(valid); if (validDates.isNotEmpty) { final result = validDates.reduce(_reducePast); @@ -623,7 +756,9 @@ class EveryDateValidatorUnion @override DateTime startDate(DateTime date, {DateTime? limit}) { if (isEmpty) return date; - final startingDates = map((every) => _startDate(every, date, limit: limit)); + final startingDates = map( + (every) => LimitedOrEveryHandler.startDate(every, date, limit: limit), + ); return startingDates.reduce(_reduceFuture); } @@ -636,7 +771,8 @@ class EveryDateValidatorUnion @override DateTime next(DateTime date, {DateTime? limit}) { if (isEmpty) return date; - final nextDates = map((every) => _next(every, date, limit: limit)); + final nextDates = + map((every) => LimitedOrEveryHandler.next(every, date, limit: limit)); return nextDates.reduce(_reduceFuture); } @@ -649,7 +785,9 @@ class EveryDateValidatorUnion @override DateTime previous(DateTime date, {DateTime? limit}) { if (isEmpty) return date; - final previousDates = map((every) => _previous(every, date, limit: limit)); + final previousDates = map( + (every) => LimitedOrEveryHandler.previous(every, date, limit: limit), + ); return previousDates.reduce(_reducePast); } @@ -678,7 +816,9 @@ class EveryDateValidatorDifference if ((limit != null) && (date.isAfter(limit) || (date == limit))) { throw DateTimeLimitReachedException(date: date, limit: limit); } - final startingDates = map((every) => _startDate(every, date, limit: limit)); + final startingDates = map( + (every) => LimitedOrEveryHandler.startDate(every, date, limit: limit), + ); final validDates = startingDates.where(valid); if (validDates.isNotEmpty) { final result = validDates.reduce(_reduceFuture); @@ -696,7 +836,8 @@ class EveryDateValidatorDifference if ((limit != null) && (date.isAfter(limit) || (date == limit))) { throw DateTimeLimitReachedException(date: date, limit: limit); } - final nextDates = map((every) => _next(every, date, limit: limit)); + final nextDates = + map((every) => LimitedOrEveryHandler.next(every, date, limit: limit)); final validDates = nextDates.where(valid); if (validDates.isNotEmpty) { final result = validDates.reduce(_reduceFuture); @@ -714,7 +855,9 @@ class EveryDateValidatorDifference if ((limit != null) && (date.isBefore(limit) || (date == limit))) { throw DateTimeLimitReachedException(date: date, limit: limit); } - final previousDates = map((every) => _previous(every, date, limit: limit)); + final previousDates = map( + (every) => LimitedOrEveryHandler.previous(every, date, limit: limit), + ); final validDates = previousDates.where(valid); if (validDates.isNotEmpty) { final result = validDates.reduce(_reducePast); @@ -735,48 +878,19 @@ class EveryDateValidatorDifference } } -DateTime _startDate( - T every, - DateTime date, { - required DateTime? limit, -}) { - if (every is! LimitedEvery) return every.startDate(date); - return every.startDate(date, limit: limit); -} - -DateTime _next( - T every, - DateTime date, { - required DateTime? limit, -}) { - if (every is! LimitedEvery) return every.next(date); - return every.next(date, limit: limit); -} - -DateTime _previous( - T every, - DateTime date, { - required DateTime? limit, -}) { - if (every is! LimitedEvery) return every.previous(date); - return every.previous(date, limit: limit); -} - -DateTime _reduceFuture(DateTime value, DateTime element) { - return value.isBefore(element) ? value : element; -} - -DateTime _reducePast(DateTime value, DateTime element) { - return value.isAfter(element) ? value : element; -} - /// Exception thrown when a date limit is reached. +/// +/// Thrown when a [LimitedEvery] method would return a date that is after (or +/// before in [LimitedEvery.previous] case) the [limit] date. +/// +/// Should **_not_** be thrown when the resulting [date] is equal to the [limit] +/// date. class DateTimeLimitReachedException implements Exception { /// Exception thrown when a date limit is reached. const DateTimeLimitReachedException({ required this.date, required this.limit, - }); + }) : assert(date != limit, 'Invalid exception'); /// Date that reached the limit. final DateTime date; @@ -789,3 +903,11 @@ class DateTimeLimitReachedException implements Exception { return 'DateTimeLimitException: $date has passed $limit'; } } + +DateTime _reduceFuture(DateTime value, DateTime element) { + return value.isBefore(element) ? value : element; +} + +DateTime _reducePast(DateTime value, DateTime element) { + return value.isAfter(element) ? value : element; +} diff --git a/lib/src/extensions.dart b/lib/src/extensions.dart index 17ea1dd..da3143f 100644 --- a/lib/src/extensions.dart +++ b/lib/src/extensions.dart @@ -133,7 +133,7 @@ extension PreviousNext on Iterable { } } -/// Extension methods related to [DateValidator]s. Simpply wrappers around +/// Extension methods related to [DateValidator]s. Simply wrappers around /// creating [DateValidatorIntersection], [DateValidatorUnion] or /// [DateValidatorDifference]. extension DateValidatorListExt on List { @@ -147,7 +147,7 @@ extension DateValidatorListExt on List { DateValidatorUnion get union => DateValidatorUnion(this); } -/// Extension methods related to [EveryDateValidator]s. Simpply wrappers around +/// Extension methods related to [EveryDateValidator]s. Simply wrappers around /// creating [EveryDateValidatorIntersection], [EveryDateValidatorUnion] or /// [EveryDateValidatorDifference]. extension EveryDateValidatorListExt on List { diff --git a/lib/src/period.dart b/lib/src/period.dart index e8fcfe1..8217f2b 100644 --- a/lib/src/period.dart +++ b/lib/src/period.dart @@ -52,8 +52,9 @@ class Period with EquatableMixin implements Comparable { } else { final last = merged.last; if (last.overlapsWith(current)) { - merged.removeLast(); - merged.add(last.mergeWith(current)!); + merged + ..removeLast() + ..add(last.mergeWith(current)!); } else { merged.add(current); } @@ -80,8 +81,9 @@ class Period with EquatableMixin implements Comparable { final previous = localPeriods[i - 1]; final lastMerged = merged.last; if (lastMerged.overlapsWith(current)) { - merged.removeLast(); - merged.add(lastMerged.getIntersection(current)!); + merged + ..removeLast() + ..add(lastMerged.getIntersection(current)!); } else if (previous.overlapsWith(current)) { merged.add(previous.getIntersection(current)!); } else { @@ -630,12 +632,13 @@ class Period with EquatableMixin implements Comparable { @override String toString({DateFormat? dateFormat}) { + // ignore: no_runtimetype_tostring, simply to print the class return '$runtimeType(${dateFormat?.format(start) ?? start}, ' '${dateFormat?.format(end) ?? end})'; } @override - // ignore: hash_and_equals, overriden in EquatableMixin + // ignore: hash_and_equals, overridden in EquatableMixin bool operator ==(Object other) { return (super == other) || ((other is Period) && (other.start == start) && (other.end == end)); @@ -649,8 +652,9 @@ class Period with EquatableMixin implements Comparable { if (period.doesNotOverlapWith(this)) { localPeriods.remove(period); } else if (containsPartially(period)) { - localPeriods.remove(period); - localPeriods.add(getIntersection(period)!); + localPeriods + ..remove(period) + ..add(getIntersection(period)!); } } return localPeriods; @@ -685,6 +689,8 @@ class SecondPeriod extends Period { milliseconds: 999, microseconds: 999, ), + 'The difference between start and end must be 999 milliseconds and ' + '999 microseconds', ) { const microsecond = Duration(microseconds: 1); if ((duration != const Duration(seconds: 1)) || @@ -711,6 +717,8 @@ class MinutePeriod extends Period { milliseconds: 999, microseconds: 999, ), + 'The difference between start and end must be 59 seconds, 999 ' + 'milliseconds and 999 microseconds', ) { const microsecond = Duration(microseconds: 1); if (duration != const Duration(minutes: 1) || @@ -750,6 +758,8 @@ class HourPeriod extends Period { milliseconds: 999, microseconds: 999, ), + 'The difference between start and end must be 59 minutes, 59 ' + 'seconds, 999 milliseconds and 999 microseconds', ) { const microsecond = Duration(microseconds: 1); if (duration != const Duration(hours: 1) || @@ -790,6 +800,8 @@ class DayPeriod extends Period { milliseconds: 999, microseconds: 999, ), + 'The difference between start and end must be 23 hours, 59 minutes, ' + '59 seconds, 999 milliseconds and 999 microseconds', ) { const microsecond = Duration(microseconds: 1); if (!start.isAtSameDayAs(end) || @@ -816,8 +828,11 @@ class DayPeriod extends Period { } } +/// {@template dayPeriodBundle} /// A base class that represents a bundle of days. +/// {@endtemplate} abstract class DayPeriodBundle extends Period { + /// {@macro dayPeriodBundle} DayPeriodBundle({required super.start, required super.end}); /// Returns the list of days in this bundle. @@ -832,12 +847,13 @@ class WeekPeriod extends Period implements DayPeriodBundle { end.difference(start) <= const Duration( days: 7, - hours: 0, minutes: 59, seconds: 59, milliseconds: 999, microseconds: 999, ), + 'The difference between start and end must be 7 days, 0 hours, ' + '59 minutes, 59 seconds, 999 milliseconds and 999 microseconds', ) { if ((duration > const Duration(days: 7, hours: 1)) || (duration < @@ -855,8 +871,8 @@ class WeekPeriod extends Period implements DayPeriodBundle { throw ArgumentError.value( end, 'end', - 'End must be at the same week as start and must be the last microsecond ' - 'of the week', + 'End must be at the same week as start and must be the last ' + 'microsecond of the week', ); } } @@ -888,6 +904,8 @@ class FortnightPeriod extends Period implements DayPeriodBundle { milliseconds: 999, microseconds: 999, ), + 'The difference between start and end must be 15 days, 23 hours, ' + '59 minutes, 59 seconds, 999 milliseconds and 999 microseconds', ) { if ((duration > const Duration(days: 16, hours: 1)) || (duration < @@ -942,6 +960,8 @@ class MonthPeriod extends Period implements DayPeriodBundle { milliseconds: 999, microseconds: 999, ), + 'The difference between start and end must be 30 days, 23 hours, ' + '59 minutes, 59 seconds, 999 milliseconds and 999 microseconds', ) { const microsecond = Duration(microseconds: 1); if (!start.isAtSameMonthAs(end) || @@ -953,8 +973,8 @@ class MonthPeriod extends Period implements DayPeriodBundle { throw ArgumentError.value( end, 'end', - 'End must be at the same month as start and must be the last microsecond ' - 'of the month', + 'End must be at the same month as start and must be the last ' + 'microsecond of the month', ); } } @@ -972,8 +992,11 @@ class MonthPeriod extends Period implements DayPeriodBundle { } } +/// {@template monthPeriodBundle} /// A base class that represents a bundle of months. +/// {@endtemplate} abstract class MonthPeriodBundle extends Period { + /// {@macro monthPeriodBundle} MonthPeriodBundle({required super.start, required super.end}); /// Returns the list of months in this bundle. @@ -994,6 +1017,8 @@ class TrimesterPeriod extends Period implements MonthPeriodBundle { milliseconds: 999, microseconds: 999, ), + 'The difference between start and end must be 91 days, 23 hours, ' + '59 minutes, 59 seconds, 999 milliseconds and 999 microseconds', ) { if ((start.timeOfDay != Duration.zero) || (end.timeOfDay != end.endOfDay.timeOfDay) || @@ -1037,6 +1062,8 @@ class SemesterPeriod extends Period implements MonthPeriodBundle { milliseconds: 999, microseconds: 999, ), + 'The difference between start and end must be 183 days, 23 hours, ' + '59 minutes, 59 seconds, 999 milliseconds and 999 microseconds', ) { if ((start.timeOfDay != Duration.zero) || (end.timeOfDay != end.endOfDay.timeOfDay) || @@ -1080,6 +1107,8 @@ class YearPeriod extends Period implements MonthPeriodBundle { milliseconds: 999, microseconds: 999, ), + 'The difference between start and end must be 365 days, 23 hours, ' + '59 minutes, 59 seconds, 999 milliseconds and 999 microseconds', ) { const microsecond = Duration(microseconds: 1); if (!start.isAtSameYearAs(end) || @@ -1093,8 +1122,8 @@ class YearPeriod extends Period implements MonthPeriodBundle { throw ArgumentError.value( end, 'end', - 'End must be at the same year as start and must be the last microsecond ' - 'of the year', + 'End must be at the same year as start and must be the last ' + 'microsecond of the year', ); } } diff --git a/lib/src/period_generator.dart b/lib/src/period_generator.dart index 59d0ac5..d13bd50 100644 --- a/lib/src/period_generator.dart +++ b/lib/src/period_generator.dart @@ -5,7 +5,8 @@ import '../period.dart'; /// A mixin for period types. /// -/// If you are looking for implementations, see [PeriodGenerator] and its values: +/// If you are looking for implementations, see [PeriodGenerator] and its +/// values: /// [SecondGenerator], [MinuteGenerator], [HourGenerator], [DayGenerator], /// [WeekGenerator], [FortnightGenerator], [MonthGenerator], /// [TrimesterGenerator], [SemesterGenerator] and [YearGenerator]. @@ -32,6 +33,7 @@ mixin PeriodGeneratorMixin { }) => of(of(period.start).start.subtract(duration)); + /// Returns true if the given [period] fits the generator. bool fitsGenerator(Period period) { final newPeriod = of(period.start); return newPeriod == period; @@ -58,7 +60,7 @@ class SecondGenerator with PeriodGeneratorMixin, EquatableMixin { } @override - // ignore: hash_and_equals, overriden in EquatableMixin + // ignore: hash_and_equals, overridden in EquatableMixin bool operator ==(Object other) { return (super == other) || (other is SecondGenerator); } @@ -89,7 +91,7 @@ class MinuteGenerator with PeriodGeneratorMixin, EquatableMixin { } @override - // ignore: hash_and_equals, overriden in EquatableMixin + // ignore: hash_and_equals, overridden in EquatableMixin bool operator ==(Object other) { return (super == other) || (other is MinuteGenerator); } @@ -122,7 +124,7 @@ class HourGenerator with PeriodGeneratorMixin, EquatableMixin { } @override - // ignore: hash_and_equals, overriden in EquatableMixin + // ignore: hash_and_equals, overridden in EquatableMixin bool operator ==(Object other) { return (super == other) || (other is HourGenerator); } @@ -144,7 +146,7 @@ class DayGenerator with PeriodGeneratorMixin, EquatableMixin { } @override - // ignore: hash_and_equals, overriden in EquatableMixin + // ignore: hash_and_equals, overridden in EquatableMixin bool operator ==(Object other) { return (super == other) || (other is DayGenerator); } @@ -156,9 +158,9 @@ class DayGenerator with PeriodGeneratorMixin, EquatableMixin { /// A class that implements a generator of a period type of a week. class WeekGenerator with PeriodGeneratorMixin, EquatableMixin { /// A class that implements a generator of a period type of a week. - const WeekGenerator({this.weekStart = DateTime.monday}) - : assert(weekStart >= DateTime.monday && weekStart <= DateTime.sunday); + const WeekGenerator({this.weekStart = DateTime.monday}); + /// The first day of the week. final int weekStart; @override @@ -167,12 +169,13 @@ class WeekGenerator with PeriodGeneratorMixin, EquatableMixin { if (difference > 0) difference -= DateTime.daysPerWeek; final day = date.day + difference; final start = date.copyWith(day: day).date; - final end = start.add(Duration(days: DateTime.daysPerWeek - 1)).endOfDay; + final end = + start.add(const Duration(days: DateTime.daysPerWeek - 1)).endOfDay; return WeekPeriod(start: start, end: end); } @override - // ignore: hash_and_equals, overriden in EquatableMixin + // ignore: hash_and_equals, overridden in EquatableMixin bool operator ==(Object other) { return (super == other) || (other is WeekGenerator); } @@ -203,7 +206,7 @@ class FortnightGenerator } @override - // ignore: hash_and_equals, overriden in EquatableMixin + // ignore: hash_and_equals, overridden in EquatableMixin bool operator ==(Object other) { return (super == other) || (other is FortnightGenerator); } @@ -226,7 +229,7 @@ class MonthGenerator with PeriodGeneratorMixin, EquatableMixin { } @override - // ignore: hash_and_equals, overriden in EquatableMixin + // ignore: hash_and_equals, overridden in EquatableMixin bool operator ==(Object other) { return (super == other) || (other is MonthGenerator); } @@ -271,7 +274,7 @@ class TrimesterGenerator } @override - // ignore: hash_and_equals, overriden in EquatableMixin + // ignore: hash_and_equals, overridden in EquatableMixin bool operator ==(Object other) { return (super == other) || (other is TrimesterGenerator); } @@ -302,7 +305,7 @@ class SemesterGenerator } @override - // ignore: hash_and_equals, overriden in EquatableMixin + // ignore: hash_and_equals, overridden in EquatableMixin bool operator ==(Object other) { return (super == other) || (other is SemesterGenerator); } @@ -325,7 +328,7 @@ class YearGenerator with PeriodGeneratorMixin, EquatableMixin { } @override - // ignore: hash_and_equals, overriden in EquatableMixin + // ignore: hash_and_equals, overridden in EquatableMixin bool operator ==(Object other) { return (super == other) || (other is YearGenerator); } diff --git a/pubspec.yaml b/pubspec.yaml index c024d78..f4f0d78 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,18 +4,22 @@ version: 2.0.0 homepage: https://fmorschel.github.io/due_date/ repository: https://github.com/FMorschel/due_date issue_tracker: https://github.com/FMorschel/due_date/issues +funding: + - https://github.com/sponsors/FMorschel + - https://www.buymeacoffee.com/fmorschel environment: sdk: '>=2.17.6 <4.0.0' dependencies: - time: '>=2.1.3 <3.0.0' - equatable: '>=2.0.5 <3.0.0' collection: '>=1.16.0 <2.0.0' + equatable: '>=2.0.5 <3.0.0' intl: '>=0.17.0 <0.19.0' + time: '>=2.1.3 <3.0.0' dev_dependencies: + dart_code_metrics: ^5.7.3 dartdoc: ^6.2.1 lints: ^2.0.0 test: ^1.24.0 - dart_code_metrics: ^5.7.3 + very_good_analysis: ^5.1.0 diff --git a/test/date_validator_test.dart b/test/date_validator_test.dart index 0e154a3..2271cca 100644 --- a/test/date_validator_test.dart +++ b/test/date_validator_test.dart @@ -4,7 +4,7 @@ import 'package:test/test.dart'; void main() { group('DateValidatorWeekday:', () { group('Monday', () { - final validator = DateValidatorWeekday(Weekday.monday); + const validator = DateValidatorWeekday(Weekday.monday); test('Monday is valid', () { expect(validator.valid(DateTime(2022, DateTime.september, 26)), isTrue); }); @@ -19,7 +19,7 @@ void main() { }); group('DateValidatorDueDayMonth:', () { group('Day 2', () { - final validator = DateValidatorDueDayMonth(2); + const validator = DateValidatorDueDayMonth(2); test('Is valid', () { expect(validator.valid(DateTime(2022, DateTime.september, 2)), isTrue); }); @@ -32,7 +32,7 @@ void main() { }); }); group('Day 31 not exact', () { - final validator = DateValidatorDueDayMonth(31); + const validator = DateValidatorDueDayMonth(31); group('Is valid', () { test('February', () { expect( @@ -55,7 +55,7 @@ void main() { }); }); group('Day 31 exact', () { - final validator = DateValidatorDueDayMonth(31, exact: true); + const validator = DateValidatorDueDayMonth(31, exact: true); test('Is valid', () { expect( validator.valid(DateTime(2022, DateTime.october, 31)), @@ -80,7 +80,7 @@ void main() { }); group('DateValidatorWeekdayCountInMonth', () { group('First Monday', () { - final validator = DateValidatorWeekdayCountInMonth( + const validator = DateValidatorWeekdayCountInMonth( week: Week.first, day: Weekday.monday, ); @@ -98,7 +98,7 @@ void main() { }); }); group('Second Tuesday', () { - final validator = DateValidatorWeekdayCountInMonth( + const validator = DateValidatorWeekdayCountInMonth( day: Weekday.tuesday, week: Week.second, ); @@ -116,7 +116,7 @@ void main() { }); }); group('Third Wednesday', () { - final validator = DateValidatorWeekdayCountInMonth( + const validator = DateValidatorWeekdayCountInMonth( day: Weekday.wednesday, week: Week.third, ); @@ -134,7 +134,7 @@ void main() { }); }); group('Fourth Thursday', () { - final validator = DateValidatorWeekdayCountInMonth( + const validator = DateValidatorWeekdayCountInMonth( day: Weekday.thursday, week: Week.fourth, ); @@ -152,7 +152,7 @@ void main() { }); }); group('Last Friday', () { - final validator = DateValidatorWeekdayCountInMonth( + const validator = DateValidatorWeekdayCountInMonth( day: Weekday.friday, week: Week.last, ); @@ -172,10 +172,10 @@ void main() { }); group('DateValidatorDayInYear', () { group('Day 1', () { - final validator = DateValidatorDayInYear(1); + const validator = DateValidatorDayInYear(1); test('Is valid', () { expect( - validator.valid(DateTime(2022, DateTime.january, 1)), + validator.valid(DateTime(2022)), isTrue, ); }); @@ -187,7 +187,7 @@ void main() { }); }); group('Day 365', () { - final validator = DateValidatorDayInYear(365); + const validator = DateValidatorDayInYear(365); test('Is valid', () { expect( validator.valid(DateTime(2022, DateTime.december, 31)), @@ -202,7 +202,7 @@ void main() { }); }); group('Day 366 not exact', () { - final validator = DateValidatorDayInYear(366); + const validator = DateValidatorDayInYear(366); test('Is not valid', () { expect( validator.valid(DateTime(2022, DateTime.january, 31)), @@ -225,7 +225,7 @@ void main() { }); }); group('Day 366 exact', () { - final validator = DateValidatorDayInYear(366, exact: true); + const validator = DateValidatorDayInYear(366, exact: true); test('Is valid', () { expect( validator.valid(DateTime(2020, DateTime.december, 31)), @@ -249,7 +249,7 @@ void main() { }); }); group('DateValidatorIntersection', () { - final validator = DateValidatorIntersection([ + const validator = DateValidatorIntersection([ DateValidatorDueDayMonth(24), DateValidatorWeekday(Weekday.saturday), ]); @@ -269,7 +269,7 @@ void main() { }); }); group('DateValidatorUnion', () { - final validator = DateValidatorUnion([ + const validator = DateValidatorUnion([ DateValidatorDueDayMonth(24), DateValidatorWeekday(Weekday.saturday), ]); @@ -293,7 +293,7 @@ void main() { }); }); group('DateValidatorDifference', () { - final validator = DateValidatorDifference([ + const validator = DateValidatorDifference([ DateValidatorDueDayMonth(24), DateValidatorWeekday(Weekday.saturday), ]); diff --git a/test/due_date_test.dart b/test/due_date_test.dart index 3688d20..beab232 100644 --- a/test/due_date_test.dart +++ b/test/due_date_test.dart @@ -21,7 +21,7 @@ void main() { equals(matcherFitted), ); }); - test('Midlle of the month', () { + test('Middle of the month', () { expect( DueDateTime(every: dueDay30, year: year, month: 2, day: 15), equals(matcher), @@ -29,7 +29,7 @@ void main() { }); test('Previous month end', () { expect( - DueDateTime(every: dueDay30, year: year, month: 1, day: 31), + DueDateTime(every: dueDay30, year: year, day: 31), equals(matcher), ); }); @@ -55,7 +55,7 @@ void main() { equals(matcherFitted), ); }); - test('Midlle of the month', () { + test('Middle of the month', () { expect( DueDateTime.utc(every: dueDay30, year: year, month: 2, day: 15), equals(matcher), @@ -63,7 +63,7 @@ void main() { }); test('Previous month end', () { expect( - DueDateTime.utc(every: dueDay30, year: year, month: 1, day: 31), + DueDateTime.utc(every: dueDay30, year: year, day: 31), equals(matcher), ); }); @@ -194,7 +194,7 @@ void main() { test('Different day', () { expect( dueDate.copyWith(day: 2), - equals(DateTime(2022, 2, 1)), + equals(DateTime(2022, 2)), ); }); test('Different hour', () { @@ -230,7 +230,7 @@ void main() { }); test('toUtc', () { final dueDate = - DueDateTime(every: EveryDueDayMonth(30), year: 2022).toUtc(); + DueDateTime(every: const EveryDueDayMonth(30), year: 2022).toUtc(); expect( dueDate.isUtc, isTrue, @@ -238,36 +238,37 @@ void main() { }); test('toLocal', () { final dueDate = - DueDateTime.utc(every: EveryDueDayMonth(30), year: 2022).toLocal(); + DueDateTime.utc(every: const EveryDueDayMonth(30), year: 2022) + .toLocal(); expect( dueDate.isUtc, isFalse, ); }); group('Add:', () { - final dueDate = DueDateTime(every: EveryDueDayMonth(30), year: 2022); + final dueDate = DueDateTime(every: const EveryDueDayMonth(30), year: 2022); test('2 days', () { expect( dueDate.add(const Duration(days: 2)), equals(DateTime(2022, 2, 28)), ); }); - test('2 days, don\'t keep every', () { + test("2 days, don't keep every", () { expect( dueDate.add(const Duration(days: 2), sameEvery: false), - equals(DateTime(2022, 2, 1)), + equals(DateTime(2022, 2)), ); }); }); group('Subtract:', () { - final dueDate = DueDateTime(every: EveryDueDayMonth(30), year: 2022); + final dueDate = DueDateTime(every: const EveryDueDayMonth(30), year: 2022); test('2 days', () { expect( dueDate.subtract(const Duration(days: 2)), equals(DateTime(2022, 1, 30)), ); }); - test('2 days, don\'t keep every', () { + test("2 days, don't keep every", () { expect( dueDate.subtract(const Duration(days: 2), sameEvery: false), equals(DateTime(2022, 1, 28)), @@ -275,7 +276,7 @@ void main() { }); }); group('AddWeeks:', () { - final dueDate = DueDateTime(every: EveryDueDayMonth(30), year: 2022); + final dueDate = DueDateTime(every: const EveryDueDayMonth(30), year: 2022); test('1 week', () { expect( dueDate.addWeeks(1), @@ -288,7 +289,7 @@ void main() { equals(DateTime(2022, 2, 28)), ); }); - test('2 weeks, don\'t keep every', () { + test("2 weeks, don't keep every", () { expect( dueDate.addWeeks(2, sameEvery: false), equals(DateTime(2022, 2, 13)), @@ -296,7 +297,7 @@ void main() { }); }); group('SubtractWeeks:', () { - final dueDate = DueDateTime(every: EveryDueDayMonth(30), year: 2022); + final dueDate = DueDateTime(every: const EveryDueDayMonth(30), year: 2022); test('1 week', () { expect( dueDate.subtractWeeks(1), @@ -309,7 +310,7 @@ void main() { equals(dueDate), ); }); - test('2 weeks, don\'t keep every', () { + test("2 weeks, don't keep every", () { expect( dueDate.subtractWeeks(2, sameEvery: false), equals(DateTime(2022, 1, 16)), @@ -318,7 +319,7 @@ void main() { }); group('AddMonths', () { final dueDate = DueDateTime( - every: EveryWeekdayCountInMonth( + every: const EveryWeekdayCountInMonth( day: Weekday.sunday, week: Week.last, ), @@ -336,7 +337,7 @@ void main() { equals(DateTime(2022, 4, 24)), ); }); - test('Add 3 month don\'t keep every', () { + test("Add 3 month don't keep every", () { final newDueDate = DueDateTime.fromDate(dueDate.addMonths(3)); final actual = dueDate.addMonths(3, sameEvery: false); expect(actual, equals(newDueDate)); @@ -349,7 +350,7 @@ void main() { }); group('SubtractMonths', () { final dueDate = DueDateTime( - every: EveryWeekdayCountInMonth( + every: const EveryWeekdayCountInMonth( day: Weekday.sunday, week: Week.last, ), @@ -379,7 +380,7 @@ void main() { }); }); test('Subtract 1 year', () { - final dueDate = DueDateTime(every: EveryDayInYear(30), year: 2022); + final dueDate = DueDateTime(every: const EveryDayInYear(30), year: 2022); final newDueDate = DueDateTime.fromDate(dueDate.subtractYears(1)); expect( dueDate.subtractYears(1), @@ -395,7 +396,7 @@ void main() { ); }); test('Add 1 year', () { - final dueDate = DueDateTime(every: EveryDayInYear(30), year: 2022); + final dueDate = DueDateTime(every: const EveryDayInYear(30), year: 2022); final newDueDate = DueDateTime.fromDate(dueDate.addYears(1)); expect( dueDate.addYears(1), @@ -414,7 +415,7 @@ void main() { group('Local', () { test('EveryWeek', () { final everyWeekday = DueDateTime( - every: EveryWeekday(Weekday.monday), + every: const EveryWeekday(Weekday.monday), year: 2022, month: DateTime.august, day: 22, @@ -426,7 +427,7 @@ void main() { }); test('EveryDueDayMonth', () { final everyWeekday = DueDateTime( - every: EveryDueDayMonth(22), + every: const EveryDueDayMonth(22), year: 2022, month: DateTime.august, day: 22, @@ -440,7 +441,7 @@ void main() { final day = DateTime(2022, DateTime.august, 22); final everyWeekday = DueDateTime.fromDate( day, - every: EveryWeekdayCountInMonth( + every: const EveryWeekdayCountInMonth( day: Weekday.monday, week: Week.fourth, ), @@ -468,7 +469,7 @@ void main() { group('UTC', () { test('EveryWeek', () { final everyWeekday = DueDateTime.utc( - every: EveryWeekday(Weekday.monday), + every: const EveryWeekday(Weekday.monday), year: 2022, month: DateTime.august, day: 22, @@ -480,7 +481,7 @@ void main() { }); test('EveryDueDayMonth', () { final everyWeekday = DueDateTime.utc( - every: EveryDueDayMonth(22), + every: const EveryDueDayMonth(22), year: 2022, month: DateTime.august, day: 22, @@ -494,7 +495,7 @@ void main() { final day = DateTime.utc(2022, DateTime.august, 22); final everyWeekday = DueDateTime.fromDate( day, - every: EveryWeekdayCountInMonth( + every: const EveryWeekdayCountInMonth( day: Weekday.monday, week: Week.fourth, ), diff --git a/test/enums_test.dart b/test/enums_test.dart index cb4a2c5..c694756 100644 --- a/test/enums_test.dart +++ b/test/enums_test.dart @@ -88,54 +88,54 @@ void main() { }); } }); - group('occrurencesIn august 2022', () { - final month = DateTime.utc(2022, DateTime.august, 1); + group('occurrencesIn august 2022', () { + final month = DateTime.utc(2022, DateTime.august); test('monday', () { const monday = Weekday.monday; expect( - monday.occrurencesIn(month.year, month.month), + monday.occurrencesIn(month.year, month.month), equals(5), ); }); test('tuesday', () { const tuesday = Weekday.tuesday; expect( - tuesday.occrurencesIn(month.year, month.month), + tuesday.occurrencesIn(month.year, month.month), equals(5), ); }); test('wednesday', () { const wednesday = Weekday.wednesday; expect( - wednesday.occrurencesIn(month.year, month.month), + wednesday.occurrencesIn(month.year, month.month), equals(5), ); }); test('thursday', () { const thursday = Weekday.thursday; expect( - thursday.occrurencesIn(month.year, month.month), + thursday.occurrencesIn(month.year, month.month), equals(4), ); }); test('friday', () { const friday = Weekday.friday; expect( - friday.occrurencesIn(month.year, month.month), + friday.occurrencesIn(month.year, month.month), equals(4), ); }); test('saturday', () { const saturday = Weekday.saturday; expect( - saturday.occrurencesIn(month.year, month.month), + saturday.occurrencesIn(month.year, month.month), equals(4), ); }); test('sunday', () { const sunday = Weekday.sunday; expect( - sunday.occrurencesIn(month.year, month.month), + sunday.occurrencesIn(month.year, month.month), equals(4), ); }); @@ -226,7 +226,7 @@ void main() { const month = Month.august; group('First', () { const matcher = Week.first; - final firstDayOfWeek = DateTime(year, month.dateTimeValue, 1); + final firstDayOfWeek = DateTime(year, month.dateTimeValue); final lastDayOfWeek = DateTime(year, month.dateTimeValue, 7); test(Weekday.fromDateTimeValue(firstDayOfWeek.weekday).name, () { expect(Week.from(firstDayOfWeek), equals(matcher)); @@ -333,7 +333,7 @@ void main() { equals(weekGenerator.of(DateTime.utc(2022, DateTime.september, -2))), ); }); - test('Starts at the previous month\'s second to last day', () { + test("Starts at the previous month's second to last day", () { expect( first.of(2022, Month.june.dateTimeValue), equals(weekGenerator.of(DateTime.utc(2022, DateTime.may, 30))), @@ -343,7 +343,7 @@ void main() { equals(weekGenerator.of(DateTime.utc(2022, DateTime.june, -1))), ); }); - test('Starts at the previous month\'s last day', () { + test("Starts at the previous month's last day", () { expect( first.of(2022, Month.march.dateTimeValue), equals(weekGenerator.of(DateTime.utc(2022, DateTime.february, 28))), @@ -559,13 +559,13 @@ void main() { group('Weekday Of', () { group('Mondays of August 2022', () { final mondays = [ - DateTime.utc(2022, DateTime.august, 1), + DateTime.utc(2022, DateTime.august), DateTime.utc(2022, DateTime.august, 8), DateTime.utc(2022, DateTime.august, 15), DateTime.utc(2022, DateTime.august, 22), DateTime.utc(2022, DateTime.august, 29), ]; - final weekValues = Week.values; + const weekValues = Week.values; for (int i = 0; i < weekValues.length; i++) { test('${mondays[i].year}/${mondays[i].month}/${mondays[i].day}', () { expect( @@ -587,7 +587,7 @@ void main() { DateTime.utc(2022, DateTime.august, 26), DateTime.utc(2022, DateTime.august, 26), ]; - final weekValues = Week.values; + const weekValues = Week.values; for (int i = 0; i < weekValues.length; i++) { test('${fridays[i].year}/${fridays[i].month}/${fridays[i].day}', () { expect( @@ -606,13 +606,13 @@ void main() { group('WeekdayOccurrence', () { group('Equals', () { test('FirstMonday', () { - const weekdayOccurence = WeekdayOccurrence.firstMonday; + const weekdayOccurrence = WeekdayOccurrence.firstMonday; const everyWeekdayCountInMonth = EveryWeekdayCountInMonth( week: Week.first, day: Weekday.monday, ); expect( - weekdayOccurence, + weekdayOccurrence, equals(everyWeekdayCountInMonth), ); }); diff --git a/test/every_test.dart b/test/every_test.dart index 743bcc6..b591d20 100644 --- a/test/every_test.dart +++ b/test/every_test.dart @@ -5,6 +5,71 @@ void main() { group('EveryWeekday:', () { final august12th2022 = DateTime(2022, DateTime.august, 12); final august12th2022Utc = DateTime.utc(2022, DateTime.august, 12); + + group('Test base methods logic', () { + group('startDate', () { + final august13th = DateTime(2022, DateTime.august, 13); + test('If the given date would be generated, return it', () { + expect( + Weekday.saturday.every.startDate(august13th), + equals(august13th), + ); + }); + test('If the given date would not be generated, use next', () { + expect( + Weekday.saturday.every.startDate(august12th2022), + equals(Weekday.saturday.every.next(august12th2022)), + ); + }); + }); + group('next', () { + final august13th = DateTime(2022, DateTime.august, 13); + final august20th = DateTime(2022, DateTime.august, 20); + test( + 'If the given date would be generated, generate a new one anyway', + () { + expect( + Weekday.saturday.every.next(august13th), + equals(august20th), + ); + }, + ); + test( + 'If the given date would not be generated, generate the next valid ' + 'date', + () { + expect( + Weekday.saturday.every.next(august12th2022), + equals(august13th), + ); + }, + ); + }); + group('previous', () { + final august13th = DateTime(2022, DateTime.august, 13); + final august6th = DateTime(2022, DateTime.august, 6); + test( + 'If the given date would be generated, generate a new one anyway', + () { + expect( + Weekday.saturday.every.previous(august13th), + equals(august6th), + ); + }, + ); + test( + 'If the given date would not be generated, generate the next valid ' + 'date', + () { + expect( + Weekday.saturday.every.previous(august12th2022), + equals(august6th), + ); + }, + ); + }); + }); + group('Every Saturday', () { const everySaturday = EveryWeekday(Weekday.saturday); group('Local', () { @@ -69,11 +134,52 @@ void main() { group('EveryWeekdayCountInMonth:', () { final august12th2022 = DateTime(2022, DateTime.august, 12); final august12th2022Utc = DateTime.utc(2022, DateTime.august, 12); - test('Right day', () { - final date = DateTime(2022, DateTime.august, 12); - final every = EveryWeekdayCountInMonth.from(date); - expect(every.startDate(august12th2022), equals(date)); + + group('Test base methods logic', () { + const every = EveryWeekdayCountInMonth( + day: Weekday.saturday, + week: Week.second, + ); + group('startDate', () { + final august13th = DateTime(2022, DateTime.august, 13); + test('If the given date would be generated, return it', () { + expect(every.startDate(august13th), equals(august13th)); + }); + test('If the given date would not be generated, use next', () { + expect( + every.startDate(DateTime(2022, DateTime.august, 14)), + equals(every.next(DateTime(2022, DateTime.august, 14))), + ); + }); + }); + group('next', () { + final august13th = DateTime(2022, DateTime.august, 13); + final september10th = DateTime(2022, DateTime.september, 10); + test( + 'If the given date would be generated, generate a new one anyway', + () => expect(every.next(august13th), equals(september10th)), + ); + test( + 'If the given date would not be generated, generate the next valid ' + 'date', + () => expect(every.next(august12th2022), equals(august13th)), + ); + }); + group('previous', () { + final august13th = DateTime(2022, DateTime.august, 13); + final july9th = DateTime(2022, DateTime.july, 9); + test( + 'If the given date would be generated, generate a new one anyway', + () => expect(every.previous(august13th), equals(july9th)), + ); + test( + 'If the given date would not be generated, generate the next valid ' + 'date', + () => expect(every.previous(august12th2022), equals(july9th)), + ); + }); }); + group('First Monday', () { const firstMondayOfMonth = EveryWeekdayCountInMonth( week: Week.first, @@ -88,7 +194,7 @@ void main() { equals(matcher), ); expect( - firstMondayOfMonth.addMonths(middleOfPreviousMonth, 1), + firstMondayOfMonth.addMonths(middleOfPreviousMonth, 0), equals(matcher), ); }); @@ -100,7 +206,7 @@ void main() { equals(matcher), ); expect( - firstMondayOfMonth.addMonths(middleOfPreviousMonth, 1), + firstMondayOfMonth.addMonths(middleOfPreviousMonth, 0), equals(matcher), ); }); @@ -112,7 +218,7 @@ void main() { equals(matcher), ); expect( - firstMondayOfMonth.addMonths(middleOfPreviousMonth, 1), + firstMondayOfMonth.addMonths(middleOfPreviousMonth, 0), equals(matcher), ); }); @@ -124,7 +230,7 @@ void main() { equals(matcher), ); expect( - firstMondayOfMonth.addMonths(middleOfPreviousMonth, 1), + firstMondayOfMonth.addMonths(middleOfPreviousMonth, 0), equals(matcher), ); }); @@ -132,7 +238,7 @@ void main() { final matcher = DateTime(2022, DateTime.september, 5); expect(firstMondayOfMonth.startDate(august12th2022), equals(matcher)); expect( - firstMondayOfMonth.addMonths(august12th2022, 1), + firstMondayOfMonth.addMonths(august12th2022, 0), equals(matcher), ); }); @@ -144,7 +250,7 @@ void main() { equals(matcher), ); expect( - firstMondayOfMonth.addMonths(middleOfPreviousMonth, 1), + firstMondayOfMonth.addMonths(middleOfPreviousMonth, 0), equals(matcher), ); }); @@ -156,7 +262,7 @@ void main() { equals(matcher), ); expect( - firstMondayOfMonth.addMonths(middleOfPreviousMonth, 1), + firstMondayOfMonth.addMonths(middleOfPreviousMonth, 0), equals(matcher), ); }); @@ -174,7 +280,7 @@ void main() { equals(matcher), ); expect( - firstMondayOfMonth.addMonths(middleOfPreviousMonthUtc, 1), + firstMondayOfMonth.addMonths(middleOfPreviousMonthUtc, 0), equals(matcher), ); }); @@ -190,7 +296,7 @@ void main() { equals(matcher), ); expect( - firstMondayOfMonth.addMonths(middleOfPreviousMonthUtc, 1), + firstMondayOfMonth.addMonths(middleOfPreviousMonthUtc, 0), equals(matcher), ); }); @@ -206,7 +312,7 @@ void main() { equals(matcher), ); expect( - firstMondayOfMonth.addMonths(middleOfPreviousMonthUtc, 1), + firstMondayOfMonth.addMonths(middleOfPreviousMonthUtc, 0), equals(matcher), ); }); @@ -222,7 +328,7 @@ void main() { equals(matcher), ); expect( - firstMondayOfMonth.addMonths(middleOfPreviousMonthUtc, 1), + firstMondayOfMonth.addMonths(middleOfPreviousMonthUtc, 0), equals(matcher), ); }); @@ -233,7 +339,7 @@ void main() { equals(matcher), ); expect( - firstMondayOfMonth.addMonths(august12th2022Utc, 1), + firstMondayOfMonth.addMonths(august12th2022Utc, 0), equals(matcher), ); }); @@ -249,7 +355,7 @@ void main() { equals(matcher), ); expect( - firstMondayOfMonth.addMonths(middleOfPreviousMonthUtc, 1), + firstMondayOfMonth.addMonths(middleOfPreviousMonthUtc, 0), equals(matcher), ); }); @@ -265,7 +371,7 @@ void main() { equals(matcher), ); expect( - firstMondayOfMonth.addMonths(middleOfPreviousMonthUtc, 1), + firstMondayOfMonth.addMonths(middleOfPreviousMonthUtc, 0), equals(matcher), ); }); @@ -313,6 +419,54 @@ void main() { }); }); group('EveryDueDayMonth:', () { + group('Test base methods logic', () { + const every = EveryDueDayMonth(15); + group('startDate', () { + final august15th = DateTime(2022, DateTime.august, 15); + test('If the given date would be generated, return it', () { + expect(every.startDate(august15th), equals(august15th)); + }); + test('If the given date would not be generated, use next', () { + expect( + every.startDate(DateTime(2022, DateTime.august, 14)), + equals(every.next(DateTime(2022, DateTime.august, 14))), + ); + }); + }); + group('next', () { + final august15th = DateTime(2022, DateTime.august, 15); + final september15th = DateTime(2022, DateTime.september, 15); + test( + 'If the given date would be generated, generate a new one anyway', + () => expect(every.next(august15th), equals(september15th)), + ); + test( + 'If the given date would not be generated, generate the next valid ' + 'date', + () => expect( + every.next(DateTime(2022, DateTime.august, 14)), + equals(august15th), + ), + ); + }); + group('previous', () { + final august15th = DateTime(2022, DateTime.august, 15); + final july15th = DateTime(2022, DateTime.july, 15); + test( + 'If the given date would be generated, generate a new one anyway', + () => expect(every.previous(august15th), equals(july15th)), + ); + test( + 'If the given date would not be generated, generate the previous ' + 'valid date', + () => expect( + every.previous(DateTime(2022, DateTime.august, 16)), + equals(august15th), + ), + ); + }); + }); + group('Every day 31', () { const everyDay31 = EveryDueDayMonth(31); group('Local', () { @@ -381,6 +535,60 @@ void main() { group('EveryDayInYear:', () { final august12th2022 = DateTime(2022, DateTime.august, 12); final august12th2022Utc = DateTime.utc(2022, DateTime.august, 12); + + group('Test base methods logic', () { + const every = EveryDayInYear(15); + group('startDate', () { + final january15th = DateTime(2022, DateTime.january, 15); + test('If the given date would be generated, return it', () { + expect( + every.startDate(january15th), + equals(january15th), + ); + }); + test('If the given date would not be generated, use next', () { + expect( + every.startDate(DateTime(2022, DateTime.january, 14)), + equals(every.next(DateTime(2022, DateTime.january, 14))), + ); + }); + }); + group('next', () { + final january15th2022 = DateTime(2022, DateTime.january, 15); + final january15th2023 = DateTime(2023, DateTime.january, 15); + test( + 'If the given date would be generated, generate a new one anyway', + () => expect(every.next(january15th2022), equals(january15th2023)), + ); + test( + 'If the given date would not be generated, generate the next valid ' + 'date', + () => expect( + every.next(DateTime(2022, DateTime.january, 14)), + equals(january15th2022), + ), + ); + }); + group('previous', () { + final january15th2022 = DateTime(2022, DateTime.january, 15); + final january15th2021 = DateTime(2021, DateTime.january, 15); + + test( + 'If the given date would be generated, generate a new one anyway', + () => + expect(every.previous(january15th2022), equals(january15th2021)), + ); + test( + 'If the given date would not be generated, generate the next valid ' + 'date', + () => expect( + every.previous(DateTime(2022, DateTime.january, 14)), + equals(january15th2021), + ), + ); + }); + }); + group('Every Day 1', () { const everyDay1 = EveryDayInYear(1); group('Local', () { @@ -389,7 +597,7 @@ void main() { expect(everyDay1.startDate(august12th2022), equals(nextYearsDayOne)); }); test('Previous Year', () { - final previousYearsDay1 = DateTime(2021); + final previousYearsDay1 = DateTime(2022); expect( everyDay1.addYears(august12th2022, -1), equals(previousYearsDay1), @@ -412,7 +620,7 @@ void main() { ); }); test('Previous Year', () { - final previousYearsDay1Utc = DateTime.utc(2021); + final previousYearsDay1Utc = DateTime.utc(2022); expect( everyDay1.addYears(august12th2022Utc, -1), equals(previousYearsDay1Utc), @@ -427,7 +635,7 @@ void main() { }); }); }); - group('Every Programmer\'s Day', () { + group("Every Programmer's Day", () { const programmersDay = EveryDayInYear(256); group('Local', () { test('This year', () { @@ -557,10 +765,60 @@ void main() { }); }); group('EveryDateValidatorIntersection', () { - final everies = EveryDateValidatorIntersection([ + const everies = EveryDateValidatorIntersection([ EveryDueDayMonth(24), EveryDateValidatorDifference([EveryWeekday(Weekday.saturday)]), ]); + + group('Test base methods logic', () { + final date = DateTime(2021, DateTime.july, 25); + final expected = DateTime(2022, DateTime.september, 24); + group('startDate', () { + test('If the given date would be generated, return it', () { + expect( + everies.startDate(expected), + equals(expected), + ); + }); + test('If the given date would not be generated, use next', () { + expect( + everies.startDate(date), + equals(everies.next(date)), + ); + }); + }); + group('next', () { + test( + 'If the given date would be generated, generate a new one anyway', + () => expect( + everies.next(expected), + equals(DateTime(2022, DateTime.december, 24)), + ), + ); + test( + 'If the given date would not be generated, generate the next valid ' + 'date', + () => expect(everies.next(date), equals(expected)), + ); + }); + group('previous', () { + final expectedPrevious = DateTime(2021, DateTime.july, 24); + + test( + 'If the given date would be generated, generate a new one anyway', + () => expect( + everies.previous(expected), + equals(expectedPrevious), + ), + ); + test( + 'If the given date would not be generated, generate the next valid ' + 'date', + () => expect(everies.previous(date), equals(expectedPrevious)), + ); + }); + }); + group('Start Date', () { test('September 24th 2022', () { final date = DateTime(2021, DateTime.july, 25); @@ -577,13 +835,6 @@ void main() { final throwsDateTimeLimitReachedException = throwsA( isA(), ); - test('Self', () { - final limit = DateTime(2021, DateTime.july, 22); - expect( - () => everies.startDate(date, limit: limit), - throwsDateTimeLimitReachedException, - ); - }); test('Inner every', () { final limit = DateTime(2021, DateTime.july, 23); expect( @@ -592,6 +843,12 @@ void main() { ); }); }); + test('The limit is the expected date', () { + final date = DateTime(2021, DateTime.july, 23); + final expected = DateTime(2021, DateTime.july, 24); + + expect(everies.startDate(date, limit: expected), equals(expected)); + }); }); group('Next', () { test('September 24th 2022', () { @@ -609,13 +866,6 @@ void main() { final throwsDateTimeLimitReachedException = throwsA( isA(), ); - test('Self', () { - final limit = DateTime(2021, DateTime.july, 22); - expect( - () => everies.next(date, limit: limit), - throwsDateTimeLimitReachedException, - ); - }); test('Inner every', () { final limit = DateTime(2021, DateTime.july, 23); expect( @@ -624,6 +874,12 @@ void main() { ); }); }); + test('The limit is the expected date', () { + final date = DateTime(2021, DateTime.july, 23); + final expected = DateTime(2021, DateTime.july, 24); + + expect(everies.next(date, limit: expected), equals(expected)); + }); }); group('Previous', () { test('July 24th 2021', () { @@ -641,13 +897,6 @@ void main() { final throwsDateTimeLimitReachedException = throwsA( isA(), ); - test('Self', () { - final limit = DateTime(2022, DateTime.september, 26); - expect( - () => everies.previous(date, limit: limit), - throwsDateTimeLimitReachedException, - ); - }); test('Inner every', () { final limit = DateTime(2022, DateTime.september, 25); expect( @@ -656,13 +905,69 @@ void main() { ); }); }); + test('The limit is the expected date', () { + final date = DateTime(2021, DateTime.september, 26); + final expected = DateTime(2021, DateTime.july, 24); + + expect(everies.previous(date, limit: expected), equals(expected)); + }); }); }); group('DateValidatorUnion', () { - final everies = EveryDateValidatorUnion([ + const everies = EveryDateValidatorUnion([ EveryDueDayMonth(24), EveryDateValidatorDifference([EveryWeekday(Weekday.saturday)]), ]); + + group('Test base methods logic', () { + final date = DateTime(2022, DateTime.september, 23); + final expected = DateTime(2022, DateTime.september, 24); + group('startDate', () { + test('If the given date would be generated, return it', () { + expect( + everies.startDate(expected), + equals(expected), + ); + }); + test('If the given date would not be generated, use next', () { + expect( + everies.startDate(date), + equals(everies.next(date)), + ); + }); + }); + group('next', () { + test( + 'If the given date would be generated, generate a new one anyway', + () => expect( + everies.next(expected), + equals(DateTime(2022, DateTime.october)), + ), + ); + test( + 'If the given date would not be generated, generate the next valid ' + 'date', + () => expect( + everies.next(DateTime(2022, DateTime.september, 17)), + equals(expected), + ), + ); + }); + group('previous', () { + final expectedPrevious = DateTime(2022, DateTime.september, 17); + + test( + 'If the given date would be generated, generate a new one anyway', + () => expect(everies.previous(expected), equals(expectedPrevious)), + ); + test( + 'If the given date would not be generated, generate the next valid ' + 'date', + () => expect(everies.previous(date), equals(expectedPrevious)), + ); + }); + }); + group('Start Date', () { test('All valid', () { final date = DateTime(2022, DateTime.september, 23); @@ -692,6 +997,12 @@ void main() { ); }); }); + test('The limit is the expected date', () { + final date = DateTime(2021, DateTime.july, 23); + final expected = DateTime(2021, DateTime.july, 24); + + expect(everies.startDate(date, limit: expected), equals(expected)); + }); }); group('Next', () { test('All valid', () { @@ -722,6 +1033,12 @@ void main() { ); }); }); + test('The limit is the expected date', () { + final date = DateTime(2021, DateTime.july, 23); + final expected = DateTime(2021, DateTime.july, 24); + + expect(everies.next(date, limit: expected), equals(expected)); + }); }); group('Previous', () { test('All valid', () { @@ -752,17 +1069,70 @@ void main() { ); }); }); + test('The limit is the expected date', () { + final date = DateTime(2022, DateTime.september, 25); + final expected = DateTime(2022, DateTime.september, 24); + + expect(everies.previous(date, limit: expected), equals(expected)); + }); }); }); group('DateValidatorDifference', () { - final everies = EveryDateValidatorDifference([ + const everies = EveryDateValidatorDifference([ EveryDueDayMonth(24), EveryDateValidatorIntersection([EveryWeekday(Weekday.saturday)]), ]); + + group('Test base methods logic', () { + final date = DateTime(2022, DateTime.september, 23); + final expected = DateTime(2022, DateTime.october); + group('startDate', () { + test('If the given date would be generated, return it', () { + expect( + everies.startDate(expected), + equals(expected), + ); + }); + test('If the given date would not be generated, use next', () { + expect( + everies.startDate(date), + equals(everies.next(date)), + ); + }); + }); + group('next', () { + test( + 'If the given date would be generated, generate a new one anyway', + () => expect( + everies.next(expected), + equals(DateTime(2022, DateTime.october, 8)), + ), + ); + test( + 'If the given date would not be generated, generate the next valid ' + 'date', + () => expect(everies.next(date), equals(expected)), + ); + }); + group('previous', () { + final expectedPrevious = DateTime(2022, DateTime.september, 17); + + test( + 'If the given date would be generated, generate a new one anyway', + () => expect(everies.previous(expected), equals(expectedPrevious)), + ); + test( + 'If the given date would not be generated, generate the next valid ' + 'date', + () => expect(everies.previous(date), equals(expectedPrevious)), + ); + }); + }); + group('Start Date', () { test('All valid', () { final date = DateTime(2022, DateTime.september, 24); - final expected = DateTime(2022, DateTime.october, 1); + final expected = DateTime(2022, DateTime.october); expect(everies.startDate(date), equals(expected)); }); test('Wrong day', () { @@ -780,13 +1150,6 @@ void main() { final throwsDateTimeLimitReachedException = throwsA( isA(), ); - test('Self', () { - final limit = DateTime(2022, DateTime.september, 24); - expect( - () => everies.startDate(date, limit: limit), - throwsDateTimeLimitReachedException, - ); - }); test('Inner every', () { final limit = DateTime(2022, DateTime.september, 25); expect( @@ -795,11 +1158,17 @@ void main() { ); }); }); + test('The limit is the expected date', () { + final date = DateTime(2022, DateTime.september, 24); + final expected = DateTime(2022, DateTime.october); + + expect(everies.startDate(date, limit: expected), equals(expected)); + }); }); group('Next', () { test('All valid', () { final date = DateTime(2022, DateTime.september, 24); - final expected = DateTime(2022, DateTime.october, 1); + final expected = DateTime(2022, DateTime.october); expect(everies.next(date), equals(expected)); }); test('Wrong day', () { @@ -817,13 +1186,6 @@ void main() { final throwsDateTimeLimitReachedException = throwsA( isA(), ); - test('Self', () { - final limit = DateTime(2022, DateTime.september, 24); - expect( - () => everies.next(date, limit: limit), - throwsDateTimeLimitReachedException, - ); - }); test('Inner every', () { final limit = DateTime(2022, DateTime.september, 25); expect( @@ -832,6 +1194,12 @@ void main() { ); }); }); + test('The limit is the expected date', () { + final date = DateTime(2022, DateTime.september, 24); + final expected = DateTime(2022, DateTime.october); + + expect(everies.next(date, limit: expected), equals(expected)); + }); }); group('Previous', () { test('All valid', () { @@ -854,13 +1222,6 @@ void main() { final throwsDateTimeLimitReachedException = throwsA( isA(), ); - test('Self', () { - final limit = DateTime(2022, DateTime.september, 26); - expect( - () => everies.previous(date, limit: limit), - throwsDateTimeLimitReachedException, - ); - }); test('Inner every', () { final limit = DateTime(2022, DateTime.september, 25); expect( @@ -869,6 +1230,12 @@ void main() { ); }); }); + test('The limit is the expected date', () { + final date = DateTime(2022, DateTime.september, 26); + final expected = DateTime(2022, DateTime.september, 17); + + expect(everies.previous(date, limit: expected), equals(expected)); + }); }); }); } diff --git a/test/extensions_test.dart b/test/extensions_test.dart index 0fbe7fd..df86623 100644 --- a/test/extensions_test.dart +++ b/test/extensions_test.dart @@ -5,7 +5,7 @@ import 'package:test/scaffolding.dart'; void main() { group('DayInYear on DateTime', () { test('January 1st', () { - expect(DateTime(2022, DateTime.january, 1).dayInYear, 1); + expect(DateTime(2022).dayInYear, 1); }); test('December 31st 2022', () { expect(DateTime(2022, DateTime.december, 31).dayInYear, 365); @@ -17,8 +17,8 @@ void main() { group('AddDays on DateTime:', () { group('Add/Subtract Days:', () { final monday = DateTime.utc(2022, DateTime.july, 18); - group('Throws won\'t skip all days', () { - final allWeek = Weekday.values; + group("Throws won't skip all days", () { + const allWeek = Weekday.values; test('Add ignoring all weekdays', () { expect( () => monday.addDays(1, ignoring: allWeek), @@ -62,7 +62,7 @@ void main() { test('Monday', () { expect( august.nextWeekday(Weekday.monday), - equals(DateTime.utc(2022, DateTime.august, 1)), + equals(DateTime.utc(2022, DateTime.august)), ); }); test('Tuesday', () { @@ -107,7 +107,7 @@ void main() { test('Monday', () { expect( august.previousWeekday(Weekday.monday), - equals(DateTime.utc(2022, DateTime.august, 1)), + equals(DateTime.utc(2022, DateTime.august)), ); }); test('Tuesday', () { @@ -160,22 +160,21 @@ void main() { group('daysBefore:', () { group('single:', () { for (final weekday in Weekday.values) { - final macther = [weekday.previous]; + final matcher = [weekday.previous]; final result = [weekday].previousWeekdays; test( weekday.name, - () => expect(result, containsAll(macther)), + () => expect(result, containsAll(matcher)), ); } }); group('multiple:', () { for (final weekday in Weekday.values) { - final macther = {...entireWeek}..remove(weekday.previous); - final iterable = [...entireWeek]; - iterable.remove(weekday); + final matcher = {...entireWeek}..remove(weekday.previous); + final iterable = [...entireWeek]..remove(weekday); test( 'all but ${weekday.name}', - () => expect(iterable.previousWeekdays, containsAll(macther)), + () => expect(iterable.previousWeekdays, containsAll(matcher)), ); } }); @@ -183,21 +182,20 @@ void main() { group('daysAfter:', () { group('single:', () { for (final weekday in Weekday.values) { - final macther = {weekday.next}; + final matcher = {weekday.next}; test( weekday.next, - () => expect([weekday].nextWeekdays, equals(macther)), + () => expect([weekday].nextWeekdays, equals(matcher)), ); } }); group('multiple:', () { for (final weekday in Weekday.values) { - final macther = {...entireWeek}..remove(weekday.next); - final iterable = [...entireWeek]; - iterable.remove(weekday); + final matcher = {...entireWeek}..remove(weekday.next); + final iterable = [...entireWeek]..remove(weekday); test( 'all but ${weekday.name}', - () => expect(iterable.nextWeekdays, containsAll(macther)), + () => expect(iterable.nextWeekdays, containsAll(matcher)), ); } }); diff --git a/test/period_generator_test.dart b/test/period_generator_test.dart index 3f979ef..3a3d3bf 100644 --- a/test/period_generator_test.dart +++ b/test/period_generator_test.dart @@ -7,11 +7,11 @@ void main() { const generator = SecondGenerator(); group('of', () { final period = Period( - start: DateTime(2020, 1, 1, 0, 0, 0), + start: DateTime(2020), end: DateTime(2020, 1, 1, 0, 0, 0, 999, 999), ); test('Start of second', () { - final second = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final second = generator.of(DateTime(2020)); expect(second, equals(period)); }); test('End of second', () { @@ -21,7 +21,7 @@ void main() { }); group('after', () { test('Start of second', () { - final second = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final second = generator.of(DateTime(2020)); final next = generator.after(second); final expected = Period( start: DateTime(2020, 1, 1, 0, 0, 1), @@ -41,7 +41,7 @@ void main() { }); group('before', () { test('Start of second', () { - final second = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final second = generator.of(DateTime(2020)); final previous = generator.before(second); final expected = Period( start: DateTime(2019, 12, 31, 23, 59, 59), @@ -61,7 +61,7 @@ void main() { }); test('fits generator', () { final period = Period( - start: DateTime(2020, 1, 1, 0, 0, 0), + start: DateTime(2020), end: DateTime(2020, 1, 1, 0, 0, 0, 999, 999), ); expect(generator.fitsGenerator(period), isTrue); @@ -71,11 +71,11 @@ void main() { const generator = MinuteGenerator(); group('of', () { final period = Period( - start: DateTime(2020, 1, 1, 0, 0, 0), + start: DateTime(2020), end: DateTime(2020, 1, 1, 0, 0, 59, 999, 999), ); test('Start of minute', () { - final minute = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final minute = generator.of(DateTime(2020)); expect(minute, equals(period)); }); test('End of minute', () { @@ -85,10 +85,10 @@ void main() { }); group('before', () { test('Start of minute', () { - final minute = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final minute = generator.of(DateTime(2020)); final previous = generator.before(minute); final expected = Period( - start: DateTime(2019, 12, 31, 23, 59, 0), + start: DateTime(2019, 12, 31, 23, 59), end: DateTime(2019, 12, 31, 23, 59, 59, 999, 999), ); expect(previous, equals(expected)); @@ -97,7 +97,7 @@ void main() { final minute = generator.of(DateTime(2020, 1, 1, 0, 0, 59, 999, 999)); final previous = generator.before(minute); final expected = Period( - start: DateTime(2019, 12, 31, 23, 59, 0), + start: DateTime(2019, 12, 31, 23, 59), end: DateTime(2019, 12, 31, 23, 59, 59, 999, 999), ); expect(previous, equals(expected)); @@ -105,10 +105,10 @@ void main() { }); group('after', () { test('Start of minute', () { - final minute = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final minute = generator.of(DateTime(2020)); final next = generator.after(minute); final expected = Period( - start: DateTime(2020, 1, 1, 0, 1, 0), + start: DateTime(2020, 1, 1, 0, 1), end: DateTime(2020, 1, 1, 0, 1, 59, 999, 999), ); expect(next, equals(expected)); @@ -117,7 +117,7 @@ void main() { final minute = generator.of(DateTime(2020, 1, 1, 0, 0, 59, 999, 999)); final next = generator.after(minute); final expected = Period( - start: DateTime(2020, 1, 1, 0, 1, 0), + start: DateTime(2020, 1, 1, 0, 1), end: DateTime(2020, 1, 1, 0, 1, 59, 999, 999), ); expect(next, equals(expected)); @@ -125,7 +125,7 @@ void main() { }); test('fits generator', () { final period = Period( - start: DateTime(2020, 1, 1, 0, 0, 0), + start: DateTime(2020), end: DateTime(2020, 1, 1, 0, 0, 59, 999, 999), ); expect(generator.fitsGenerator(period), isTrue); @@ -135,11 +135,11 @@ void main() { const generator = HourGenerator(); group('of', () { final period = Period( - start: DateTime(2020, 1, 1, 0, 0, 0), + start: DateTime(2020), end: DateTime(2020, 1, 1, 0, 59, 59, 999, 999), ); test('Start of hour', () { - final hour = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final hour = generator.of(DateTime(2020)); expect(hour, equals(period)); }); test('End of hour', () { @@ -149,16 +149,16 @@ void main() { }); group('minutes', () { const minuteGenerator = MinuteGenerator(); - final hour = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final hour = generator.of(DateTime(2020)); final minutes = hour.minutes; test('type', () { expect(minutes, isA>()); }); - test('lenght', () { + test('length', () { expect(minutes.length, equals(60)); }); test('Start of hour', () { - final firstMinute = minuteGenerator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final firstMinute = minuteGenerator.of(DateTime(2020)); expect(minutes.first, equals(firstMinute)); }); test('End of hour', () { @@ -170,10 +170,10 @@ void main() { }); group('before', () { test('Start of hour', () { - final hour = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final hour = generator.of(DateTime(2020)); final previous = generator.before(hour); final expected = Period( - start: DateTime(2019, 12, 31, 23, 0, 0), + start: DateTime(2019, 12, 31, 23), end: DateTime(2019, 12, 31, 23, 59, 59, 999, 999), ); expect(previous, equals(expected)); @@ -182,7 +182,7 @@ void main() { final hour = generator.of(DateTime(2020, 1, 1, 0, 59, 59, 999, 999)); final previous = generator.before(hour); final expected = Period( - start: DateTime(2019, 12, 31, 23, 0, 0), + start: DateTime(2019, 12, 31, 23), end: DateTime(2019, 12, 31, 23, 59, 59, 999, 999), ); expect(previous, equals(expected)); @@ -190,10 +190,10 @@ void main() { }); group('after', () { test('Start of hour', () { - final hour = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final hour = generator.of(DateTime(2020)); final next = generator.after(hour); final expected = Period( - start: DateTime(2020, 1, 1, 1, 0, 0), + start: DateTime(2020, 1, 1, 1), end: DateTime(2020, 1, 1, 1, 59, 59, 999, 999), ); expect(next, equals(expected)); @@ -202,7 +202,7 @@ void main() { final hour = generator.of(DateTime(2020, 1, 1, 0, 59, 59, 999, 999)); final next = generator.after(hour); final expected = Period( - start: DateTime(2020, 1, 1, 1, 0, 0), + start: DateTime(2020, 1, 1, 1), end: DateTime(2020, 1, 1, 1, 59, 59, 999, 999), ); expect(next, equals(expected)); @@ -210,7 +210,7 @@ void main() { }); test('fits generator', () { final period = Period( - start: DateTime(2020, 1, 1, 0, 0, 0), + start: DateTime(2020), end: DateTime(2020, 1, 1, 0, 59, 59, 999, 999), ); expect(generator.fitsGenerator(period), isTrue); @@ -220,11 +220,11 @@ void main() { const generator = DayGenerator(); group('of', () { final period = Period( - start: DateTime(2020, 1, 1, 0, 0, 0), + start: DateTime(2020), end: DateTime(2020, 1, 1, 23, 59, 59, 999, 999), ); test('Start of day', () { - final day = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final day = generator.of(DateTime(2020)); expect(day, equals(period)); }); test('End of day', () { @@ -234,16 +234,16 @@ void main() { }); group('hours', () { const hourGenerator = HourGenerator(); - final day = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final day = generator.of(DateTime(2020)); final hours = day.hours; test('type', () { expect(hours, isA>()); }); - test('lenght', () { + test('length', () { expect(hours.length, equals(24)); }); test('Start of day', () { - final firstHour = hourGenerator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final firstHour = hourGenerator.of(DateTime(2020)); expect(hours.first, equals(firstHour)); }); test('End of day', () { @@ -255,10 +255,10 @@ void main() { }); group('before', () { test('Start of day', () { - final day = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final day = generator.of(DateTime(2020)); final previous = generator.before(day); final expected = Period( - start: DateTime(2019, 12, 31, 0, 0, 0), + start: DateTime(2019, 12, 31), end: DateTime(2019, 12, 31, 23, 59, 59, 999, 999), ); expect(previous, equals(expected)); @@ -267,7 +267,7 @@ void main() { final day = generator.of(DateTime(2020, 1, 1, 23, 59, 59, 999, 999)); final previous = generator.before(day); final expected = Period( - start: DateTime(2019, 12, 31, 0, 0, 0), + start: DateTime(2019, 12, 31), end: DateTime(2019, 12, 31, 23, 59, 59, 999, 999), ); expect(previous, equals(expected)); @@ -275,10 +275,10 @@ void main() { }); group('after', () { test('Start of day', () { - final day = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final day = generator.of(DateTime(2020)); final next = generator.after(day); final expected = Period( - start: DateTime(2020, 1, 2, 0, 0, 0), + start: DateTime(2020, 1, 2), end: DateTime(2020, 1, 2, 23, 59, 59, 999, 999), ); expect(next, equals(expected)); @@ -287,7 +287,7 @@ void main() { final day = generator.of(DateTime(2020, 1, 1, 23, 59, 59, 999, 999)); final next = generator.after(day); final expected = Period( - start: DateTime(2020, 1, 2, 0, 0, 0), + start: DateTime(2020, 1, 2), end: DateTime(2020, 1, 2, 23, 59, 59, 999, 999), ); expect(next, equals(expected)); @@ -295,7 +295,7 @@ void main() { }); test('fits generator', () { final period = Period( - start: DateTime(2020, 1, 1, 0, 0, 0), + start: DateTime(2020), end: DateTime(2020, 1, 1, 23, 59, 59, 999, 999), ); expect(generator.fitsGenerator(period), isTrue); @@ -355,7 +355,7 @@ void main() { test('Starts sunday', () { const week = WeekGenerator(weekStart: DateTime.sunday); final period = Period( - start: DateTime(2023, 1, 1), + start: DateTime(2023), end: DateTime(2023, 1, 7, 23, 59, 59, 999, 999), ); expect(week.of(day), equals(period)); @@ -734,9 +734,9 @@ void main() { }); }); group('before', () { - final generator = WeekGenerator(); + const generator = WeekGenerator(); test('Start of week', () { - final week = generator.of(DateTime(2020, 1, 1)); + final week = generator.of(DateTime(2020)); final previous = generator.before(week); final expected = Period( start: DateTime(2019, 12, 23), @@ -755,9 +755,9 @@ void main() { }); }); group('after', () { - final generator = WeekGenerator(); + const generator = WeekGenerator(); test('Start of week', () { - final week = generator.of(DateTime(2020, 1, 1)); + final week = generator.of(DateTime(2020)); final next = generator.after(week); final expected = Period( start: DateTime(2020, 1, 6), @@ -776,7 +776,7 @@ void main() { }); }); test('fits generator', () { - final generator = WeekGenerator(); + const generator = WeekGenerator(); final period = Period( start: DateTime(2019, 12, 23), end: DateTime(2019, 12, 29, 23, 59, 59, 999, 999), @@ -787,7 +787,7 @@ void main() { group('FortnightPeriodGenerator', () { const fortnightGenerator = FortnightGenerator(); group('Start of month', () { - final day = DateTime(2022, DateTime.january, 1); + final day = DateTime(2022); final period = Period( start: day.date, end: DateTime(2022, 1, 15, 23, 59, 59, 999, 999), @@ -940,7 +940,7 @@ void main() { }); group('Before', () { const fortnightGenerator = FortnightGenerator(); - final day = DateTime(2022, DateTime.january, 1); + final day = DateTime(2022); final period = Period( start: day.date, end: DateTime(2022, 1, 15, 23, 59, 59, 999, 999), @@ -955,7 +955,7 @@ void main() { }); group('After', () { const fortnightGenerator = FortnightGenerator(); - final day = DateTime(2022, DateTime.january, 1); + final day = DateTime(2022); final period = Period( start: day.date, end: DateTime(2022, 1, 15, 23, 59, 59, 999, 999), @@ -972,7 +972,7 @@ void main() { const fortnightGenerator = FortnightGenerator(); test('start of month fits', () { final period = Period( - start: DateTime(2022, DateTime.january, 1), + start: DateTime(2022), end: DateTime(2022, 1, 15, 23, 59, 59, 999, 999), ); expect(fortnightGenerator.fitsGenerator(period), isTrue); @@ -1010,7 +1010,7 @@ void main() { group('MonthPeriodGenerator', () { const monthGenerator = MonthGenerator(); group('Start of month', () { - final day = DateTime(2022, DateTime.january, 1); + final day = DateTime(2022); final period = Period( start: day.date, end: DateTime(2022, 1, 31, 23, 59, 59, 999, 999), @@ -1041,7 +1041,7 @@ void main() { }); group('end of month', () { group('28th', () { - final day = DateTime(2022, DateTime.february, 1); + final day = DateTime(2022, DateTime.february); final period = Period( start: day.date, end: DateTime(2022, 2, 28, 23, 59, 59, 999, 999), @@ -1071,7 +1071,7 @@ void main() { }); }); group('29th', () { - final day = DateTime(2020, DateTime.february, 1); + final day = DateTime(2020, DateTime.february); final period = Period( start: day.date, end: DateTime(2020, 2, 29, 23, 59, 59, 999, 999), @@ -1101,7 +1101,7 @@ void main() { }); }); group('30th', () { - final day = DateTime(2022, DateTime.april, 1); + final day = DateTime(2022, DateTime.april); final period = Period( start: day.date, end: DateTime(2022, 4, 30, 23, 59, 59, 999, 999), @@ -1131,7 +1131,7 @@ void main() { }); }); group('31th', () { - final day = DateTime(2022, DateTime.january, 1); + final day = DateTime(2022); final period = Period( start: day.date, end: DateTime(2022, 1, 31, 23, 59, 59, 999, 999), @@ -1163,11 +1163,11 @@ void main() { }); group('before', () { final period = Period( - start: DateTime(2022, DateTime.january, 1), + start: DateTime(2022), end: DateTime(2022, DateTime.january, 31, 23, 59, 59, 999, 999), ); final expected = Period( - start: DateTime(2021, DateTime.december, 1), + start: DateTime(2021, DateTime.december), end: DateTime(2021, DateTime.december, 31, 23, 59, 59, 999, 999), ); test('before', () { @@ -1176,11 +1176,11 @@ void main() { }); group('after', () { final period = Period( - start: DateTime(2022, DateTime.january, 1), + start: DateTime(2022), end: DateTime(2022, 1, 31, 23, 59, 59, 999, 999), ); final expected = Period( - start: DateTime(2022, 2, 1), + start: DateTime(2022, 2), end: DateTime(2022, 2, 28, 23, 59, 59, 999, 999), ); test('after', () { @@ -1190,28 +1190,28 @@ void main() { group('fits generator', () { test('28 days', () { final period = Period( - start: DateTime(2022, DateTime.february, 1), + start: DateTime(2022, DateTime.february), end: DateTime(2022, 2, 28, 23, 59, 59, 999, 999), ); expect(monthGenerator.fitsGenerator(period), isTrue); }); test('29 days', () { final period = Period( - start: DateTime(2020, DateTime.february, 1), + start: DateTime(2020, DateTime.february), end: DateTime(2020, 2, 29, 23, 59, 59, 999, 999), ); expect(monthGenerator.fitsGenerator(period), isTrue); }); test('30 days', () { final period = Period( - start: DateTime(2022, DateTime.april, 1), + start: DateTime(2022, DateTime.april), end: DateTime(2022, 4, 30, 23, 59, 59, 999, 999), ); expect(monthGenerator.fitsGenerator(period), isTrue); }); test('31 days', () { final period = Period( - start: DateTime(2022, DateTime.january, 1), + start: DateTime(2022), end: DateTime(2022, 1, 31, 23, 59, 59, 999, 999), ); expect(monthGenerator.fitsGenerator(period), isTrue); @@ -1221,7 +1221,7 @@ void main() { group('TrimesterPeriodGenerator', () { const trimesterGenerator = TrimesterGenerator(); group('First trimester of the year', () { - final day = DateTime(2022, DateTime.january, 1); + final day = DateTime(2022); final period = Period( start: day.date, end: DateTime(2022, 3, 31, 23, 59, 59, 999, 999), @@ -1251,7 +1251,7 @@ void main() { }); }); group('Second trimester of the year', () { - final day = DateTime(2022, DateTime.april, 1); + final day = DateTime(2022, DateTime.april); final period = Period( start: day.date, end: DateTime(2022, 6, 30, 23, 59, 59, 999, 999), @@ -1281,7 +1281,7 @@ void main() { }); }); group('Third trimester of the year', () { - final day = DateTime(2022, DateTime.july, 1); + final day = DateTime(2022, DateTime.july); final period = Period( start: day.date, end: DateTime(2022, 9, 30, 23, 59, 59, 999, 999), @@ -1311,7 +1311,7 @@ void main() { }); }); group('Fourth trimester of the year', () { - final day = DateTime(2022, DateTime.october, 1); + final day = DateTime(2022, DateTime.october); final period = Period( start: day.date, end: DateTime(2022, 12, 31, 23, 59, 59, 999, 999), @@ -1342,11 +1342,11 @@ void main() { }); group('before', () { final period = Period( - start: DateTime(2022, DateTime.january, 1), + start: DateTime(2022), end: DateTime(2022, 3, 31, 23, 59, 59, 999, 999), ); final expected = Period( - start: DateTime(2021, DateTime.october, 1), + start: DateTime(2021, DateTime.october), end: DateTime(2021, 12, 31, 23, 59, 59, 999, 999), ); test('returns the previous trimester', () { @@ -1355,11 +1355,11 @@ void main() { }); group('after', () { final period = Period( - start: DateTime(2022, DateTime.january, 1), + start: DateTime(2022), end: DateTime(2022, 3, 31, 23, 59, 59, 999, 999), ); final expected = Period( - start: DateTime(2022, DateTime.april, 1), + start: DateTime(2022, DateTime.april), end: DateTime(2022, 6, 30, 23, 59, 59, 999, 999), ); test('returns the next trimester', () { @@ -1369,35 +1369,35 @@ void main() { group('fits generator', () { test('first trimester leap', () { final period = Period( - start: DateTime(2020, DateTime.january, 1), + start: DateTime(2020), end: DateTime(2020, 3, 31, 23, 59, 59, 999, 999), ); expect(trimesterGenerator.fitsGenerator(period), isTrue); }); test('first trimester non leap', () { final period = Period( - start: DateTime(2022, DateTime.january, 1), + start: DateTime(2022), end: DateTime(2022, 3, 31, 23, 59, 59, 999, 999), ); expect(trimesterGenerator.fitsGenerator(period), isTrue); }); test('second trimester', () { final period = Period( - start: DateTime(2022, DateTime.april, 1), + start: DateTime(2022, DateTime.april), end: DateTime(2022, 6, 30, 23, 59, 59, 999, 999), ); expect(trimesterGenerator.fitsGenerator(period), isTrue); }); test('third trimester', () { final period = Period( - start: DateTime(2022, DateTime.july, 1), + start: DateTime(2022, DateTime.july), end: DateTime(2022, 9, 30, 23, 59, 59, 999, 999), ); expect(trimesterGenerator.fitsGenerator(period), isTrue); }); test('fourth trimester', () { final period = Period( - start: DateTime(2022, DateTime.october, 1), + start: DateTime(2022, DateTime.october), end: DateTime(2022, 12, 31, 23, 59, 59, 999, 999), ); expect(trimesterGenerator.fitsGenerator(period), isTrue); @@ -1407,7 +1407,7 @@ void main() { group('SemesterPeriodGenerator', () { const semesterGenerator = SemesterGenerator(); group('First semester of the year', () { - final day = DateTime(2022, DateTime.january, 1); + final day = DateTime(2022); final period = Period( start: day.date, end: DateTime(2022, 6, 30, 23, 59, 59, 999, 999), @@ -1437,7 +1437,7 @@ void main() { }); }); group('Second semester of the year', () { - final day = DateTime(2022, DateTime.july, 1); + final day = DateTime(2022, DateTime.july); final period = Period( start: day.date, end: DateTime(2022, 12, 31, 23, 59, 59, 999, 999), @@ -1468,11 +1468,11 @@ void main() { }); group('before', () { final period = Period( - start: DateTime(2022, DateTime.july, 1), + start: DateTime(2022, DateTime.july), end: DateTime(2022, 12, 31, 23, 59, 59, 999, 999), ); final expected = Period( - start: DateTime(2022, DateTime.january, 1), + start: DateTime(2022), end: DateTime(2022, 6, 30, 23, 59, 59, 999, 999), ); test('returns the previous semester', () { @@ -1481,11 +1481,11 @@ void main() { }); group('after', () { final period = Period( - start: DateTime(2022, DateTime.january, 1), + start: DateTime(2022), end: DateTime(2022, 6, 30, 23, 59, 59, 999, 999), ); final expected = Period( - start: DateTime(2022, DateTime.july, 1), + start: DateTime(2022, DateTime.july), end: DateTime(2022, 12, 31, 23, 59, 59, 999, 999), ); test('returns the next semester', () { @@ -1495,14 +1495,14 @@ void main() { group('fits generator', () { test('first semester', () { final period = Period( - start: DateTime(2022, DateTime.january, 1), + start: DateTime(2022), end: DateTime(2022, 6, 30, 23, 59, 59, 999, 999), ); expect(semesterGenerator.fitsGenerator(period), isTrue); }); test('second semester', () { final period = Period( - start: DateTime(2022, DateTime.july, 1), + start: DateTime(2022, DateTime.july), end: DateTime(2022, 12, 31, 23, 59, 59, 999, 999), ); expect(semesterGenerator.fitsGenerator(period), isTrue); @@ -1512,7 +1512,7 @@ void main() { group('YearPeriodGenerator', () { const yearGenerator = YearGenerator(); group('Non leap year', () { - final day = DateTime(2022, DateTime.january, 1); + final day = DateTime(2022); final period = Period( start: day.date, end: DateTime(2022, 12, 31, 23, 59, 59, 999, 999), @@ -1542,7 +1542,7 @@ void main() { }); }); group('Leap year', () { - final day = DateTime(2020, DateTime.january, 1); + final day = DateTime(2020); final period = Period( start: day.date, end: DateTime(2020, 12, 31, 23, 59, 59, 999, 999), @@ -1573,11 +1573,11 @@ void main() { }); group('before', () { final period = Period( - start: DateTime(2022, DateTime.january, 1), + start: DateTime(2022), end: DateTime(2022, 12, 31, 23, 59, 59, 999, 999), ); final expected = Period( - start: DateTime(2021, DateTime.january, 1), + start: DateTime(2021), end: DateTime(2021, 12, 31, 23, 59, 59, 999, 999), ); test('returns the previous year', () { @@ -1586,11 +1586,11 @@ void main() { }); group('after', () { final period = Period( - start: DateTime(2021, DateTime.january, 1), + start: DateTime(2021), end: DateTime(2021, 12, 31, 23, 59, 59, 999, 999), ); final expected = Period( - start: DateTime(2022, DateTime.january, 1), + start: DateTime(2022), end: DateTime(2022, 12, 31, 23, 59, 59, 999, 999), ); test('returns the next year', () { @@ -1600,14 +1600,14 @@ void main() { group('fits generator', () { test('leap year', () { final period = Period( - start: DateTime(2020, DateTime.january, 1), + start: DateTime(2020), end: DateTime(2020, 12, 31, 23, 59, 59, 999, 999), ); expect(yearGenerator.fitsGenerator(period), isTrue); }); test('non leap year', () { final period = Period( - start: DateTime(2022, DateTime.january, 1), + start: DateTime(2022), end: DateTime(2022, 12, 31, 23, 59, 59, 999, 999), ); expect(yearGenerator.fitsGenerator(period), isTrue); diff --git a/test/period_test.dart b/test/period_test.dart index 9a56f2d..bbb2f5d 100644 --- a/test/period_test.dart +++ b/test/period_test.dart @@ -6,7 +6,7 @@ void main() { group('Period ->', () { group('Constructor ->', () { group('Default ->', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 2); test('Works if start is before end', () { expect(Period(start: start, end: end), isA()); @@ -14,7 +14,7 @@ void main() { test('Works if start is equal to end', () { expect(Period(start: start, end: start), isA()); }); - test('Doesn\'t work if end is before start', () { + test("Doesn't work if end is before start", () { expect( () => Period(start: end, end: start), throwsArgumentError, @@ -35,10 +35,10 @@ void main() { }); }); group('duration ->', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 2); final period = Period(start: start, end: end); - test('deve dar um dia + 1 microsecond', () { + test('should be 1 day + 1 microsecond', () { expect( period.duration, equals(const Duration(days: 1, microseconds: 1)), @@ -46,12 +46,12 @@ void main() { }); }); group('contains ->', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 2); final period = Period(start: start, end: end); - const microssecond = Duration(microseconds: 1); + const microsecond = Duration(microseconds: 1); test('before start', () { - expect(period.contains(start.subtract(microssecond)), isFalse); + expect(period.contains(start.subtract(microsecond)), isFalse); }); test('start', () { expect(period.contains(start), isTrue); @@ -69,11 +69,11 @@ void main() { expect(period.contains(end.toUtc()), isTrue); }); test('after end', () { - expect(period.contains(end.add(microssecond)), isFalse); + expect(period.contains(end.add(microsecond)), isFalse); }); }); group('overlapsWith ->', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 2); final start2 = DateTime(2022, DateTime.january, 1, 12); final end2 = DateTime(2022, DateTime.january, 3); @@ -84,7 +84,7 @@ void main() { }); }); group('doesNotOverlapWith ->', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 2); final start2 = DateTime(2022, DateTime.january, 2, 12); final end2 = DateTime(2022, DateTime.january, 3); @@ -95,7 +95,7 @@ void main() { }); }); group('getIntersection', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 2); final start2 = DateTime(2022, DateTime.january, 1, 12); final end2 = DateTime(2022, DateTime.january, 3); @@ -107,7 +107,7 @@ void main() { }); }); group('mergeWith', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 2); final start2 = DateTime(2022, DateTime.january, 1, 12); final end2 = DateTime(2022, DateTime.january, 3); @@ -119,7 +119,7 @@ void main() { }); }); group('differenceBetween', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 2); final start2 = DateTime(2022, DateTime.january, 1, 12); final end2 = DateTime(2022, DateTime.january, 3); @@ -135,7 +135,7 @@ void main() { }); }); group('sort', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 2); final start2 = DateTime(2022, DateTime.january, 1, 12); final end2 = DateTime(2022, DateTime.january, 3); @@ -155,7 +155,7 @@ void main() { }); }); group('mergeOverlappingPeriods', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 2); final start2 = DateTime(2022, DateTime.january, 1, 12); final end2 = DateTime(2022, DateTime.january, 3); @@ -174,7 +174,7 @@ void main() { }); group('intersections', () { test('[day 1 (12h) - day 2, day 3 (12h) - day 4]', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 2); final start2 = DateTime(2022, DateTime.january, 1, 12); final end2 = DateTime(2022, DateTime.january, 3); @@ -190,6 +190,7 @@ void main() { ); }); test( + // ignore: missing_whitespace_between_adjacent_strings, it is a list '[Period(start: DateTime(2023, 03, 16), end: DateTime(2023, 03, 17)),' 'Period(start: DateTime(2023, 03, 18), end: DateTime(2023, 03, 19))]', () { @@ -205,10 +206,11 @@ void main() { expect(Period.intersections(list), orderedEquals(expected)); }); test( + // ignore: missing_whitespace_between_adjacent_strings, it is a list '[Period(start: DateTime(2023, 03, 16), end: DateTime(2023, 03, 17)),' 'Period(' ' start: DateTime(2023, 03, 18, 12), ' - ' end: DateTime(2023, 03, 18, 13),' + ' end: DateTime(2023, 03, 18, 13), ' ')]', () { final list = [ Period(start: DateTime(2023, 03, 15), end: DateTime(2023, 03, 17)), @@ -234,14 +236,14 @@ void main() { '[' 'Period(2023-03-15 00:00:00.000, 2023-03-17 00:00:00.000), ' 'Period(2023-03-16 00:00:00.000, 2023-03-19 00:00:00.000), ' - 'Period(2023-03-18 00:00:00.000, 2023-03-20 00:00:00.000)' + 'Period(2023-03-18 00:00:00.000, 2023-03-20 00:00:00.000) ' ']', () { final period1 = Period( - start: DateTime(2023, 4, 1), + start: DateTime(2023, 4), end: DateTime(2023, 4, 15), ); final period2 = Period( - start: DateTime(2023, 4, 1), + start: DateTime(2023, 4), end: DateTime(2023, 4, 30), ); final period3 = Period( @@ -288,13 +290,12 @@ void main() { period4, period1, period3, - ]; - list.sort(); + ]..sort(); expect(list, orderedEquals(expected)); }); }); group('subtract', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 2); final start2 = DateTime(2022, DateTime.january, 1, 12); final end2 = DateTime(2022, DateTime.january, 3); @@ -317,7 +318,7 @@ void main() { }); }); group('splitAt', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 2); final split = DateTime(2022, DateTime.january, 1, 12); final base = Period(start: start, end: end); @@ -342,7 +343,7 @@ void main() { }); }); group('splitIn', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 2); final split = DateTime(2022, DateTime.january, 1, 12); final base = Period(start: start, end: end); @@ -404,17 +405,17 @@ void main() { ); }); test( - '[Period:Period(2020-01-01 00:00:00.000, 2020-01-10 08:00:00.000),' - 'Period:Period(2020-01-11 08:00:00.000, 2020-01-20 16:00:00.000),' + '[Period:Period(2020-01-01 00:00:00.000, 2020-01-10 08:00:00.000), ' + 'Period:Period(2020-01-11 08:00:00.000, 2020-01-20 16:00:00.000), ' 'Period:Period(2020-01-21 16:00:00.000, 2020-01-31 00:00:00.000)]', () { final base = Period( - start: DateTime(2020, 1, 1), + start: DateTime(2020), end: DateTime(2020, 1, 31), ); final expected = [ Period( - start: DateTime(2020, 1, 1), + start: DateTime(2020), end: DateTime(2020, 1, 10, 8), ), Period( @@ -427,7 +428,7 @@ void main() { ), ]; expect( - base.splitIn(3, periodBetween: Duration(days: 1)), + base.splitIn(3, periodBetween: const Duration(days: 1)), orderedEquals(expected), ); for (int i = 1; i < (expected.length - 1); i++) { @@ -436,21 +437,21 @@ void main() { }); }); test('isNotEmpty', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 2); final period = Period(start: start, end: end); expect(period.isNotEmpty, isTrue); expect(period.isEmpty, isFalse); }); test('isEmpty', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final period = Period(start: start, end: start); expect(period.isEmpty, isTrue); expect(period.isNotEmpty, isFalse); }); test('equals', () { const dayGenerator = DayGenerator(); - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 1, 23, 59, 59, 999, 999); final period = Period(start: start, end: end); final period2 = Period(start: start, end: end); @@ -462,7 +463,7 @@ void main() { expect(period2 == period3, isTrue); }); test('shift', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 1, 23, 59, 59, 999, 999); final period = Period(start: start, end: end); final period2 = period.shift(const Duration(days: 1)); @@ -473,7 +474,7 @@ void main() { expect(period3.end, end.subtract(const Duration(days: 1))); }); group('containsFully', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 1, 23, 59, 59, 999, 999); final period = Period(start: start, end: end); test('same', () { @@ -513,7 +514,7 @@ void main() { ); expect(period.containsFully(period2), isFalse); }); - test('Non overlaping', () { + test('Non overlapping', () { final period2 = Period( start: end.add(const Duration(days: 1)), end: end.add(const Duration(days: 2)), @@ -522,7 +523,7 @@ void main() { }); }); group('containedFullyBy', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 1, 23, 59, 59, 999, 999); final period = Period(start: start, end: end); test('same', () { @@ -562,7 +563,7 @@ void main() { ); expect(period2.containedFullyBy(period), isFalse); }); - test('Non overlaping', () { + test('Non overlapping', () { final period2 = Period( start: end.add(const Duration(days: 1)), end: end.add(const Duration(days: 2)), @@ -571,7 +572,7 @@ void main() { }); }); group('containsPartially', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 1, 23, 59, 59, 999, 999); final period = Period(start: start, end: end); test('same', () { @@ -611,7 +612,7 @@ void main() { ); expect(period.containsPartially(period2), isTrue); }); - test('Non overlaping', () { + test('Non overlapping', () { final period2 = Period( start: end.add(const Duration(days: 1)), end: end.add(const Duration(days: 2)), @@ -620,7 +621,7 @@ void main() { }); }); group('containedPartiallyBy', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 1, 23, 59, 59, 999, 999); final period = Period(start: start, end: end); test('same', () { @@ -660,7 +661,7 @@ void main() { ); expect(period2.containedPartiallyBy(period), isTrue); }); - test('Non overlaping', () { + test('Non overlapping', () { final period2 = Period( start: end.add(const Duration(days: 1)), end: end.add(const Duration(days: 2)), @@ -669,7 +670,7 @@ void main() { }); }); group('occursBefore', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 1, 23, 59, 59, 999, 999); final period = Period(start: start, end: end); test('same', () { @@ -699,7 +700,7 @@ void main() { }); }); group('occursAfter', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 1, 23, 59, 59, 999, 999); final period = Period(start: start, end: end); test('same', () { @@ -728,7 +729,7 @@ void main() { }); }); group('copyWith', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 1, 23, 59, 59, 999, 999); final period = Period(start: start, end: end); test('start', () { @@ -762,7 +763,7 @@ void main() { }); }); group('endsBefore', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 1, 23, 59, 59, 999, 999); final period = Period(start: start, end: end); test('same as end', () { @@ -776,7 +777,7 @@ void main() { }); }); group('endsAfter', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 1, 23, 59, 59, 999, 999); final period = Period(start: start, end: end); test('same as end', () { @@ -790,7 +791,7 @@ void main() { }); }); group('startsAfter', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 1, 23, 59, 59, 999, 999); final period = Period(start: start, end: end); test('same as start', () { @@ -807,7 +808,7 @@ void main() { }); }); group('startsBefore', () { - final start = DateTime(2022, DateTime.january, 1); + final start = DateTime(2022); final end = DateTime(2022, DateTime.january, 1, 23, 59, 59, 999, 999); final period = Period(start: start, end: end); test('same as start', () { @@ -825,7 +826,7 @@ void main() { }); group('getNext', () { const dayGenerator = DayGenerator(); - final first = DateTime(2022, DateTime.january, 1); + final first = DateTime(2022); final period = dayGenerator.of(first); final second = DateTime(2022, DateTime.january, 2); final period2 = dayGenerator.of(second); @@ -835,7 +836,7 @@ void main() { }); group('getPrevious', () { const dayGenerator = DayGenerator(); - final first = DateTime(2022, DateTime.january, 1); + final first = DateTime(2022); final period = dayGenerator.of(first); final second = DateTime(2022, DateTime.january, 2); final period2 = dayGenerator.of(second); @@ -847,7 +848,7 @@ void main() { test('Seconds', () { const generator = MinuteGenerator(); const oneSecond = Duration(seconds: 1); - final minute = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final minute = generator.of(DateTime(2020)); final seconds = minute.seconds; expect(seconds, isA>()); expect(seconds, hasLength(60)); @@ -856,7 +857,7 @@ void main() { seconds.first, equals( Period( - start: DateTime(2020, 1, 1, 0, 0, 0), + start: DateTime(2020), end: DateTime(2020, 1, 1, 0, 0, 0, 999, 999), ), ), @@ -876,7 +877,7 @@ void main() { test('Minutes', () { const generator = HourGenerator(); const oneMinute = Duration(minutes: 1); - final hour = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final hour = generator.of(DateTime(2020)); final minutes = hour.minutes; expect(minutes, isA>()); expect(minutes, hasLength(60)); @@ -885,7 +886,7 @@ void main() { minutes.first, equals( Period( - start: DateTime(2020, 1, 1, 0, 0, 0), + start: DateTime(2020), end: DateTime(2020, 1, 1, 0, 0, 59, 999, 999), ), ), @@ -894,7 +895,7 @@ void main() { minutes.last, equals( Period( - start: DateTime(2020, 1, 1, 0, 59, 0), + start: DateTime(2020, 1, 1, 0, 59), end: DateTime(2020, 1, 1, 0, 59, 59, 999, 999), ), ), @@ -905,7 +906,7 @@ void main() { test('Hours', () { const generator = DayGenerator(); const oneHour = Duration(hours: 1); - final day = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final day = generator.of(DateTime(2020)); final hours = day.hours; expect(hours, isA>()); expect(hours, hasLength(24)); @@ -914,7 +915,7 @@ void main() { hours.first, equals( Period( - start: DateTime(2020, 1, 1, 0, 0, 0), + start: DateTime(2020), end: DateTime(2020, 1, 1, 0, 59, 59, 999, 999), ), ), @@ -925,7 +926,7 @@ void main() { test('Days', () { const generator = WeekGenerator(); const dayGenerator = DayGenerator(); - final week = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final week = generator.of(DateTime(2020)); final days = week.days; expect(days, isA>()); expect(days, hasLength(7)); @@ -934,7 +935,7 @@ void main() { days.first, equals( Period( - start: DateTime(2019, 12, 30, 0, 0, 0), + start: DateTime(2019, 12, 30), end: DateTime(2019, 12, 30, 23, 59, 59, 999, 999), ), ), @@ -945,7 +946,7 @@ void main() { test('Days', () { const generator = FortnightGenerator(); const dayGenerator = DayGenerator(); - final fortnight = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final fortnight = generator.of(DateTime(2020)); final days = fortnight.days; expect(days, isA>()); expect(days, hasLength(15)); @@ -954,7 +955,7 @@ void main() { days.first, equals( Period( - start: DateTime(2020, 1, 1, 0, 0, 0), + start: DateTime(2020), end: DateTime(2020, 1, 1, 23, 59, 59, 999, 999), ), ), @@ -963,7 +964,7 @@ void main() { days.last, equals( Period( - start: DateTime(2020, 1, 15, 0, 0, 0), + start: DateTime(2020, 1, 15), end: DateTime(2020, 1, 15, 23, 59, 59, 999, 999), ), ), @@ -974,7 +975,7 @@ void main() { test('Days', () { const generator = MonthGenerator(); const dayGenerator = DayGenerator(); - final month = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final month = generator.of(DateTime(2020)); final days = month.days; expect(days, isA>()); expect(days, hasLength(31)); @@ -983,7 +984,7 @@ void main() { days.first, equals( Period( - start: DateTime(2020, 1, 1, 0, 0, 0), + start: DateTime(2020), end: DateTime(2020, 1, 1, 23, 59, 59, 999, 999), ), ), @@ -992,7 +993,7 @@ void main() { days.last, equals( Period( - start: DateTime(2020, 1, 31, 0, 0, 0), + start: DateTime(2020, 1, 31), end: DateTime(2020, 1, 31, 23, 59, 59, 999, 999), ), ), @@ -1003,7 +1004,7 @@ void main() { test('Months', () { const generator = TrimesterGenerator(); const monthGenerator = MonthGenerator(); - final trimester = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final trimester = generator.of(DateTime(2020)); final months = trimester.months; expect(months, isA>()); expect(months, hasLength(3)); @@ -1015,7 +1016,7 @@ void main() { months.first, equals( Period( - start: DateTime(2020, 1, 1, 0, 0, 0), + start: DateTime(2020), end: DateTime(2020, 1, 31, 23, 59, 59, 999, 999), ), ), @@ -1024,7 +1025,7 @@ void main() { months.last, equals( Period( - start: DateTime(2020, 3, 1, 0, 0, 0), + start: DateTime(2020, 3), end: DateTime(2020, 3, 31, 23, 59, 59, 999, 999), ), ), @@ -1035,7 +1036,7 @@ void main() { test('Months', () { const generator = SemesterGenerator(); const monthGenerator = MonthGenerator(); - final semester = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final semester = generator.of(DateTime(2020)); final months = semester.months; expect(months, isA>()); expect(months, hasLength(6)); @@ -1047,7 +1048,7 @@ void main() { months.first, equals( Period( - start: DateTime(2020, 1, 1, 0, 0, 0), + start: DateTime(2020), end: DateTime(2020, 1, 31, 23, 59, 59, 999, 999), ), ), @@ -1056,7 +1057,7 @@ void main() { months.last, equals( Period( - start: DateTime(2020, 6, 1, 0, 0, 0), + start: DateTime(2020, 6), end: DateTime(2020, 6, 30, 23, 59, 59, 999, 999), ), ), @@ -1066,7 +1067,7 @@ void main() { test('Months', () { const generator = YearGenerator(); const monthGenerator = MonthGenerator(); - final year = generator.of(DateTime(2020, 1, 1, 0, 0, 0)); + final year = generator.of(DateTime(2020)); final months = year.months; expect(months, isA>()); expect(months, hasLength(12)); @@ -1078,7 +1079,7 @@ void main() { months.first, equals( Period( - start: DateTime(2020, 1, 1, 0, 0, 0), + start: DateTime(2020), end: DateTime(2020, 1, 31, 23, 59, 59, 999, 999), ), ), @@ -1087,7 +1088,7 @@ void main() { months.last, equals( Period( - start: DateTime(2020, 12, 1, 0, 0, 0), + start: DateTime(2020, 12), end: DateTime(2020, 12, 31, 23, 59, 59, 999, 999), ), ), From fbe6a3f161df4c574a654bfb6b6c9cda438dcd97 Mon Sep 17 00:00:00 2001 From: FMorschel <52160996+FMorschel@users.noreply.github.com> Date: Thu, 7 Dec 2023 02:26:41 -0300 Subject: [PATCH 02/16] Create build.yml --- .github/workflows/build.yml | 68 +++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..43a310f --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,68 @@ +name: Build + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: dart-lang/setup-dart@v1 + with: + sdk: main + + - name: Install dependencies + run: dart pub get + + - name: Check format + run: dart format --output=none --set-exit-if-changed -l 80 lib + + - name: Analyze + run: dart analyze lib + + - name: Run tests + run: dart test --coverage coverage --reporter=github + + - name: Coverage + run: dart run coverage:format_coverage -l -i ./coverage/test/due_date_test.dart.vm.json -o ./coverage/lcov.info + + - name: Upload coverage to codecov + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: true # optional (default = false) + verbose: true # optional (default = false) + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + + update-docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: dart-lang/setup-dart@v1 + with: + sdk: main + - name: Generate docs + run: dart doc + - name: Checkout gh-pages branch + run: | + git fetch + git checkout gh-pages + - name: Clear base folder + run: | + rm -rf * + - name: Copy docs to base folder + run: | + cp -r ../doc/api/* . + - name: Commit and push + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git add . + git commit -m "Update documentation" -a + git push \ No newline at end of file From bca73ae81408df38a6c0bb8f1c9bc8e22e07b4a7 Mon Sep 17 00:00:00 2001 From: FMorschel <52160996+FMorschel@users.noreply.github.com> Date: Thu, 7 Dec 2023 02:27:38 -0300 Subject: [PATCH 03/16] Update README.md --- README.md | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 85a53fa..730b101 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,17 @@ # DueDate +[![pub package](https://img.shields.io/pub/v/due_date.svg)](https://pub.dev/packages/due_date) + +[![likes](https://badges.bar/due_date/likes)](https://pub.dev/packages/due_date/score) + +[![pub points](https://badges.bar/due_date/pub%20points)](https://pub.dev/packages/due_date/score) + +[![popularity](https://badges.bar/due_date/popularity)](https://pub.dev/packages/due_date/score) + +[![Build](https://github.com/fmorschel/due_date/actions/workflows/build.yml/badge.svg)](https://github.com/fmorschel/due_date/actions/workflows/build.yml) + +[![codecov](https://codecov.io/gh/fmorschel/due_date/branch/main/graph/badge.svg)](https://codecov.io/gh/fmorschel/due_date) + A package for working with repeating `DateTime` patterns. Ever wanted to create a new `DateTime` with, let's say, the same day in month? But the day is 31 and next month only has 30, so you go to 30 and the next day is lost because then you have no variable to save the original's month day? With `DueDateTime` this managing is done for you without any headaches. @@ -90,6 +102,33 @@ See the API docs [here](https://fmorschel.github.io/due_date/). Find more information at . -Contibute to the package by creating a PR at . +Contribute to the package by creating a PR at . File issues at . + +Discuss related topics at + +## Alternatives/Inspiration + +- [pub.dev -> time](https://pub.dev/packages/time) + - Made me start thinking about this package and how I could improve it with issues and discussions on the GitHub repo. + +- [DateUtils -> Flutter](https://api.flutter.dev/flutter/material/DateUtils-class.html) + - Inspired me to create the `Period` class and its methods. As well as some `Every` classes. + +## What makes this different + +This package is focused on working with `DateTime` objects and their patterns. It is not a calendar package, but it can be used to create one. +It is also not a package to work with timezones. It is focused on the `DateTime` object itself. It does not have any timezone related methods. For that, you may want to check out the [timezone](https://pub.dev/packages/timezone) package. + +This is not a package to work with `Duration` objects. It is focused on `DateTime` objects and their patterns. For that, you may want to check out the [time](https://pub.dev/packages/time) package. + +This package is not a package to work with `DateTime` objects and their formatting. It is focused on `DateTime` objects and their patterns. For that, you may want to check out the [intl](https://pub.dev/packages/intl) package. + +This package is not intended to be a replacement for the `DateTime` class. It is intended to be a complement to it. + +The [time](https://pub.dev/packages/time) package is a great package to work with `Duration` and `DateTime` objects. It uses extension methods to add functionality to the `DateTime` class. This package is not intended to be a replacement for the `time` package. It is intended to be a complement to it. + +## License + +This package is licensed under the MIT license. See the [LICENSE]() file for details. From cf7312b234210605586acbc2da92398701ca306e Mon Sep 17 00:00:00 2001 From: FMorschel <52160996+FMorschel@users.noreply.github.com> Date: Thu, 7 Dec 2023 02:44:22 -0300 Subject: [PATCH 04/16] Added EveryModifiers --- lib/period.dart | 8 +- lib/src/every.dart | 1 + lib/src/every_modifier.dart | 483 ++++++++++++++++++++++++++ test/constants_test.dart | 238 +++++++++++++ test/every_modifier_test.dart | 620 ++++++++++++++++++++++++++++++++++ 5 files changed, 1349 insertions(+), 1 deletion(-) create mode 100644 lib/src/every_modifier.dart create mode 100644 test/constants_test.dart create mode 100644 test/every_modifier_test.dart diff --git a/lib/period.dart b/lib/period.dart index 7fc6bf7..1cbd130 100644 --- a/lib/period.dart +++ b/lib/period.dart @@ -16,7 +16,13 @@ /// [SemesterGenerator] and [YearGenerator]. library period; -export 'src/enums.dart' show Weekday, Month, Week, PeriodGenerator; +import 'src/enums.dart' show PeriodGenerator; +import 'src/period.dart'; +import 'src/period_generator.dart'; + +export 'src/constants.dart'; +export 'src/enums.dart' show Month, PeriodGenerator, Week, Weekday; +export 'src/every_modifier.dart'; export 'src/extensions.dart' show EndOfDay; export 'src/period.dart'; export 'src/period_generator.dart'; diff --git a/lib/src/every.dart b/lib/src/every.dart index 4b656c2..977d200 100644 --- a/lib/src/every.dart +++ b/lib/src/every.dart @@ -3,6 +3,7 @@ import 'package:time/time.dart'; import 'constants.dart'; import 'date_validator.dart'; import 'enums.dart'; +import 'every_modifier.dart'; import 'extensions.dart'; /// Abstract class that, when extended, processes [DateTime] with custom logic. diff --git a/lib/src/every_modifier.dart b/lib/src/every_modifier.dart new file mode 100644 index 0000000..d84bf4e --- /dev/null +++ b/lib/src/every_modifier.dart @@ -0,0 +1,483 @@ +import 'package:equatable/equatable.dart'; + +import '../due_date.dart'; +import 'constants.dart'; + +/// An enum that represents the direction of the process inside [EveryModifier]. +/// Used on [EveryModifier.processDate]. +enum DateDirection { + /// An enum that represents the start direction of the process inside + /// [EveryModifier]. + start, + + /// An enum that represents the next direction of the process inside + /// [EveryModifier]. + next, + + /// An enum that represents the previous direction of the process inside + /// [EveryModifier]. + previous; + + /// Returns true if the [DateDirection] is [DateDirection.start]. + bool get isStart => this == DateDirection.start; + + /// Returns true if the [DateDirection] is [DateDirection.next]. + bool get isNext => this == DateDirection.next; + + /// Returns true if the [DateDirection] is [DateDirection.previous]. + bool get isPrevious => this == DateDirection.previous; +} + +/// {@template everyModifier} +/// Abstract class that, when extended, processes [DateTime] with custom logic. +/// {@endtemplate} +abstract class EveryModifier implements Every { + /// {@macro everyModifier} + const EveryModifier({ + required this.every, + }); + + /// The base generator for this [EveryModifier]. + final T every; + + /// A method that processes [date] with custom logic. + DateTime processDate(DateTime date, DateDirection direction); +} + +/// {@template everyModifierMixin} +/// Mixin that, when used, passes the calls the specific method on the +/// underlying [every]. +/// +/// If the [every] is a [LimitedEvery], the [LimitedEveryModifierMixin] should +/// be used instead. +/// {@endtemplate} +mixin EveryModifierMixin on EveryModifier { + @override + DateTime startDate(DateTime date) { + return processDate( + LimitedOrEveryHandler.startDate(every, date, limit: null), + DateDirection.start, + ); + } + + @override + DateTime next(DateTime date) { + return processDate( + LimitedOrEveryHandler.next(every, date, limit: null), + DateDirection.next, + ); + } + + @override + DateTime previous(DateTime date) { + return processDate( + LimitedOrEveryHandler.previous(every, date, limit: null), + DateDirection.previous, + ); + } +} + +/// {@macro everyModifierMixin} +/// +/// Also makes the using class a [LimitedEvery]. +/// +/// Should **always** be used when the [every] is a [LimitedEvery]. +mixin LimitedEveryModifierMixin on EveryModifier + implements LimitedEvery { + @override + DateTime startDate(DateTime date, {DateTime? limit}) { + return processDate( + LimitedOrEveryHandler.startDate(every, date, limit: limit), + DateDirection.start, + limit: limit, + ); + } + + @override + DateTime next(DateTime date, {DateTime? limit}) { + return processDate( + LimitedOrEveryHandler.next(every, date, limit: limit), + DateDirection.next, + limit: limit, + ); + } + + @override + DateTime previous(DateTime date, {DateTime? limit}) { + return processDate( + LimitedOrEveryHandler.previous(every, date, limit: limit), + DateDirection.previous, + limit: limit, + ); + } + + @override + DateTime processDate( + DateTime date, + DateDirection direction, { + DateTime? limit, + }); +} + +/// {@template everyModifierInvalidator} +/// Class that wraps an [every] generator and adds an [invalidator] that will +/// be used to invalidate the generated dates. +/// {@endtemplate} +abstract class EveryModifierInvalidator + extends EveryModifier with EveryModifierMixin { + /// {@macro everyModifierInvalidator} + const EveryModifierInvalidator({ + required super.every, + required this.invalidator, + }); + + /// The [DateValidator] that will be used to invalidate the generated dates. + final DateValidator invalidator; +} + +/// {@template everySkipInvalidModifier} +/// Class that wraps an [Every] generator and adds a [DateValidator] that will +/// be used to invalidate the generated dates. +/// +/// It will return the next [DateTime] that matches the [every] pattern and is +/// not valid for the [invalidator]. +/// {@endtemplate} +class EverySkipInvalidModifier + extends EveryModifierInvalidator + with EquatableMixin, DateValidatorMixin, LimitedEveryModifierMixin + implements EveryDateValidator { + /// {@macro everySkipInvalidModifier} + const EverySkipInvalidModifier({ + required super.every, + required super.invalidator, + }); + + /// Returns the next [DateTime] that matches the [every] pattern and is not + /// valid for the [invalidator]. + @override + DateTime startDate(DateTime date, {DateTime? limit}) => + super.startDate(date, limit: limit); + + /// Returns the next instance of the given [date] considering the [every] + /// base process. If the [date] is valid for the [invalidator], a new + /// [DateTime] will be returned. + @override + DateTime next(DateTime date, {DateTime? limit}) => + super.next(date, limit: limit); + + /// Returns the previous instance of the given [date] considering the [every] + /// base process. If the [date] is valid for the [invalidator], a new + /// [DateTime] will be returned. + @override + DateTime previous(DateTime date, {DateTime? limit}) => + super.previous(date, limit: limit); + + /// Returns `true` if the [date] is valid for the [every] (if it is a + /// [DateValidator], like an [EveryDateValidator], for example) and not valid + /// for the [invalidator]. + @override + bool valid(DateTime date) { + if (every is DateValidator) { + final invalid = (every as DateValidator).invalid(date); + if (invalid) return false; + } + return invalidator.invalid(date); + } + + /// Returns `true` if the [date] is invalid for the [every] (if it is a + /// [DateValidator], like an [EveryDateValidator], for example) and valid for + /// the [invalidator]. + /// + /// This is the opposite of [valid]. + /// Implementations that return true for invalid should also return false for + /// valid. + /// + /// Usually, this will be implemented as `!valid(date)` by the [Every] classes + /// that implement [DateValidatorMixin]. However, if there is a simpler way to + /// check for invalid dates, it can be implemented here. + @override + bool invalid(DateTime date) { + if (every is DateValidator) { + final invalid = (every as DateValidator).invalid(date); + if (invalid) return true; + } + return invalidator.valid(date); + } + + @override + DateTime processDate( + DateTime date, + DateDirection direction, { + DateTime? limit, + }) { + if ((limit != null) && + (direction.isPrevious ? date.isBefore(limit) : date.isAfter(limit))) { + throw DateTimeLimitReachedException(date: date, limit: limit); + } + if (invalidator.invalid(date)) return date; + if (!direction.isPrevious) return next(date, limit: limit); + return previous(date, limit: limit); + } + + @override + // ignore: hash_and_equals, already implemented by EquatableMixin + bool operator ==(Object other) { + return (super == other) || + ((other is EverySkipInvalidModifier) && + (other.every == every) && + (other.invalidator == invalidator)); + } + + @override + List get props => [every, invalidator]; +} + +/// {@template everyOverrideWrapper} +/// Class that wraps an [Every] generator and adds a [DateValidator] that will +/// be used to invalidate the generated dates and an [overrider] that will be +/// used instead. +/// +/// When the [invalidator] invalidates the generated dates, the [overrider] +/// will be used instead. +/// {@endtemplate} +class EveryOverrideWrapper extends EveryModifierInvalidator + with EquatableMixin, LimitedEveryModifierMixin { + /// {@macro everyOverrideWrapper} + const EveryOverrideWrapper({ + required super.every, + required super.invalidator, + required this.overrider, + }); + + /// The every used instead of the original when the generated date is valid + /// for the [invalidator]. + final T overrider; + + /// Generates the start date of the [every] base process. + /// If the [date] is valid for the [invalidator], the [overrider] startDate + /// will be used instead of the [every]. + @override + DateTime startDate(DateTime date, {DateTime? limit}) { + final validForEveryValidator = + (every is DateValidator) && ((every as DateValidator).valid(date)); + if (!validForEveryValidator && (every.startDate(date) != date)) { + DateTime previous = LimitedOrEveryHandler.previous( + overrider, + date, + limit: limit, + ); + + /// - Iterate over the next possible dates after [previous] with the + /// [every] generator using startDate on the first iteration and next on + /// every following. + /// If the date generated for the iteration is already bigger than the + /// given [date], super.startDate will be used. + /// If the date is valid for the [invalidator], the [overrider] startDate + /// will be used. + /// If that date is then the exact given [date], it will be returned. + /// If that date is before the given [date], a new iteration will be + /// started. + previous = every.startDate(previous); + if (previous.isAfter(date)) { + return super.startDate(date, limit: limit); + } else if (previous.isAtSameMomentAs(date)) { + if (invalidator.invalid(previous)) return date; + } + while (previous.isBefore(date)) { + if (invalidator.valid(previous)) { + previous = overrider.startDate(previous); + } + if (previous.isAfter(date)) { + return super.startDate(date, limit: limit); + } else if (previous.isAtSameMomentAs(date)) { + if (invalidator.invalid(previous)) return date; + } + previous = every.next(previous); + } + if (previous.isAfter(date)) { + return super.startDate(date, limit: limit); + } else if (previous.isAtSameMomentAs(date)) { + if (invalidator.invalid(previous)) return date; + } + } + return super.startDate(date, limit: limit); + } + + /// Generates the next instance of the given [date] considering the [every] + /// base process. + /// If the [date] is valid for the [invalidator], the [overrider] next will + /// be used instead of the [every]. + @override + DateTime next(DateTime date, {DateTime? limit}) => + super.next(date, limit: limit); + + /// Generates the previous instance of the given [date] considering the + /// [every] base process. + /// If the [date] is valid for the [invalidator], the [overrider] previous + /// will be used instead of the [every]. + @override + DateTime previous(DateTime date, {DateTime? limit}) => + super.previous(date, limit: limit); + + /// When the [date] is valid for the [invalidator], the [overrider] will be + /// used instead of [every]. + /// + /// If the [date] is invalid for the [invalidator], [date] will be returned. + @override + DateTime processDate( + DateTime date, + DateDirection direction, { + DateTime? limit, + }) { + if ((limit != null) && + (direction.isPrevious ? date.isBefore(limit) : date.isAfter(limit))) { + throw DateTimeLimitReachedException(date: date, limit: limit); + } + if (invalidator.invalid(date)) return date; + if (!direction.isPrevious) { + return processDate( + LimitedOrEveryHandler.next(overrider, date, limit: limit), + direction, + limit: limit, + ); + } + return processDate( + LimitedOrEveryHandler.previous(overrider, date, limit: limit), + direction, + limit: limit, + ); + } + + @override + // ignore: hash_and_equals, already implemented by EquatableMixin + bool operator ==(Object other) { + return (super == other) || + ((other is EveryOverrideWrapper) && + (other.every == every) && + (other.invalidator == invalidator) && + (other.overrider == overrider)); + } + + @override + List get props => [every, invalidator, overrider]; +} + +/// {@template everySkipCountWrapper} +/// Class that wraps an [Every] generator and skips [count] times from the +/// [Every] base process. +/// {@endtemplate} +class EverySkipCountWrapper extends EveryModifier + with EquatableMixin, LimitedEveryModifierMixin { + /// {@macro everySkipCountWrapper} + const EverySkipCountWrapper({ + required super.every, + required this.count, + }) : assert(count >= 0, 'Count must be greater than or equal to 0'); + + /// The number of times to skip. + final int count; + + /// Generates the start date of the [every] base process. + /// It will skip [currentCount] times from the [date] using the + /// [EverySkipCountWrapper.next] process. + /// + /// {@template currentCount} + /// If [currentCount] is `null`, it will be set to [count]. + /// {@endtemplate} + @override + DateTime startDate(DateTime date, {DateTime? limit, int? currentCount}) { + assert( + currentCount == null || currentCount >= 0, + 'currentCount must be greater than or equal to 0', + ); + final validForEveryValidator = + (every is DateValidator) && ((every as DateValidator).valid(date)); + if (validForEveryValidator || + LimitedOrEveryHandler.startDate(every, date, limit: limit) == date) { + return date; + } + return processDate( + LimitedOrEveryHandler.next(every, date, limit: limit), + DateDirection.next, + limit: limit, + currentCount: currentCount ?? count, + ); + } + + /// Generates the next of the [every] base process. + /// It will skip [currentCount] times from the [date] using the + /// [EverySkipCountWrapper.next] process. + /// + /// {@macro currentCount} + @override + DateTime next(DateTime date, {DateTime? limit, int? currentCount}) { + assert( + currentCount == null || currentCount >= 0, + 'currentCount must be greater than or equal to 0', + ); + return processDate( + LimitedOrEveryHandler.next(every, date, limit: limit), + DateDirection.next, + limit: limit, + currentCount: currentCount ?? count, + ); + } + + /// Generates the previous of the [every] base process. + /// It will skip [currentCount] times from the [date] using the + /// [EverySkipCountWrapper.previous] process. + /// + /// {@macro currentCount} + @override + DateTime previous(DateTime date, {DateTime? limit, int? currentCount}) { + assert( + currentCount == null || currentCount >= 0, + 'currentCount must be greater than or equal to 0', + ); + return processDate( + LimitedOrEveryHandler.previous(every, date, limit: limit), + DateDirection.previous, + limit: limit, + currentCount: currentCount ?? count, + ); + } + + /// Continues iterating the [every] base process. + /// It will skip [currentCount] times from the [date]. + /// + /// {@macro currentCount} + @override + DateTime processDate( + DateTime date, + DateDirection direction, { + DateTime? limit, + int? currentCount, + }) { + assert( + (currentCount == null) || (currentCount >= 0), + 'currentCount must be greater than or equal to 0', + ); + if ((limit != null) && + (direction.isPrevious ? date.isBefore(limit) : date.isAfter(limit))) { + throw DateTimeLimitReachedException(date: date, limit: limit); + } + currentCount ??= count; + if (currentCount <= 0) return date; + if (!direction.isPrevious) { + return next(date, limit: limit, currentCount: currentCount - 1); + } + return previous(date, limit: limit, currentCount: currentCount - 1); + } + + @override + // ignore: hash_and_equals, already implemented by EquatableMixin + bool operator ==(Object other) { + return (super == other) || + ((other is EverySkipCountWrapper) && + (other.every == every) && + (other.count == count)); + } + + @override + List get props => [every, count]; +} diff --git a/test/constants_test.dart b/test/constants_test.dart new file mode 100644 index 0000000..5cd4e66 --- /dev/null +++ b/test/constants_test.dart @@ -0,0 +1,238 @@ +import 'package:due_date/due_date.dart'; +import 'package:due_date/period.dart'; +import 'package:test/test.dart'; + +void main() { + group('LimitedOrEveryHandler', () { + final every = Weekday.monday.every; + final limited = EverySkipInvalidModifier( + every: every, + invalidator: const DateValidatorWeekdayCountInMonth( + week: Week.first, + day: Weekday.monday, + ), + ); + + group('startDate for Every', () { + final date = DateTime(2023, 12, 3); + final expectedDate = DateTime(2023, 12, 4); + + test('when limit is null', () { + final result = + LimitedOrEveryHandler.startDate(every, date, limit: null); + + expect(result, equals(expectedDate)); + }); + test('when limit is not null', () { + final result = LimitedOrEveryHandler.startDate( + every, + date, + limit: DateTime(2023, 12, 12), + ); + + expect(result, equals(expectedDate)); + }); + + test('when limit is before date', () { + final result = LimitedOrEveryHandler.startDate( + every, + date, + limit: DateTime(2023, 12, 2), + ); + + expect(result, equals(expectedDate)); + }); + }); + + group('startDate for LimitedEvery', () { + final date = DateTime(2023, 12, 3); + final expectedDate = DateTime(2023, 12, 11); + + test('when limit is null', () { + final result = + LimitedOrEveryHandler.startDate(limited, date, limit: null); + + expect(result, equals(expectedDate)); + }); + + group('when limit is not null', () { + test('and limit is after date', () { + final result = LimitedOrEveryHandler.startDate( + limited, + date, + limit: DateTime(2023, 12, 12), + ); + + expect(result, equals(expectedDate)); + }); + + test('and limit is before date', () { + expect( + () => LimitedOrEveryHandler.startDate( + limited, + date, + limit: DateTime(2023, 12), + ), + throwsA(isA()), + ); + }); + + test('and limit is the expected date', () { + final result = LimitedOrEveryHandler.startDate( + limited, + date, + limit: expectedDate, + ); + + expect(result, equals(expectedDate)); + }); + }); + }); + + group('next Every', () { + final date = DateTime(2023, 12, 3); + final expectedDate = DateTime(2023, 12, 4); + + test('when limit is null', () { + final result = LimitedOrEveryHandler.next(every, date, limit: null); + + expect(result, equals(expectedDate)); + }); + test('when limit is not null', () { + final result = LimitedOrEveryHandler.next( + every, + date, + limit: DateTime(2023, 12, 12), + ); + + expect(result, equals(expectedDate)); + }); + + test('when limit is before date', () { + final result = LimitedOrEveryHandler.next( + every, + date, + limit: DateTime(2023, 12, 2), + ); + + expect(result, equals(expectedDate)); + }); + }); + + group('next for LimitedEvery', () { + final date = DateTime(2023, 12, 3); + final expectedDate = DateTime(2023, 12, 11); + + test('when limit is null', () { + final result = LimitedOrEveryHandler.next(limited, date, limit: null); + + expect(result, equals(expectedDate)); + }); + + group('when limit is not null', () { + test('and limit is after date', () { + final result = LimitedOrEveryHandler.next( + limited, + date, + limit: DateTime(2023, 12, 12), + ); + + expect(result, equals(expectedDate)); + }); + + test('and limit is before date', () { + expect( + () => LimitedOrEveryHandler.next( + limited, + date, + limit: DateTime(2023, 12), + ), + throwsA(isA()), + ); + }); + + test('and limit is the expected date', () { + final result = LimitedOrEveryHandler.next( + limited, + date, + limit: expectedDate, + ); + + expect(result, equals(expectedDate)); + }); + }); + }); + + group('previous for Every', () { + final date = DateTime(2023, 12, 11); + final expectedDate = DateTime(2023, 12, 4); + + test('when limit is null', () { + final result = LimitedOrEveryHandler.previous(every, date, limit: null); + + expect(result, equals(expectedDate)); + }); + test('when limit is not null', () { + final result = LimitedOrEveryHandler.previous( + every, + date, + limit: DateTime(2023, 12, 3), + ); + + expect(result, equals(expectedDate)); + }); + + test('when limit is after date', () { + final result = LimitedOrEveryHandler.previous( + every, + date, + limit: DateTime(2023, 12, 5), + ); + + expect(result, equals(expectedDate)); + }); + }); + + group('previous for LimitedEvery', () { + final date = DateTime(2023, 12, 10); + final expectedDate = DateTime(2023, 11, 27); + + test('when limit is null', () { + final result = + LimitedOrEveryHandler.previous(limited, date, limit: null); + + expect(result, equals(expectedDate)); + }); + test('when limit is not null', () { + final result = LimitedOrEveryHandler.previous( + limited, + date, + limit: DateTime(2023, 11, 26), + ); + + expect(result, equals(expectedDate)); + }); + + test('when limit is before date', () { + expect( + () => LimitedOrEveryHandler.previous( + limited, + date, + limit: DateTime(2023, 11, 28), + ), + throwsA(isA()), + ); + }); + + test('and limit is the expected date', () { + final result = LimitedOrEveryHandler.previous( + limited, + date, + limit: expectedDate, + ); + + expect(result, equals(expectedDate)); + }); + }); + }); +} diff --git a/test/every_modifier_test.dart b/test/every_modifier_test.dart new file mode 100644 index 0000000..d6482ff --- /dev/null +++ b/test/every_modifier_test.dart @@ -0,0 +1,620 @@ +import 'package:due_date/due_date.dart' + show DateTimeLimitReachedException, DateValidatorWeekdayCountInMonth; +import 'package:due_date/period.dart'; +import 'package:test/test.dart'; + +void main() { + group('DateDirection', () { + test('isStart should return true for start direction', () { + const direction = DateDirection.start; + expect(direction.isStart, isTrue); + }); + + test('isStart should return false for non-start directions', () { + const nextDirection = DateDirection.next; + const previousDirection = DateDirection.previous; + expect(nextDirection.isStart, isFalse); + expect(previousDirection.isStart, isFalse); + }); + + test('isNext should return true for next direction', () { + const direction = DateDirection.next; + expect(direction.isNext, isTrue); + }); + + test('isNext should return false for non-next directions', () { + const startDirection = DateDirection.start; + const previousDirection = DateDirection.previous; + expect(startDirection.isNext, isFalse); + expect(previousDirection.isNext, isFalse); + }); + + test('isPrevious should return true for previous direction', () { + const direction = DateDirection.previous; + expect(direction.isPrevious, isTrue); + }); + + test('isPrevious should return false for non-previous directions', () { + const startDirection = DateDirection.start; + const nextDirection = DateDirection.next; + expect(startDirection.isPrevious, isFalse); + expect(nextDirection.isPrevious, isFalse); + }); + }); + + group('EverySkipInvalidModifier', () { + final every = Weekday.monday.every; + const invalidator = DateValidatorWeekdayCountInMonth( + week: Week.first, + day: Weekday.monday, + ); + final modifier = + EverySkipInvalidModifier(every: every, invalidator: invalidator); + + group('Test base methods logic', () { + final date = DateTime(2022, DateTime.october, 7); + final expected = DateTime(2022, DateTime.october, 10); + group('startDate', () { + test('If the given date would be generated, return it', () { + expect( + modifier.startDate(expected), + equals(expected), + ); + }); + test('If the given date would not be generated, use next', () { + expect( + modifier.startDate(date), + equals(modifier.next(date)), + ); + }); + }); + group('next', () { + test( + 'If the given date would be generated, generate a new one anyway', + () => expect( + modifier.next(expected), + equals(DateTime(2022, DateTime.october, 17)), + ), + ); + test( + 'If the given date would not be generated, generate the next valid ' + 'date', + () => expect(modifier.next(date), equals(expected)), + ); + }); + group('previous', () { + final expectedPrevious = DateTime(2022, DateTime.september, 26); + + test( + 'If the given date would be generated, generate a new one anyway', + () => expect(modifier.previous(expected), equals(expectedPrevious)), + ); + test( + 'If the given date would not be generated, generate the next valid ' + 'date', + () => expect(modifier.previous(date), equals(expectedPrevious)), + ); + }); + }); + + group('startDate', () { + final date = DateTime(2023, 12, 3); + final expectedDate = DateTime(2023, 12, 11); + + test('when limit is null', () { + final result = modifier.startDate(date); + + expect(result, equals(expectedDate)); + }); + + group('when limit is not null', () { + test('and limit is after date', () { + final result = modifier.startDate( + date, + limit: DateTime(2023, 12, 12), + ); + + expect(result, equals(expectedDate)); + }); + + test('and limit is before date', () { + expect( + () => modifier.startDate(date, limit: DateTime(2023, 12)), + throwsA(isA()), + ); + }); + + test('and limit is the expected date', () { + final result = modifier.startDate(date, limit: expectedDate); + + expect(result, equals(expectedDate)); + }); + }); + }); + + group('next', () { + final date = DateTime(2023, 12, 3); + final expectedDate = DateTime(2023, 12, 11); + + test('when limit is null', () { + final result = modifier.next(date); + + expect(result, equals(expectedDate)); + }); + + group('when limit is not null', () { + test('and limit is after date', () { + final result = modifier.next(date, limit: DateTime(2023, 12, 12)); + + expect(result, equals(expectedDate)); + }); + + test('and limit is before date', () { + expect( + () => modifier.next(date, limit: DateTime(2023, 12)), + throwsA(isA()), + ); + }); + + test('and limit is the expected date', () { + final result = modifier.next(date, limit: expectedDate); + + expect(result, equals(expectedDate)); + }); + }); + }); + + group('previous', () { + final date = DateTime(2023, 12, 10); + final expectedDate = DateTime(2023, 11, 27); + + test('when limit is null', () { + final result = modifier.previous(date); + + expect(result, equals(expectedDate)); + }); + test('when limit is not null', () { + final result = modifier.previous(date, limit: DateTime(2023, 11, 26)); + + expect(result, equals(expectedDate)); + }); + + test('when limit is before date', () { + expect( + () => modifier.previous(date, limit: DateTime(2023, 11, 28)), + throwsA(isA()), + ); + }); + + test('and limit is the expected date', () { + final result = modifier.previous(date, limit: expectedDate); + + expect(result, equals(expectedDate)); + }); + }); + + group('valid', () { + test('should return true', () { + final result = modifier.valid(DateTime(2023, 12, 11)); + + expect(result, isTrue); + }); + + group('should return false', () { + test('when date is invalid because of invalidator', () { + final result = modifier.valid(DateTime(2023, 12, 4)); + + expect(result, isFalse); + }); + + test('when date is invalid because of every', () { + final result = modifier.valid(DateTime(2023, 12, 3)); + + expect(result, isFalse); + }); + }); + }); + + group('invalid', () { + test('should return false', () { + final result = modifier.invalid(DateTime(2023, 12, 11)); + + expect(result, isFalse); + }); + group('should return true', () { + test('when date is invalid because of invalidator', () { + final result = modifier.invalid(DateTime(2023, 12, 4)); + + expect(result, isTrue); + }); + + test('when date is invalid because of every', () { + final result = modifier.invalid(DateTime(2023, 12, 3)); + + expect(result, isTrue); + }); + }); + }); + }); + + group('EveryOverrideWrapper', () { + final every = Weekday.monday.every; + const invalidator = DateValidatorWeekdayCountInMonth( + week: Week.first, + day: Weekday.monday, + ); + final wrapper = EveryOverrideWrapper( + every: every, + invalidator: invalidator, + overrider: Weekday.tuesday.every, + ); + + group('Test base methods logic', () { + final date = DateTime(2022, DateTime.september, 27); + final expected = DateTime(2022, DateTime.october, 4); + group('startDate', () { + test('If the given date would be generated, return it', () { + expect( + wrapper.startDate(expected), + equals(expected), + ); + }); + test('If the given date would not be generated, use next', () { + expect( + wrapper.startDate(date), + equals(wrapper.next(date)), + ); + }); + }); + group('next', () { + test( + 'If the given date would be generated, generate a new one anyway', + () => expect( + wrapper.next(expected), + equals(DateTime(2022, DateTime.october, 10)), + ), + ); + test( + 'If the given date would not be generated, generate the next valid ' + 'date', + () => expect( + wrapper.next(date), + equals(expected), + ), + ); + }); + group('previous', () { + final expectedPrevious = DateTime(2022, DateTime.september, 26); + + test( + 'If the given date would be generated, generate a new one anyway', + () { + expect( + wrapper.previous(DateTime(2022, DateTime.october, 3)), + equals(expectedPrevious), + ); + expect( + wrapper.previous(DateTime(2022, DateTime.october, 4)), + equals(DateTime(2022, DateTime.september, 27)), + ); + }, + ); + test( + 'If the given date would not be generated, generate the next valid ' + 'date', + () => expect(wrapper.previous(date), equals(expectedPrevious)), + ); + }); + }); + + group('startDate', () { + final date = DateTime(2023, 12, 3); + final expectedDate = DateTime(2023, 12, 5); + + test('when limit is null', () { + final result = wrapper.startDate(date); + + expect(result, equals(expectedDate)); + }); + + group('when limit is not null', () { + test('and limit is after date', () { + final result = wrapper.startDate( + date, + limit: DateTime(2023, 12, 12), + ); + + expect(result, equals(expectedDate)); + }); + + test('and limit is before date', () { + expect( + () => wrapper.startDate(date, limit: DateTime(2023, 12)), + throwsA(isA()), + ); + }); + + test('and limit is the expected date', () { + final result = wrapper.startDate(date, limit: expectedDate); + + expect(result, equals(expectedDate)); + }); + }); + }); + + group('next', () { + final date = DateTime(2023, 12, 3); + final expectedDate = DateTime(2023, 12, 5); + + test('when limit is null', () { + final result = wrapper.next(date); + + expect(result, equals(expectedDate)); + }); + + group('when limit is not null', () { + test('and limit is after date', () { + final result = wrapper.next(date, limit: DateTime(2023, 12, 12)); + + expect(result, equals(expectedDate)); + }); + + test('and limit is before date', () { + expect( + () => wrapper.next(date, limit: DateTime(2023, 12)), + throwsA(isA()), + ); + }); + + test('and limit is the expected date', () { + final result = wrapper.next(date, limit: expectedDate); + + expect(result, equals(expectedDate)); + }); + }); + }); + + group('previous', () { + final date = DateTime(2023, 12, 10); + final expectedDate = DateTime(2023, 11, 28); + + test('when limit is null', () { + final result = wrapper.previous(date); + + expect(result, equals(expectedDate)); + }); + test('when limit is not null', () { + final result = wrapper.previous(date, limit: DateTime(2023, 11, 26)); + + expect(result, equals(expectedDate)); + }); + + test('when limit is before date', () { + expect( + () => wrapper.previous(date, limit: DateTime(2023, 11, 29)), + throwsA(isA()), + ); + }); + + test('and limit is the expected date', () { + final result = wrapper.previous(date, limit: expectedDate); + + expect(result, equals(expectedDate)); + }); + }); + }); + + group('EverySkipCountWrapper', () { + final every = Weekday.monday.every; + + group('Test base methods logic', () { + group('Count 0', () { + final wrapper = EverySkipCountWrapper(every: every, count: 0); + final date = DateTime(2022, DateTime.september, 27); + final expected = DateTime(2022, DateTime.october, 3); + group('startDate', () { + test('If the given date would be generated, return it', () { + expect(wrapper.startDate(expected), equals(expected)); + }); + test('If the given date would not be generated, use next', () { + expect(wrapper.startDate(date), equals(wrapper.next(date))); + }); + }); + group('next', () { + test( + 'If the given date would be generated, generate a new one anyway', + () => expect( + wrapper.next(expected), + equals(DateTime(2022, DateTime.october, 10)), + ), + ); + test( + 'If the given date would not be generated, generate the next valid ' + 'date', + () => expect(wrapper.next(date), equals(expected)), + ); + }); + group('previous', () { + final expectedPrevious = DateTime(2022, DateTime.september, 26); + + test( + 'If the given date would be generated, generate a new one anyway', + () => expect(wrapper.previous(expected), equals(expectedPrevious)), + ); + test( + 'If the given date would not be generated, generate the next valid ' + 'date', + () => expect(wrapper.previous(date), equals(expectedPrevious)), + ); + }); + }); + group('Count 1', () { + final wrapper = EverySkipCountWrapper(every: every, count: 1); + final date = DateTime(2022, DateTime.september, 27); + final expected = DateTime(2022, DateTime.october, 3); + group('startDate', () { + test('If the given date would be generated, return it', () { + expect(wrapper.startDate(expected), equals(expected)); + }); + test('If the given date would not be generated, use next', () { + expect(wrapper.startDate(date), equals(wrapper.next(date))); + }); + }); + group('next', () { + test( + 'If the given date would be generated, generate a new one anyway', + () => expect( + wrapper.next(expected), + equals(DateTime(2022, DateTime.october, 17)), + ), + ); + test( + 'If the given date would not be generated, generate the next valid ' + 'date', + () => expect( + wrapper.next(date), + equals(DateTime(2022, DateTime.october, 10)), + ), + ); + }); + group('previous', () { + final expectedPrevious = DateTime(2022, DateTime.september, 19); + + test( + 'If the given date would be generated, generate a new one anyway', + () { + expect( + wrapper.previous(DateTime(2022, DateTime.october, 3)), + equals(expectedPrevious), + ); + }, + ); + test( + 'If the given date would not be generated, generate the next valid ' + 'date', + () => expect(wrapper.previous(date), equals(expectedPrevious)), + ); + }); + }); + }); + + group('constructor ', () { + test('when count is 0', () { + expect( + EverySkipCountWrapper(every: every, count: 0), + isA(), + ); + }); + test('when count is negative', () { + expect( + () => EverySkipCountWrapper(every: every, count: -1), + throwsA(isA()), + ); + }); + test('when count is positive', () { + expect( + EverySkipCountWrapper(every: every, count: 1), + isA(), + ); + }); + }); + + final wrapper = EverySkipCountWrapper(every: every, count: 1); + + group('startDate', () { + final date = DateTime(2023, 12, 3); + final expectedDate = DateTime(2023, 12, 11); + + test('when limit is null', () { + final result = wrapper.startDate(date); + + expect(result, equals(expectedDate)); + }); + + group('when limit is not null', () { + test('and limit is after date', () { + final result = wrapper.startDate( + date, + limit: DateTime(2023, 12, 12), + ); + + expect(result, equals(expectedDate)); + }); + + test('and limit is before date', () { + expect( + () => wrapper.startDate(date, limit: DateTime(2023, 12)), + throwsA(isA()), + ); + }); + + test('and limit is the expected date', () { + final result = wrapper.startDate(date, limit: expectedDate); + + expect(result, equals(expectedDate)); + }); + }); + }); + + group('next', () { + final date = DateTime(2023, 12, 3); + final expectedDate = DateTime(2023, 12, 11); + + test('when limit is null', () { + final result = wrapper.next(date); + + expect(result, equals(expectedDate)); + }); + + group('when limit is not null', () { + test('and limit is after date', () { + final result = wrapper.next(date, limit: DateTime(2023, 12, 12)); + + expect(result, equals(expectedDate)); + }); + + test('and limit is before date', () { + expect( + () => wrapper.next(date, limit: DateTime(2023, 12)), + throwsA(isA()), + ); + }); + + test('and limit is the expected date', () { + final result = wrapper.next(date, limit: expectedDate); + + expect(result, equals(expectedDate)); + }); + }); + }); + + group('previous', () { + final date = DateTime(2023, 12, 10); + final expectedDate = DateTime(2023, 11, 27); + + test('when limit is null', () { + final result = wrapper.previous(date); + + expect(result, equals(expectedDate)); + }); + test('when limit is not null', () { + final result = wrapper.previous(date, limit: DateTime(2023, 11, 26)); + + expect(result, equals(expectedDate)); + }); + + test('when limit is before date', () { + expect( + () => wrapper.previous(date, limit: DateTime(2023, 11, 29)), + throwsA(isA()), + ); + }); + + test('and limit is the expected date', () { + final result = wrapper.previous(date, limit: expectedDate); + + expect(result, equals(expectedDate)); + }); + }); + }); +} From 49521b9cb9307bf4281968a24f4bea0cfb107b3c Mon Sep 17 00:00:00 2001 From: FMorschel <52160996+FMorschel@users.noreply.github.com> Date: Thu, 7 Dec 2023 02:57:03 -0300 Subject: [PATCH 05/16] Removed mentions of #14 and fixed imports --- lib/period.dart | 6 +++++- lib/src/every.dart | 5 ++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/period.dart b/lib/period.dart index 7fc6bf7..57548cc 100644 --- a/lib/period.dart +++ b/lib/period.dart @@ -16,7 +16,11 @@ /// [SemesterGenerator] and [YearGenerator]. library period; -export 'src/enums.dart' show Weekday, Month, Week, PeriodGenerator; +import 'src/enums.dart' show PeriodGenerator; +import 'src/period.dart'; +import 'src/period_generator.dart'; + +export 'src/enums.dart' show Month, PeriodGenerator, Week, Weekday; export 'src/extensions.dart' show EndOfDay; export 'src/period.dart'; export 'src/period_generator.dart'; diff --git a/lib/src/every.dart b/lib/src/every.dart index 4b656c2..efa625a 100644 --- a/lib/src/every.dart +++ b/lib/src/every.dart @@ -58,9 +58,8 @@ abstract class LimitedEvery extends Every { /// Abstract class that forces the implementation of [Every] to have a /// limit parameter for the [startDate], [next] and [previous] methods. /// - /// See [EveryDateValidatorDifference], [EveryDateValidatorIntersection], - /// [EveryDateValidatorUnion], [EverySkipCountWrapper], [EveryOverrideWrapper] - /// and [EverySkipInvalidModifier] for complete base implementations. + /// See [EveryDateValidatorDifference], [EveryDateValidatorIntersection] and + /// [EveryDateValidatorUnion] for complete base implementations. /// /// See [EveryWeek], [EveryMonth], [EveryYear] for your base implementations. const LimitedEvery(); From 9f379a8fcbde7022599b0517c01e0411dae35a9c Mon Sep 17 00:00:00 2001 From: FMorschel <52160996+FMorschel@users.noreply.github.com> Date: Thu, 7 Dec 2023 03:03:07 -0300 Subject: [PATCH 06/16] Removed changes that need #12 --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 730b101..7a10bc2 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,6 @@ [![popularity](https://badges.bar/due_date/popularity)](https://pub.dev/packages/due_date/score) -[![Build](https://github.com/fmorschel/due_date/actions/workflows/build.yml/badge.svg)](https://github.com/fmorschel/due_date/actions/workflows/build.yml) - -[![codecov](https://codecov.io/gh/fmorschel/due_date/branch/main/graph/badge.svg)](https://codecov.io/gh/fmorschel/due_date) - A package for working with repeating `DateTime` patterns. Ever wanted to create a new `DateTime` with, let's say, the same day in month? But the day is 31 and next month only has 30, so you go to 30 and the next day is lost because then you have no variable to save the original's month day? With `DueDateTime` this managing is done for you without any headaches. From a5fb8119013a446934273307dc729ad8cbcc83dd Mon Sep 17 00:00:00 2001 From: FMorschel <52160996+FMorschel@users.noreply.github.com> Date: Thu, 7 Dec 2023 03:03:50 -0300 Subject: [PATCH 07/16] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 85a53fa..9836de0 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +[![Build](https://github.com/fmorschel/due_date/actions/workflows/build.yml/badge.svg)](https://github.com/fmorschel/due_date/actions/workflows/build.yml) + +[![codecov](https://codecov.io/gh/fmorschel/due_date/branch/main/graph/badge.svg)](https://codecov.io/gh/fmorschel/due_date) + # DueDate A package for working with repeating `DateTime` patterns. From 9ac9b571dab10fe1a80223bcac93a07fd95d9fa3 Mon Sep 17 00:00:00 2001 From: FMorschel <52160996+FMorschel@users.noreply.github.com> Date: Thu, 7 Dec 2023 04:38:04 -0300 Subject: [PATCH 08/16] Updating project info --- .idea/.gitignore | 3 ++ .idea/codeStyles/Project.xml | 7 +++ .idea/codeStyles/codeStyleConfig.xml | 5 ++ .idea/misc.xml | 6 +++ .idea/vcs.xml | 6 +++ .markdownlint.json | 5 ++ .vscode/extensions.json | 7 +++ .vscode/settings.json | 3 ++ CONTRIBUTING.md | 76 ++++++++++++++++++++++++++++ README.md | 19 ++++--- pubspec.yaml | 12 +++++ 11 files changed, 142 insertions(+), 7 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/vcs.xml create mode 100644 .markdownlint.json create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 CONTRIBUTING.md diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..c97b9e9 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..639900d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..632ae1f --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,5 @@ +{ + "default": true, + "MD013": false, + "MD033": false +} \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..6654552 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "dart-code.dart-code", + "streetsidesoftware.code-spell-checker", + "davidanson.vscode-markdownlint" + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..11c39d7 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "dart.lineLength": 80 +} \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..5ed0a72 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,76 @@ +# Contributing to due_date + +First off, thanks for considering contributing to due_date! ❤️ + +## Ways to Contribute + +Here are some ways you can contribute to the project: + +### Reporting Bugs + +If you find a bug, please file an issue describing the problem. Include steps to reproduce the bug so we can investigate. +File issues at . + +### Suggesting Enhancements + +We welcome enhancement suggestions! File an issue explaining your idea with as much detail as possible. +File issues at . + +### Contributing Code + +Code contributions are welcome! Please follow these guidelines: + +- Fork the repo and create a new branch for your change. + +- Run `dart analyze` to check for any static analysis issues. +- Run `dart test` to run all tests. Make sure all tests pass. +- Run `dart fix --apply` to fix any linting issues. +- Run `dart format` to auto-format your code changes. Keep coding style consistent. +- Consider writing tests covering your change. All code should have full test coverage. +- Document any public API changes. Make sure docs are updated. +- Submit a pull request with details explaining what you changed. +Create a PR at + +We will review your PR and let you know if any other changes are needed. + +## Questions + +If you just have a question on using the library, ask away on our discussions tracker! +Discuss related topics at . + +## Donations + +due_date is an open source project that I maintain in my free time. If you find it useful, donations are greatly appreciated! + +### Why Donate? + +Your donations allow me to spend more time maintaining and improving the package: + +- Responding to issues +- Reviewing pull requests +- Adding new features +- Writing documentation +- Updating dependencies + +Without donations, I need to limit my time spent based on what I can fit around other priorities in life. + +### Making a Donation + +If you're interested in donating to support due_date development, you can do so via: + +- [GitHub Sponsors](https://github.com/sponsors/fmorschel) - Recurring or one-time payments +- [Buy me a coffee](https://www.buymeacoffee.com/fmorschel) - One-time payments + +All donations are greatly appreciated! Every bit helps justify more time spent on open source work. + +## Using Donations + +Donations help provide financial support but do not influence due_date's roadmap or feature priorities. Bug fixes and maintenance tasks always take priority. + +The majority of donations fund my time spent coding, documenting, reviewing, and responding to the community. + +I commit to being fully transparent about how donations are used to sustain development. Please feel free to ask questions! + +## License + +By contributing code, you agree to license your contribution under the [MIT license](LICENSE). diff --git a/README.md b/README.md index 7a10bc2..53d2652 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,17 @@ # DueDate [![pub package](https://img.shields.io/pub/v/due_date.svg)](https://pub.dev/packages/due_date) - -[![likes](https://badges.bar/due_date/likes)](https://pub.dev/packages/due_date/score) - -[![pub points](https://badges.bar/due_date/pub%20points)](https://pub.dev/packages/due_date/score) - -[![popularity](https://badges.bar/due_date/popularity)](https://pub.dev/packages/due_date/score) +[![GitHub License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/FMorschel/due_date/main/LICENSE) + +[![GitHub Sponsors](https://img.shields.io/github/sponsors/FMorschel)](https://github.com/sponsors/FMorschel) + +Buy Me A Coffee donate button + A package for working with repeating `DateTime` patterns. @@ -102,7 +107,7 @@ Contribute to the package by creating a PR at . -Discuss related topics at +Discuss related topics at . ## Alternatives/Inspiration diff --git a/pubspec.yaml b/pubspec.yaml index c024d78..2dddcdf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,6 +4,18 @@ version: 2.0.0 homepage: https://fmorschel.github.io/due_date/ repository: https://github.com/FMorschel/due_date issue_tracker: https://github.com/FMorschel/due_date/issues +funding: + - https://github.com/sponsors/FMorschel + - https://www.buymeacoffee.com/fmorschel +topics: + - date + - datetime + - date-time + - time + - calendar + #- common-utilities + #- util + #- utils environment: sdk: '>=2.17.6 <4.0.0' From 617db8e5671595f3d34612279ff7739001e5c364 Mon Sep 17 00:00:00 2001 From: FMorschel <52160996+FMorschel@users.noreply.github.com> Date: Thu, 7 Dec 2023 04:50:53 -0300 Subject: [PATCH 09/16] Removed missing unused import --- lib/src/every.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/src/every.dart b/lib/src/every.dart index deb7ea1..efa625a 100644 --- a/lib/src/every.dart +++ b/lib/src/every.dart @@ -3,7 +3,6 @@ import 'package:time/time.dart'; import 'constants.dart'; import 'date_validator.dart'; import 'enums.dart'; -import 'every_modifier.dart'; import 'extensions.dart'; /// Abstract class that, when extended, processes [DateTime] with custom logic. From f862421d4f3f75220b16ffbf21330dc020e54255 Mon Sep 17 00:00:00 2001 From: FMorschel <52160996+FMorschel@users.noreply.github.com> Date: Thu, 7 Dec 2023 04:52:20 -0300 Subject: [PATCH 10/16] Adding to solve warning in pubspec.yaml topics --- .vscode/settings.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 46ce5e5..f1dbe44 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { "cSpell.words": [ + "datetime", "endtemplate", "everies", "overrider" From 849e33071551773c2f55af68fa744e0914a210c3 Mon Sep 17 00:00:00 2001 From: FMorschel <52160996+FMorschel@users.noreply.github.com> Date: Mon, 11 Dec 2023 17:07:28 -0300 Subject: [PATCH 11/16] First git hook --- .hooks/pre-commit | 83 +++++++++++++++++++++++++++++++++++++ lib/src/date_validator.dart | 4 +- lib/src/due_date.dart | 10 ++--- lib/src/enums.dart | 55 ++++++++++++++++++++++++ test/constants_test.dart | 2 +- 5 files changed, 146 insertions(+), 8 deletions(-) create mode 100644 .hooks/pre-commit diff --git a/.hooks/pre-commit b/.hooks/pre-commit new file mode 100644 index 0000000..c051c03 --- /dev/null +++ b/.hooks/pre-commit @@ -0,0 +1,83 @@ +#!/bin/sh + +echo "Running pre-commit checks..." + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=$(git hash-object -t tree /dev/null) +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --type=bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# Fetch packages +echo "Running dart pub get..." +dart pub get >/dev/null +if [ $? -ne 0 ]; then + echo "dart pub get failed." + echo "Please run 'dart pub get' in the project root." + exit 1 +fi + +# Dart analyzer no errors should be found +echo "Running Dart analyzer..." +dart analyze +if [ $? -ne 0 ]; then + echo "Dart analyzer found issues." + echo "Please run 'dart analyze' in the project root." + exit 1 +fi + +# Dart tests should pass +echo "Running Dart tests..." +dart test . --fail-fast 1>/dev/null +# Print files that failed tests +if [ $? -ne 0 ]; then + echo "Dart tests failed." + echo "Please run 'dart test' in the project root." + exit 1 +fi + +# Dart fix --apply then any changed files should be added to the commit +echo "Running Dart fix..." +dart fix --apply . +git add . + +# Dart format then any changed files should be added to the commit +echo "Running Dart format..." +dart format . +git add . + +# return 0 to indicate that everything went well +echo "Pre-commit checks passed." +exit 0 diff --git a/lib/src/date_validator.dart b/lib/src/date_validator.dart index 27530d6..372e3bc 100644 --- a/lib/src/date_validator.dart +++ b/lib/src/date_validator.dart @@ -37,7 +37,7 @@ abstract class DateValidator { } /// Mixin to easily implement the [DateValidator.invalid], -/// [DateValidator.filterValidDates] and [DateValidator.filterValidDates] +/// [DateValidator.filterValidDates] and [DateValidator.filterValidDates] /// methods. mixin DateValidatorMixin implements DateValidator { @override @@ -342,7 +342,7 @@ class DateValidatorUnion extends DelegatingList /// one of the [validators]. class DateValidatorDifference extends DelegatingList with EquatableMixin, DateValidatorMixin, DateValidatorListMixin { - /// A [DateValidator] that validates a [DateTime] if the date is valid for + /// A [DateValidator] that validates a [DateTime] if the date is valid for /// only one of the [validators]. const DateValidatorDifference(super.validators); diff --git a/lib/src/due_date.dart b/lib/src/due_date.dart index 1a4c447..e7a684a 100644 --- a/lib/src/due_date.dart +++ b/lib/src/due_date.dart @@ -501,8 +501,8 @@ class DueDateTime extends DateTime with EquatableMixin { /// ``` /// /// Notice that the duration being added is actually 50 * 24 * 60 * 60 - /// seconds. If the resulting `DueDateTime` has a different daylight saving - /// offset than `this`, then the result won't have the same time-of-day as + /// seconds. If the resulting `DueDateTime` has a different daylight saving + /// offset than `this`, then the result won't have the same time-of-day as /// `this`, and may not even hit the calendar date 50 days later. /// /// Be careful when working with dates in local time. @@ -515,7 +515,7 @@ class DueDateTime extends DateTime with EquatableMixin { return DueDateTime.fromDate(date, every: sameEvery ? every : null); } - /// Returns a new [DueDateTime] instance with [duration] subtracted from + /// Returns a new [DueDateTime] instance with [duration] subtracted from /// `this`. /// /// If [sameEvery] is true, keeps the current one. @@ -530,8 +530,8 @@ class DueDateTime extends DateTime with EquatableMixin { /// ``` /// /// Notice that the duration being subtracted is actually 50 * 24 * 60 * 60 - /// seconds. If the resulting `DueDateTime` has a different daylight saving - /// offset than `this`, then the result won't have the same time-of-day as + /// seconds. If the resulting `DueDateTime` has a different daylight saving + /// offset than `this`, then the result won't have the same time-of-day as /// `this`, and may not even hit the calendar date 50 days earlier. /// /// Be careful when working with dates in local time. diff --git a/lib/src/enums.dart b/lib/src/enums.dart index dbd6147..f525480 100644 --- a/lib/src/enums.dart +++ b/lib/src/enums.dart @@ -7,32 +7,38 @@ import '../period.dart'; enum Weekday implements Comparable { /// Monday. monday(DateTime.monday, generator: WeekGenerator()), + /// Tuesday. tuesday( DateTime.tuesday, generator: WeekGenerator(weekStart: DateTime.tuesday), ), + /// Wednesday. wednesday( DateTime.wednesday, generator: WeekGenerator(weekStart: DateTime.wednesday), ), + /// Thursday. thursday( DateTime.thursday, generator: WeekGenerator(weekStart: DateTime.thursday), ), + /// Friday. friday( DateTime.friday, generator: WeekGenerator(weekStart: DateTime.friday), ), + /// Saturday. saturday( DateTime.saturday, isWeekend: true, generator: WeekGenerator(weekStart: DateTime.saturday), ), + /// Sunday. sunday( DateTime.sunday, @@ -214,26 +220,37 @@ enum Weekday implements Comparable { enum Month implements Comparable { /// January month constant. january(DateTime.january), + /// February month constant. february(DateTime.february), + /// March month constant. march(DateTime.march), + /// April month constant. april(DateTime.april), + /// May month constant. may(DateTime.may), + /// June month constant. june(DateTime.june), + /// July month constant. july(DateTime.july), + /// August month constant. august(DateTime.august), + /// September month constant. september(DateTime.september), + /// October month constant. october(DateTime.october), + /// November month constant. november(DateTime.november), + /// December month constant. december(DateTime.december); @@ -341,12 +358,16 @@ enum Month implements Comparable { enum Week implements Comparable { /// First week. first, + /// Second week. second, + /// Third week. third, + /// Fourth week. fourth, + /// Last week. last; @@ -498,6 +519,7 @@ enum WeekdayOccurrence week: Week.first, ), ), + /// The first Tuesday of the month. firstTuesday( EveryWeekdayCountInMonth( @@ -505,6 +527,7 @@ enum WeekdayOccurrence week: Week.first, ), ), + /// The first Wednesday of the month. firstWednesday( EveryWeekdayCountInMonth( @@ -512,6 +535,7 @@ enum WeekdayOccurrence week: Week.first, ), ), + /// The first Thursday of the month. firstThursday( EveryWeekdayCountInMonth( @@ -519,6 +543,7 @@ enum WeekdayOccurrence week: Week.first, ), ), + /// The first Friday of the month. firstFriday( EveryWeekdayCountInMonth( @@ -526,6 +551,7 @@ enum WeekdayOccurrence week: Week.first, ), ), + /// The first Saturday of the month. firstSaturday( EveryWeekdayCountInMonth( @@ -533,6 +559,7 @@ enum WeekdayOccurrence week: Week.first, ), ), + /// The first Sunday of the month. firstSunday( EveryWeekdayCountInMonth( @@ -540,6 +567,7 @@ enum WeekdayOccurrence week: Week.first, ), ), + /// The second Monday of the month. secondMonday( EveryWeekdayCountInMonth( @@ -547,6 +575,7 @@ enum WeekdayOccurrence week: Week.second, ), ), + /// The second Tuesday of the month. secondTuesday( EveryWeekdayCountInMonth( @@ -554,6 +583,7 @@ enum WeekdayOccurrence week: Week.second, ), ), + /// The second Wednesday of the month. secondWednesday( EveryWeekdayCountInMonth( @@ -561,6 +591,7 @@ enum WeekdayOccurrence week: Week.second, ), ), + /// The second Thursday of the month. secondThursday( EveryWeekdayCountInMonth( @@ -568,6 +599,7 @@ enum WeekdayOccurrence week: Week.second, ), ), + /// The second Friday of the month. secondFriday( EveryWeekdayCountInMonth( @@ -575,6 +607,7 @@ enum WeekdayOccurrence week: Week.second, ), ), + /// The second Saturday of the month. secondSaturday( EveryWeekdayCountInMonth( @@ -582,6 +615,7 @@ enum WeekdayOccurrence week: Week.second, ), ), + /// The second Sunday of the month. secondSunday( EveryWeekdayCountInMonth( @@ -589,6 +623,7 @@ enum WeekdayOccurrence week: Week.second, ), ), + /// The third Monday of the month. thirdMonday( EveryWeekdayCountInMonth( @@ -596,6 +631,7 @@ enum WeekdayOccurrence week: Week.third, ), ), + /// The third Tuesday of the month. thirdTuesday( EveryWeekdayCountInMonth( @@ -603,6 +639,7 @@ enum WeekdayOccurrence week: Week.third, ), ), + /// The third Wednesday of the month. thirdWednesday( EveryWeekdayCountInMonth( @@ -610,6 +647,7 @@ enum WeekdayOccurrence week: Week.third, ), ), + /// The third Thursday of the month. thirdThursday( EveryWeekdayCountInMonth( @@ -617,6 +655,7 @@ enum WeekdayOccurrence week: Week.third, ), ), + /// The third Friday of the month. thirdFriday( EveryWeekdayCountInMonth( @@ -624,6 +663,7 @@ enum WeekdayOccurrence week: Week.third, ), ), + /// The third Saturday of the month. thirdSaturday( EveryWeekdayCountInMonth( @@ -631,6 +671,7 @@ enum WeekdayOccurrence week: Week.third, ), ), + /// The third Sunday of the month. thirdSunday( EveryWeekdayCountInMonth( @@ -638,6 +679,7 @@ enum WeekdayOccurrence week: Week.third, ), ), + /// The fourth Monday of the month. fourthMonday( EveryWeekdayCountInMonth( @@ -645,6 +687,7 @@ enum WeekdayOccurrence week: Week.fourth, ), ), + /// The fourth Tuesday of the month. fourthTuesday( EveryWeekdayCountInMonth( @@ -652,6 +695,7 @@ enum WeekdayOccurrence week: Week.fourth, ), ), + /// The fourth Wednesday of the month. fourthWednesday( EveryWeekdayCountInMonth( @@ -659,6 +703,7 @@ enum WeekdayOccurrence week: Week.fourth, ), ), + /// The fourth Thursday of the month. fourthThursday( EveryWeekdayCountInMonth( @@ -666,6 +711,7 @@ enum WeekdayOccurrence week: Week.fourth, ), ), + /// The fourth Friday of the month. fourthFriday( EveryWeekdayCountInMonth( @@ -673,6 +719,7 @@ enum WeekdayOccurrence week: Week.fourth, ), ), + /// The fourth Saturday of the month. fourthSaturday( EveryWeekdayCountInMonth( @@ -680,6 +727,7 @@ enum WeekdayOccurrence week: Week.fourth, ), ), + /// The fourth Sunday of the month. fourthSunday( EveryWeekdayCountInMonth( @@ -687,6 +735,7 @@ enum WeekdayOccurrence week: Week.fourth, ), ), + /// The last Monday of the month. lastMonday( EveryWeekdayCountInMonth( @@ -694,6 +743,7 @@ enum WeekdayOccurrence week: Week.last, ), ), + /// The last Tuesday of the month. lastTuesday( EveryWeekdayCountInMonth( @@ -701,6 +751,7 @@ enum WeekdayOccurrence week: Week.last, ), ), + /// The last Wednesday of the month. lastWednesday( EveryWeekdayCountInMonth( @@ -708,6 +759,7 @@ enum WeekdayOccurrence week: Week.last, ), ), + /// The last Thursday of the month. lastThursday( EveryWeekdayCountInMonth( @@ -715,6 +767,7 @@ enum WeekdayOccurrence week: Week.last, ), ), + /// The last Friday of the month. lastFriday( EveryWeekdayCountInMonth( @@ -722,6 +775,7 @@ enum WeekdayOccurrence week: Week.last, ), ), + /// The last Saturday of the month. lastSaturday( EveryWeekdayCountInMonth( @@ -729,6 +783,7 @@ enum WeekdayOccurrence week: Week.last, ), ), + /// The last Sunday of the month. lastSunday( EveryWeekdayCountInMonth( diff --git a/test/constants_test.dart b/test/constants_test.dart index 5cd4e66..93b3240 100644 --- a/test/constants_test.dart +++ b/test/constants_test.dart @@ -150,7 +150,7 @@ void main() { throwsA(isA()), ); }); - + test('and limit is the expected date', () { final result = LimitedOrEveryHandler.next( limited, From adb23e42d406f7bf48505b147061454fb4f4918f Mon Sep 17 00:00:00 2001 From: FMorschel <52160996+FMorschel@users.noreply.github.com> Date: Thu, 7 Dec 2023 02:26:41 -0300 Subject: [PATCH 12/16] Create build.yml --- .github/workflows/build.yml | 68 +++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..43a310f --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,68 @@ +name: Build + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: dart-lang/setup-dart@v1 + with: + sdk: main + + - name: Install dependencies + run: dart pub get + + - name: Check format + run: dart format --output=none --set-exit-if-changed -l 80 lib + + - name: Analyze + run: dart analyze lib + + - name: Run tests + run: dart test --coverage coverage --reporter=github + + - name: Coverage + run: dart run coverage:format_coverage -l -i ./coverage/test/due_date_test.dart.vm.json -o ./coverage/lcov.info + + - name: Upload coverage to codecov + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: true # optional (default = false) + verbose: true # optional (default = false) + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + + update-docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: dart-lang/setup-dart@v1 + with: + sdk: main + - name: Generate docs + run: dart doc + - name: Checkout gh-pages branch + run: | + git fetch + git checkout gh-pages + - name: Clear base folder + run: | + rm -rf * + - name: Copy docs to base folder + run: | + cp -r ../doc/api/* . + - name: Commit and push + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git add . + git commit -m "Update documentation" -a + git push \ No newline at end of file From 849338723260ec05d24c6a190239d374aff0c440 Mon Sep 17 00:00:00 2001 From: FMorschel <52160996+FMorschel@users.noreply.github.com> Date: Thu, 7 Dec 2023 03:03:50 -0300 Subject: [PATCH 13/16] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 53d2652..d67a8f7 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +[![Build](https://github.com/fmorschel/due_date/actions/workflows/build.yml/badge.svg)](https://github.com/fmorschel/due_date/actions/workflows/build.yml) + +[![codecov](https://codecov.io/gh/fmorschel/due_date/branch/main/graph/badge.svg)](https://codecov.io/gh/fmorschel/due_date) + # DueDate [![pub package](https://img.shields.io/pub/v/due_date.svg)](https://pub.dev/packages/due_date) From 21fd89cadfa024e546a4bd7c8226e3423415a186 Mon Sep 17 00:00:00 2001 From: FMorschel <52160996+FMorschel@users.noreply.github.com> Date: Tue, 12 Dec 2023 14:18:20 -0300 Subject: [PATCH 14/16] Differenciating workflows --- .github/workflows/{build.yml => dart.yml} | 29 +----- .github/workflows/docs.yml | 38 +++++++ .github/workflows/version.yml | 120 ++++++++++++++++++++++ 3 files changed, 159 insertions(+), 28 deletions(-) rename .github/workflows/{build.yml => dart.yml} (58%) create mode 100644 .github/workflows/docs.yml create mode 100644 .github/workflows/version.yml diff --git a/.github/workflows/build.yml b/.github/workflows/dart.yml similarity index 58% rename from .github/workflows/build.yml rename to .github/workflows/dart.yml index 43a310f..5597c90 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/dart.yml @@ -1,4 +1,4 @@ -name: Build +name: Dart CI on: push: @@ -39,30 +39,3 @@ jobs: verbose: true # optional (default = false) env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - - update-docs: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: dart-lang/setup-dart@v1 - with: - sdk: main - - name: Generate docs - run: dart doc - - name: Checkout gh-pages branch - run: | - git fetch - git checkout gh-pages - - name: Clear base folder - run: | - rm -rf * - - name: Copy docs to base folder - run: | - cp -r ../doc/api/* . - - name: Commit and push - run: | - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - git add . - git commit -m "Update documentation" -a - git push \ No newline at end of file diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..2e137cb --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,38 @@ +name: Update Docs + +on: + push: + branches: + - stable + paths: + - 'docs/api/**' + pull_request: + branches: + - stable + paths: + - 'docs/api/**' + +jobs: + update-docs: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Install git-filter-repo + run: sudo apt-get install -y git-filter-repo + + - name: Switch to gh-pages and replace contents + run: | + git checkout gh-pages + git rm -r -f . + git checkout HEAD -- docs/api + mv docs/api/* . + git add . + git commit -m "Update gh-pages" || echo "No changes to commit" + git push + + - name: Filter repo + run: | + git filter-repo --path docs/api \ No newline at end of file diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml new file mode 100644 index 0000000..44546af --- /dev/null +++ b/.github/workflows/version.yml @@ -0,0 +1,120 @@ +name: Update Version + +on: + push: + branches: + - stable + pull_request: + branches: + - stable + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Dart + uses: dart-lang/setup-dart@v1 + + - name: Validate files + run: | + # Extract version from pubspec.yaml + version=$(grep 'version:' pubspec.yaml | cut -d ' ' -f 2) + + # Get the version from the last commit on stable (if it exists) + git fetch origin stable:stable + last_version=$(git show stable:pubspec.yaml | grep 'version:' | cut -d ' ' -f 2) + + # Check if the versions are different + if [ "$version" != "$last_version" ]; then + echo "Version has been updated to $version" + else + echo "Version has not been updated" + exit 1 + fi + + # Check if README.md and CHANGELOG.md contain the new version number + if grep -q "$version" README.md && grep -q "$version" CHANGELOG.md; then + echo "Version number found in README.md and CHANGELOG.md" + else + echo "Version number not found in README.md or CHANGELOG.md" + exit 1 + fi + + - name: Delete docs directory + run: rm -rf docs/* + + - name: Generate docs + run: dart doc + + - name: Commit changes + run: | + git add . + git commit -m "Update docs" || echo "No changes to commit" + + - name: Push changes + run: git push + + - name: Setup reviewdog + uses: reviewdog/action-setup@v1 + with: + reviewdog_version: latest + + - name: Generate tag message + id: generate_tag_message + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + VERSION_NUMBER=$(grep 'version:' pubspec.yaml | sed 's/version: //g') + LAST_VERSION=$(git describe --abbrev=0 --tags `git rev-list --tags --skip=1 --max-count=1`) + COMMITS=$(curl -s -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/repos/${{ github.repository }}/compare/$LAST_VERSION...$VERSION_NUMBER) + + WHATS_CHANGED="" + NEW_CONTRIBUTORS="" + CONTRIBUTORS=() + + for row in $(echo "${COMMITS}" | jq -r '.commits[] | @base64'); do + _jq() { + echo ${row} | base64 --decode | jq -r ${1} + } + + COMMIT_SHA=$(_jq '.sha') + COMMIT_MESSAGE=$(_jq '.commit.message') + AUTHOR_USERNAME=$(_jq '.author.login') + PR_NUMBER=$(curl -s -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/repos/${{ github.repository }}/commits/$COMMIT_SHA/pulls | jq -r '.[0].number') + + WHATS_CHANGED+="$COMMIT_MESSAGE by @$AUTHOR_USERNAME in #$PR_NUMBER\n" + + if [[ ! " ${CONTRIBUTORS[@]} " =~ " ${AUTHOR_USERNAME} " ]]; then + CONTRIBUTORS+=("$AUTHOR_USERNAME") + NEW_CONTRIBUTORS+="@$AUTHOR_USERNAME made their first contribution in #$PR_NUMBER\n" + fi + done + + DESCRIPTION="What's Changed\n$WHATS_CHANGED\nNew Contributors\n$NEW_CONTRIBUTORS\nFull Changelog: $LAST_VERSION...$VERSION_NUMBER" + echo "::set-output name=description::$DESCRIPTION" + + - name: Review tag message + run: | + echo "${{ steps.generate_tag_message.outputs.description }}" | reviewdog -f=diff -diff="git diff" -reporter=github-pr-review + + - name: Create tag with version number + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git tag -a $VERSION_NUMBER -m "${{ steps.generate_tag_message.outputs.description }}" + git push origin $VERSION_NUMBER + + - name: Create draft release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ steps.generate_tag_message.outputs.version_number }} + release_name: Release ${{ steps.generate_tag_message.outputs.version_number }} + body: ${{ steps.generate_tag_message.outputs.description }} + draft: true From fff5352edc4913f046bde10f4504976c25991993 Mon Sep 17 00:00:00 2001 From: FMorschel <52160996+FMorschel@users.noreply.github.com> Date: Tue, 12 Dec 2023 14:37:03 -0300 Subject: [PATCH 15/16] Removing old workflow --- .github/workflows/build.yml | 68 ------------------------------------- 1 file changed, 68 deletions(-) delete mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 43a310f..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,68 +0,0 @@ -name: Build - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - uses: dart-lang/setup-dart@v1 - with: - sdk: main - - - name: Install dependencies - run: dart pub get - - - name: Check format - run: dart format --output=none --set-exit-if-changed -l 80 lib - - - name: Analyze - run: dart analyze lib - - - name: Run tests - run: dart test --coverage coverage --reporter=github - - - name: Coverage - run: dart run coverage:format_coverage -l -i ./coverage/test/due_date_test.dart.vm.json -o ./coverage/lcov.info - - - name: Upload coverage to codecov - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} - fail_ci_if_error: true # optional (default = false) - verbose: true # optional (default = false) - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - - update-docs: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: dart-lang/setup-dart@v1 - with: - sdk: main - - name: Generate docs - run: dart doc - - name: Checkout gh-pages branch - run: | - git fetch - git checkout gh-pages - - name: Clear base folder - run: | - rm -rf * - - name: Copy docs to base folder - run: | - cp -r ../doc/api/* . - - name: Commit and push - run: | - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - git add . - git commit -m "Update documentation" -a - git push \ No newline at end of file From 063f48fb751d4693b7339c7d67d5f5de8b6a253e Mon Sep 17 00:00:00 2001 From: FMorschel <52160996+FMorschel@users.noreply.github.com> Date: Tue, 12 Dec 2023 17:00:23 -0300 Subject: [PATCH 16/16] Renaming branch on Dart CI --- .github/workflows/dart.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index 5597c90..8fc6a22 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -2,9 +2,11 @@ name: Dart CI on: push: - branches: [ master ] + branches: + - main pull_request: - branches: [ master ] + branches: + - main jobs: build: