From 7bfe67e65a99d7f3699238010d1a91d73e39301b Mon Sep 17 00:00:00 2001 From: Sergey Dmitriev <51058739+0niel@users.noreply.github.com> Date: Wed, 3 Jan 2024 13:26:06 +0300 Subject: [PATCH] feat: Create `academic_calendar` package --- .../.github/ISSUE_TEMPLATE/bug_report.md | 29 ++++++ .../.github/ISSUE_TEMPLATE/build.md | 14 +++ .../.github/ISSUE_TEMPLATE/chore.md | 14 +++ .../.github/ISSUE_TEMPLATE/ci.md | 14 +++ .../.github/ISSUE_TEMPLATE/config.yml | 1 + .../.github/ISSUE_TEMPLATE/documentation.md | 14 +++ .../.github/ISSUE_TEMPLATE/feature_request.md | 18 ++++ .../.github/ISSUE_TEMPLATE/performance.md | 14 +++ .../.github/ISSUE_TEMPLATE/refactor.md | 14 +++ .../.github/ISSUE_TEMPLATE/revert.md | 16 ++++ .../.github/ISSUE_TEMPLATE/style.md | 14 +++ .../.github/ISSUE_TEMPLATE/test.md | 14 +++ .../.github/PULL_REQUEST_TEMPLATE.md | 27 ++++++ .../academic_calendar/.github/cspell.json | 21 ++++ .../academic_calendar/.github/dependabot.yaml | 11 +++ .../.github/workflows/main.yaml | 27 ++++++ packages/academic_calendar/.gitignore | 7 ++ packages/academic_calendar/README.md | 62 ++++++++++++ .../academic_calendar/analysis_options.yaml | 1 + packages/academic_calendar/coverage_badge.svg | 20 ++++ .../lib/academic_calendar.dart | 4 + .../lib/src/academic_calendar.dart | 95 +++++++++++++++++++ packages/academic_calendar/pubspec.yaml | 15 +++ .../test/src/academic_calendar_test.dart | 58 +++++++++++ 24 files changed, 524 insertions(+) create mode 100644 packages/academic_calendar/.github/ISSUE_TEMPLATE/bug_report.md create mode 100644 packages/academic_calendar/.github/ISSUE_TEMPLATE/build.md create mode 100644 packages/academic_calendar/.github/ISSUE_TEMPLATE/chore.md create mode 100644 packages/academic_calendar/.github/ISSUE_TEMPLATE/ci.md create mode 100644 packages/academic_calendar/.github/ISSUE_TEMPLATE/config.yml create mode 100644 packages/academic_calendar/.github/ISSUE_TEMPLATE/documentation.md create mode 100644 packages/academic_calendar/.github/ISSUE_TEMPLATE/feature_request.md create mode 100644 packages/academic_calendar/.github/ISSUE_TEMPLATE/performance.md create mode 100644 packages/academic_calendar/.github/ISSUE_TEMPLATE/refactor.md create mode 100644 packages/academic_calendar/.github/ISSUE_TEMPLATE/revert.md create mode 100644 packages/academic_calendar/.github/ISSUE_TEMPLATE/style.md create mode 100644 packages/academic_calendar/.github/ISSUE_TEMPLATE/test.md create mode 100644 packages/academic_calendar/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 packages/academic_calendar/.github/cspell.json create mode 100644 packages/academic_calendar/.github/dependabot.yaml create mode 100644 packages/academic_calendar/.github/workflows/main.yaml create mode 100644 packages/academic_calendar/.gitignore create mode 100644 packages/academic_calendar/README.md create mode 100644 packages/academic_calendar/analysis_options.yaml create mode 100644 packages/academic_calendar/coverage_badge.svg create mode 100644 packages/academic_calendar/lib/academic_calendar.dart create mode 100644 packages/academic_calendar/lib/src/academic_calendar.dart create mode 100644 packages/academic_calendar/pubspec.yaml create mode 100644 packages/academic_calendar/test/src/academic_calendar_test.dart diff --git a/packages/academic_calendar/.github/ISSUE_TEMPLATE/bug_report.md b/packages/academic_calendar/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..50a4c7b8 --- /dev/null +++ b/packages/academic_calendar/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,29 @@ +--- +name: Bug Report +about: Create a report to help us improve +title: "fix: " +labels: bug +--- + +**Description** + +A clear and concise description of what the bug is. + +**Steps To Reproduce** + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected Behavior** + +A clear and concise description of what you expected to happen. + +**Screenshots** + +If applicable, add screenshots to help explain your problem. + +**Additional Context** + +Add any other context about the problem here. diff --git a/packages/academic_calendar/.github/ISSUE_TEMPLATE/build.md b/packages/academic_calendar/.github/ISSUE_TEMPLATE/build.md new file mode 100644 index 00000000..0cf8e62c --- /dev/null +++ b/packages/academic_calendar/.github/ISSUE_TEMPLATE/build.md @@ -0,0 +1,14 @@ +--- +name: Build System +about: Changes that affect the build system or external dependencies +title: "build: " +labels: build +--- + +**Description** + +Describe what changes need to be done to the build system and why. + +**Requirements** + +- [ ] The build system is passing diff --git a/packages/academic_calendar/.github/ISSUE_TEMPLATE/chore.md b/packages/academic_calendar/.github/ISSUE_TEMPLATE/chore.md new file mode 100644 index 00000000..498ebfd8 --- /dev/null +++ b/packages/academic_calendar/.github/ISSUE_TEMPLATE/chore.md @@ -0,0 +1,14 @@ +--- +name: Chore +about: Other changes that don't modify src or test files +title: "chore: " +labels: chore +--- + +**Description** + +Clearly describe what change is needed and why. If this changes code then please use another issue type. + +**Requirements** + +- [ ] No functional changes to the code diff --git a/packages/academic_calendar/.github/ISSUE_TEMPLATE/ci.md b/packages/academic_calendar/.github/ISSUE_TEMPLATE/ci.md new file mode 100644 index 00000000..fa2dd9e2 --- /dev/null +++ b/packages/academic_calendar/.github/ISSUE_TEMPLATE/ci.md @@ -0,0 +1,14 @@ +--- +name: Continuous Integration +about: Changes to the CI configuration files and scripts +title: "ci: " +labels: ci +--- + +**Description** + +Describe what changes need to be done to the ci/cd system and why. + +**Requirements** + +- [ ] The ci system is passing diff --git a/packages/academic_calendar/.github/ISSUE_TEMPLATE/config.yml b/packages/academic_calendar/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..ec4bb386 --- /dev/null +++ b/packages/academic_calendar/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false \ No newline at end of file diff --git a/packages/academic_calendar/.github/ISSUE_TEMPLATE/documentation.md b/packages/academic_calendar/.github/ISSUE_TEMPLATE/documentation.md new file mode 100644 index 00000000..f494a4d9 --- /dev/null +++ b/packages/academic_calendar/.github/ISSUE_TEMPLATE/documentation.md @@ -0,0 +1,14 @@ +--- +name: Documentation +about: Improve the documentation so all collaborators have a common understanding +title: "docs: " +labels: documentation +--- + +**Description** + +Clearly describe what documentation you are looking to add or improve. + +**Requirements** + +- [ ] Requirements go here diff --git a/packages/academic_calendar/.github/ISSUE_TEMPLATE/feature_request.md b/packages/academic_calendar/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..ddd2fcca --- /dev/null +++ b/packages/academic_calendar/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,18 @@ +--- +name: Feature Request +about: A new feature to be added to the project +title: "feat: " +labels: feature +--- + +**Description** + +Clearly describe what you are looking to add. The more context the better. + +**Requirements** + +- [ ] Checklist of requirements to be fulfilled + +**Additional Context** + +Add any other context or screenshots about the feature request go here. diff --git a/packages/academic_calendar/.github/ISSUE_TEMPLATE/performance.md b/packages/academic_calendar/.github/ISSUE_TEMPLATE/performance.md new file mode 100644 index 00000000..699b8d45 --- /dev/null +++ b/packages/academic_calendar/.github/ISSUE_TEMPLATE/performance.md @@ -0,0 +1,14 @@ +--- +name: Performance Update +about: A code change that improves performance +title: "perf: " +labels: performance +--- + +**Description** + +Clearly describe what code needs to be changed and what the performance impact is going to be. Bonus point's if you can tie this directly to user experience. + +**Requirements** + +- [ ] There is no drop in test coverage. diff --git a/packages/academic_calendar/.github/ISSUE_TEMPLATE/refactor.md b/packages/academic_calendar/.github/ISSUE_TEMPLATE/refactor.md new file mode 100644 index 00000000..1626c570 --- /dev/null +++ b/packages/academic_calendar/.github/ISSUE_TEMPLATE/refactor.md @@ -0,0 +1,14 @@ +--- +name: Refactor +about: A code change that neither fixes a bug nor adds a feature +title: "refactor: " +labels: refactor +--- + +**Description** + +Clearly describe what needs to be refactored and why. Please provide links to related issues (bugs or upcoming features) in order to help prioritize. + +**Requirements** + +- [ ] There is no drop in test coverage. diff --git a/packages/academic_calendar/.github/ISSUE_TEMPLATE/revert.md b/packages/academic_calendar/.github/ISSUE_TEMPLATE/revert.md new file mode 100644 index 00000000..9d121dc5 --- /dev/null +++ b/packages/academic_calendar/.github/ISSUE_TEMPLATE/revert.md @@ -0,0 +1,16 @@ +--- +name: Revert Commit +about: Reverts a previous commit +title: "revert: " +labels: revert +--- + +**Description** + +Provide a link to a PR/Commit that you are looking to revert and why. + +**Requirements** + +- [ ] Change has been reverted +- [ ] No change in test coverage has happened +- [ ] A new ticket is created for any follow on work that needs to happen diff --git a/packages/academic_calendar/.github/ISSUE_TEMPLATE/style.md b/packages/academic_calendar/.github/ISSUE_TEMPLATE/style.md new file mode 100644 index 00000000..02244a7b --- /dev/null +++ b/packages/academic_calendar/.github/ISSUE_TEMPLATE/style.md @@ -0,0 +1,14 @@ +--- +name: Style Changes +about: Changes that do not affect the meaning of the code (white space, formatting, missing semi-colons, etc) +title: "style: " +labels: style +--- + +**Description** + +Clearly describe what you are looking to change and why. + +**Requirements** + +- [ ] There is no drop in test coverage. diff --git a/packages/academic_calendar/.github/ISSUE_TEMPLATE/test.md b/packages/academic_calendar/.github/ISSUE_TEMPLATE/test.md new file mode 100644 index 00000000..431a7ea7 --- /dev/null +++ b/packages/academic_calendar/.github/ISSUE_TEMPLATE/test.md @@ -0,0 +1,14 @@ +--- +name: Test +about: Adding missing tests or correcting existing tests +title: "test: " +labels: test +--- + +**Description** + +List out the tests that need to be added or changed. Please also include any information as to why this was not covered in the past. + +**Requirements** + +- [ ] There is no drop in test coverage. diff --git a/packages/academic_calendar/.github/PULL_REQUEST_TEMPLATE.md b/packages/academic_calendar/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..11699363 --- /dev/null +++ b/packages/academic_calendar/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,27 @@ + + +## Status + +**READY/IN DEVELOPMENT/HOLD** + +## Description + + + +## Type of Change + + + +- [ ] โœจ New feature (non-breaking change which adds functionality) +- [ ] ๐Ÿ› ๏ธ Bug fix (non-breaking change which fixes an issue) +- [ ] โŒ Breaking change (fix or feature that would cause existing functionality to change) +- [ ] ๐Ÿงน Code refactor +- [ ] โœ… Build configuration change +- [ ] ๐Ÿ“ Documentation +- [ ] ๐Ÿ—‘๏ธ Chore diff --git a/packages/academic_calendar/.github/cspell.json b/packages/academic_calendar/.github/cspell.json new file mode 100644 index 00000000..e529a5a2 --- /dev/null +++ b/packages/academic_calendar/.github/cspell.json @@ -0,0 +1,21 @@ +{ + "version": "0.2", + "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json", + "dictionaries": ["vgv_allowed", "vgv_forbidden"], + "dictionaryDefinitions": [ + { + "name": "vgv_allowed", + "path": "https://raw.githubusercontent.com/verygoodopensource/very_good_dictionaries/main/allowed.txt", + "description": "Allowed VGV Spellings" + }, + { + "name": "vgv_forbidden", + "path": "https://raw.githubusercontent.com/verygoodopensource/very_good_dictionaries/main/forbidden.txt", + "description": "Forbidden VGV Spellings" + } + ], + "useGitignore": true, + "words": [ + "academic_calendar" + ] +} diff --git a/packages/academic_calendar/.github/dependabot.yaml b/packages/academic_calendar/.github/dependabot.yaml new file mode 100644 index 00000000..63b035cd --- /dev/null +++ b/packages/academic_calendar/.github/dependabot.yaml @@ -0,0 +1,11 @@ +version: 2 +enable-beta-ecosystems: true +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + - package-ecosystem: "pub" + directory: "/" + schedule: + interval: "daily" diff --git a/packages/academic_calendar/.github/workflows/main.yaml b/packages/academic_calendar/.github/workflows/main.yaml new file mode 100644 index 00000000..c7146c3c --- /dev/null +++ b/packages/academic_calendar/.github/workflows/main.yaml @@ -0,0 +1,27 @@ +name: ci + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + semantic_pull_request: + uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/semantic_pull_request.yml@v1 + + spell-check: + uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/spell_check.yml@v1 + with: + includes: "**/*.md" + modified_files_only: false + + build: + uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_package.yml@v1 + diff --git a/packages/academic_calendar/.gitignore b/packages/academic_calendar/.gitignore new file mode 100644 index 00000000..526da158 --- /dev/null +++ b/packages/academic_calendar/.gitignore @@ -0,0 +1,7 @@ +# See https://www.dartlang.org/guides/libraries/private-files + +# Files and directories created by pub +.dart_tool/ +.packages +build/ +pubspec.lock \ No newline at end of file diff --git a/packages/academic_calendar/README.md b/packages/academic_calendar/README.md new file mode 100644 index 00000000..765f282f --- /dev/null +++ b/packages/academic_calendar/README.md @@ -0,0 +1,62 @@ +# Academic Calendar + +[![style: very good analysis][very_good_analysis_badge]][very_good_analysis_link] +[![Powered by Mason](https://img.shields.io/endpoint?url=https%3A%2F%2Ftinyurl.com%2Fmason-badge)](https://github.com/felangel/mason) +[![License: MIT][license_badge]][license_link] + +A Very Good Project created by Very Good CLI. + +## Installation ๐Ÿ’ป + +**โ— In order to start using Academic Calendar you must have the [Dart SDK][dart_install_link] installed on your machine.** + +Install via `dart pub add`: + +```sh +dart pub add academic_calendar +``` + +--- + +## Continuous Integration ๐Ÿค– + +Academic Calendar comes with a built-in [GitHub Actions workflow][github_actions_link] powered by [Very Good Workflows][very_good_workflows_link] but you can also add your preferred CI/CD solution. + +Out of the box, on each pull request and push, the CI `formats`, `lints`, and `tests` the code. This ensures the code remains consistent and behaves correctly as you add functionality or make changes. The project uses [Very Good Analysis][very_good_analysis_link] for a strict set of analysis options used by our team. Code coverage is enforced using the [Very Good Workflows][very_good_coverage_link]. + +--- + +## Running Tests ๐Ÿงช + +To run all unit tests: + +```sh +dart pub global activate coverage 1.2.0 +dart test --coverage=coverage +dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info +``` + +To view the generated coverage report you can use [lcov](https://github.com/linux-test-project/lcov). + +```sh +# Generate Coverage Report +genhtml coverage/lcov.info -o coverage/ + +# Open Coverage Report +open coverage/index.html +``` + +[dart_install_link]: https://dart.dev/get-dart +[github_actions_link]: https://docs.github.com/en/actions/learn-github-actions +[license_badge]: https://img.shields.io/badge/license-MIT-blue.svg +[license_link]: https://opensource.org/licenses/MIT +[logo_black]: https://raw.githubusercontent.com/VGVentures/very_good_brand/main/styles/README/vgv_logo_black.png#gh-light-mode-only +[logo_white]: https://raw.githubusercontent.com/VGVentures/very_good_brand/main/styles/README/vgv_logo_white.png#gh-dark-mode-only +[mason_link]: https://github.com/felangel/mason +[very_good_analysis_badge]: https://img.shields.io/badge/style-very_good_analysis-B22C89.svg +[very_good_analysis_link]: https://pub.dev/packages/very_good_analysis +[very_good_coverage_link]: https://github.com/marketplace/actions/very-good-coverage +[very_good_ventures_link]: https://verygood.ventures +[very_good_ventures_link_light]: https://verygood.ventures#gh-light-mode-only +[very_good_ventures_link_dark]: https://verygood.ventures#gh-dark-mode-only +[very_good_workflows_link]: https://github.com/VeryGoodOpenSource/very_good_workflows diff --git a/packages/academic_calendar/analysis_options.yaml b/packages/academic_calendar/analysis_options.yaml new file mode 100644 index 00000000..799268d3 --- /dev/null +++ b/packages/academic_calendar/analysis_options.yaml @@ -0,0 +1 @@ +include: package:very_good_analysis/analysis_options.5.1.0.yaml diff --git a/packages/academic_calendar/coverage_badge.svg b/packages/academic_calendar/coverage_badge.svg new file mode 100644 index 00000000..499e98ce --- /dev/null +++ b/packages/academic_calendar/coverage_badge.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + coverage + coverage + 100% + 100% + + diff --git a/packages/academic_calendar/lib/academic_calendar.dart b/packages/academic_calendar/lib/academic_calendar.dart new file mode 100644 index 00000000..febceb4e --- /dev/null +++ b/packages/academic_calendar/lib/academic_calendar.dart @@ -0,0 +1,4 @@ +/// A library with a set of functions to work with academic calendars. +library academic_calendar; + +export 'src/academic_calendar.dart'; diff --git a/packages/academic_calendar/lib/src/academic_calendar.dart b/packages/academic_calendar/lib/src/academic_calendar.dart new file mode 100644 index 00000000..525c6dbd --- /dev/null +++ b/packages/academic_calendar/lib/src/academic_calendar.dart @@ -0,0 +1,95 @@ +import 'package:intl/intl.dart'; + +const maxWeeksInSemester = 18; + +class Period { + Period({ + required this.yearStart, + required this.yearEnd, + required this.semester, + }); + int yearStart; + int yearEnd; + int semester; +} + +Period getPeriod(DateTime date) { + if (date.month >= 7) { + return Period(yearStart: date.year, yearEnd: date.year + 1, semester: 1); + } else { + return Period(yearStart: date.year - 1, yearEnd: date.year, semester: 2); + } +} + +/// Returns the academic week number for the given date. if date is null, the +/// current date is used. +int getWeek([DateTime? date]) { + final now = date ?? DateTime.now(); + final startDate = getSemesterStart(now); + + if (now.millisecondsSinceEpoch < startDate.millisecondsSinceEpoch) { + return 1; + } + + var week = now.weekOfYear - startDate.weekOfYear; + + week += 1; + + return week; +} + +DateTime getDayByWeek(Period period, int weekday, int week) { + final startDate = getSemesterStart( + DateTime(period.yearStart, period.semester == 1 ? 9 : 2), + ); + + if (week == 1) { + return startDate.add(Duration(days: weekday - startDate.weekday)); + } + + return startDate.add( + Duration( + days: 7 * (week - 1) + weekday - startDate.weekday, + ), + ); +} + +DateTime getSemesterStart(DateTime date) { + if (date.month >= 9) { + var startDate = DateTime(date.year, 9); + if (startDate.weekday == DateTime.sunday) { + startDate = startDate.add(const Duration(days: 1)); + } + return startDate; + } + + var startDate = DateTime(date.year, 2); + startDate = startDate.add(const Duration(days: 8)); + + if (startDate.weekday == DateTime.sunday) { + startDate = startDate.add(const Duration(days: 1)); + } + + return startDate; +} + +extension DateTimeExtension on DateTime { + /// Calculates number of weeks for a given year as per https://en.wikipedia.org/wiki/ISO_week_date#Weeks_per_year + int _numOfWeeks(int year) { + final dec28 = DateTime(year, 12, 28); + final dayOfDec28 = int.parse(DateFormat('D').format(dec28)); + return ((dayOfDec28 - dec28.weekday + 10) / 7).floor(); + } + + /// Calculates week number from a date as per https://en.wikipedia.org/wiki/ISO_week_date#Calculation + int get weekOfYear { + final dayOfYear = int.parse(DateFormat('D').format(this)); + var woy = ((dayOfYear - weekday + 10) / 7).floor(); + if (woy < 1) { + woy = _numOfWeeks(year - 1); + } else if (woy > _numOfWeeks(year)) { + woy = 1; + } + return woy; + } +} diff --git a/packages/academic_calendar/pubspec.yaml b/packages/academic_calendar/pubspec.yaml new file mode 100644 index 00000000..cfa791a1 --- /dev/null +++ b/packages/academic_calendar/pubspec.yaml @@ -0,0 +1,15 @@ +name: academic_calendar +description: Utility for working with academic calendars. +version: 0.1.0+1 +publish_to: none + +environment: + sdk: ">=3.0.0 <4.0.0" + +dependencies: + intl: ^0.19.0 + +dev_dependencies: + mocktail: ^1.0.0 + test: ^1.19.2 + very_good_analysis: ^5.1.0 diff --git a/packages/academic_calendar/test/src/academic_calendar_test.dart b/packages/academic_calendar/test/src/academic_calendar_test.dart new file mode 100644 index 00000000..b10c3584 --- /dev/null +++ b/packages/academic_calendar/test/src/academic_calendar_test.dart @@ -0,0 +1,58 @@ +import 'package:academic_calendar/academic_calendar.dart'; +import 'package:test/test.dart'; + +void main() { + group('AcademicCalendar', () { + test('getPeriod returns correct period for given date', () { + final period1 = getPeriod(DateTime(2022, 9)); + expect(period1.yearStart, 2022); + expect(period1.yearEnd, 2023); + expect(period1.semester, 1); + + final period2 = getPeriod(DateTime(2022, 2)); + expect(period2.yearStart, 2021); + expect(period2.yearEnd, 2022); + expect(period2.semester, 2); + }); + + test('getWeek returns correct week number for given date', () { + final week1 = getWeek(DateTime(2022, 9)); + expect(week1, 1); + + final week2 = getWeek(DateTime(2022, 9, 6)); + expect(week2, 2); + + final week3 = getWeek(DateTime(2023, 9, 4)); + expect(week3, 2); + + final week4 = getWeek(DateTime(2023, 9, 5)); + expect(week4, 2); + + final week5 = getWeek(DateTime(2023, 9, 9)); + expect(week5, 2); + + final week6 = getWeek(DateTime(2023, 9, 10)); + expect(week6, 2); + + final week7 = getWeek(DateTime(2023, 9, 11)); + expect(week7, 3); + + final week8 = getWeek(DateTime(2023, 9, 17)); + expect(week8, 3); + + final week9 = getWeek(DateTime(2023, 9, 18)); + expect(week9, 4); + + final week10 = getWeek(DateTime(2023, 11, 29)); + expect(week10, 14); + }); + + test('getSemesterStart returns correct start date for given date', () { + final startDate1 = getSemesterStart(DateTime(2022, 9)); + expect(startDate1, DateTime(2022, 9)); + + final startDate2 = getSemesterStart(DateTime(2022, 2)); + expect(startDate2, DateTime(2022, 2, 9)); + }); + }); +}