namespace ExamCalendar.Test; public sealed class ExamListTests { private readonly ExamList _list = new(); [Fact] public void Construction() { _list.Count.Should().Be(0, "initially empty"); } [Fact] public void Insert_Single() { _list.Insert(CreateExam("M", new DateTime(2022, 11, 17))) .Should().BeTrue("insert successful"); _list.Count.Should().Be(1); } [Fact] public void Insert_Retrieve_Single() { var exam = CreateExam("M", new DateTime(2022, 11, 17)); _list.Insert(exam); _list.GetAt(0).Should() .NotBeNull("one exam has been inserted, index 0 exists") .And.BeSameAs(exam, "same reference is returned"); } [Fact] public void Insert_Multiple_Sorted_InsertBefore() { _list.Insert(CreateExam("LOAL", new DateTime(2022, 11, 22))); var exam = CreateExam("M", new DateTime(2022, 11, 17)); _list.Insert(exam); _list.GetAt(0) .Should().NotBeNull() .And.BeSameAs(exam, "earlier exam inserted before later exam"); _list.Count.Should().Be(2, "two exams inserted"); } [Fact] public void Insert_Multiple_Sorted_InsertAfter() { _list.Insert(CreateExam("LOAL", new DateTime(2022, 11, 17))); var exam = CreateExam("M", new DateTime(2022, 11, 21)); _list.Insert(exam); _list.GetAt(1) .Should().NotBeNull() .And.BeSameAs(exam, "later exam inserted at end"); _list.Count.Should().Be(2); } [Fact] public void Insert_Multiple_Sorted_InsertBetween() { _list.Insert(CreateExam("LOAL", new DateTime(2022, 11, 17))); _list.Insert(CreateExam("D", new DateTime(2022, 11, 21))); var exam = CreateExam("M", new DateTime(2022, 11, 18)); _list.Insert(exam); _list.GetAt(1) .Should().NotBeNull() .And.BeSameAs(exam, "inserted between earlier and later exams"); CheckSubject(0, "LOAL"); CheckSubject(2, "D"); _list.Count.Should().Be(3); } [Fact] public void Insert_Multiple() { _list.Insert(CreateExam("LOAL", new DateTime(2022, 11, 17))); _list.Insert(CreateExam("D", new DateTime(2022, 11, 21))); _list.Insert(CreateExam("PR", new DateTime(2022, 11, 30))); _list.Insert(CreateExam("E", new DateTime(2022, 11, 10))); var exam = CreateExam("M", new DateTime(2022, 11, 18)); _list.Insert(exam); foreach (var (idx, subject) in new[] { (0, "E"), (1, "LOAL"), (2, "M"), (3, "D"), (4, "PR") }) { CheckSubject(idx, subject); } } [Fact] public void ToArray_Filled() { InsertSampleExams(); var examArray = _list.ToArray(); examArray.Length.Should().Be(5, "contains all exams in the list"); } [Fact] public void ToArray_Empty() { var examArray = _list.ToArray(); examArray.Length.Should().Be(0, "list is empty"); } [Fact] public void Interval_To() { InsertSampleExams(); var searchResult = _list.GetTestsInInterval(new DateTime(2022, 11, 16), new DateTime(2022, 11, 21)); searchResult.Length.Should().Be(3); searchResult[0].Subject.Should().NotBeNull().And.Be("LOAL"); searchResult[2].Subject.Should().NotBeNull().And.Be("D"); } [Fact] public void Interval_From() { InsertSampleExams(); var searchResult = _list.GetTestsInInterval(new DateTime(2022, 11, 17), new DateTime(2022, 11, 22)); searchResult.Length.Should().Be(3); searchResult[0].Subject.Should().NotBeNull().And.Be("LOAL"); searchResult[2].Subject.Should().NotBeNull().And.Be("D"); } [Fact] public void Interval_FromTo_Open() { InsertSampleExams(); var searchResult = _list.GetTestsInInterval(new DateTime(2022, 11, 16), new DateTime(2022, 11, 22)); searchResult.Length.Should().Be(3); } [Fact] public void Interval_FromTo_Exact() { InsertSampleExams(); var searchResult = _list.GetTestsInInterval(new DateTime(2022, 11, 17), new DateTime(2022, 11, 21)); searchResult.Length.Should().Be(3); } [Fact] public void Interval_EarlyFrom() { InsertSampleExams(); var searchResult = _list.GetTestsInInterval(new DateTime(2022, 11, 01), new DateTime(2022, 11, 22)); searchResult.Length.Should().Be(4); } [Fact] public void Interval_LateTo() { InsertSampleExams(); var searchResult = _list.GetTestsInInterval(new DateTime(2022, 11, 19), new DateTime(2022, 12, 09)); searchResult.Length.Should().Be(2); } [Fact] public void Interval_TooEarly() { InsertSampleExams(); var searchResult = _list.GetTestsInInterval(new DateTime(2022, 11, 01), new DateTime(2022, 11, 09)); searchResult.Length.Should().Be(0); } [Fact] public void Interval_TooLate() { InsertSampleExams(); var searchResult = _list.GetTestsInInterval(new DateTime(2022, 12, 01), new DateTime(2022, 12, 09)); searchResult.Length.Should().Be(0); } [Fact] public void Interval_BetweenExams() { InsertSampleExams(); var searchResult = _list.GetTestsInInterval(new DateTime(2022, 11, 22), new DateTime(2022, 11, 29)); searchResult.Length.Should().Be(0); } [Fact] public void Interval_InvalidDateSpan() { InsertSampleExams(); var searchResult = _list.GetTestsInInterval(new DateTime(2022, 12, 01), new DateTime(2022, 11, 10)); searchResult.Length.Should().Be(0, "from > to"); } [Fact] public void Insert_SameDateTwice() { _list.Insert(CreateExam("E", new DateTime(2022, 11, 10))); _list.Insert(CreateExam("LOAL", new DateTime(2022, 11, 17))); _list.Insert(CreateExam("M", new DateTime(2022, 11, 18))); _list.Insert(CreateExam("D", new DateTime(2022, 11, 21))); _list.Insert(CreateExam("PR", new DateTime(2022, 11, 17))) .Should().BeFalse("Date is already taken"); var searchResult = _list.GetTestsInInterval(DateTime.MinValue, new DateTime(2022, 11, 21)); searchResult.Length.Should().Be(4, "exam with duplicate date not added"); } [Fact] public void Insert_Saturday() { _list.Insert(CreateExam("M", new DateTime(2022, 11, 19))) .Should().BeFalse("exam cannot happen on a Saturday"); _list.Count.Should().Be(0); } [Theory] [InlineData("")] [InlineData(null)] public void Insert_InvalidSubject(string? subject) { _list.Insert(new Exam(subject, new DateTime(2022, 11, 17), "HASLM")) .Should().BeFalse("invalid subject"); } [Fact] public void Insert_Null() { _list.Insert(null) .Should().BeFalse("cannot insert null"); } [Fact] public void Remove_Exists() { _list.Insert(CreateExam("E", new DateTime(2022, 11, 10))); _list.Insert(CreateExam("LOAL", new DateTime(2022, 11, 17))); var exam = CreateExam("M", new DateTime(2022, 11, 18)); _list.Insert(exam); _list.Insert(CreateExam("D", new DateTime(2022, 11, 21))); _list.Insert(CreateExam("PR", new DateTime(2022, 11, 30))); _list.Remove(new DateTime(2022, 11, 18), out var examRemoved) .Should().BeTrue("exam existed and could be removed"); examRemoved.Should() .NotBeNull("found") .And.BeSameAs(exam, "correct one removed"); _list.Count.Should().Be(4, "one removed"); _list.ToArray().Length.Should().Be(4); } [Fact] public void Remove_Empty() { _list.Remove(new DateTime(2022, 11, 18), out var examRemoved) .Should().BeFalse("list is empty"); examRemoved.Should().BeNull("cannot remove from empty list"); _list.Count.Should().Be(0); } [Fact] public void Remove_First() { InsertSampleExams(); var firstExam = _list.GetAt(0); _list.Count.Should().Be(5); firstExam.Should().NotBeNull(); _list.Remove(firstExam!.Date, out var examRemoved) .Should().BeTrue("exam was found and removed"); examRemoved.Should().NotBeNull() .And.BeSameAs(firstExam, "correct exam removed"); _list.Count.Should().Be(4); _list.ToArray().Length.Should().Be(4); } [Fact] public void Remove_Last() { InsertSampleExams(); var lastExam = _list.GetAt(_list.Count - 1); lastExam.Should().NotBeNull(); _list.Remove(lastExam!.Date, out var examRemoved) .Should().BeTrue("exam was found and removed"); examRemoved.Should().NotBeNull() .And.BeSameAs(lastExam, "correct exam removed"); _list.Count.Should().Be(4); } [Fact] public void Remove_Single() { var exam = CreateExam("E", new DateTime(2022, 11, 10)); _list.Insert(exam); _list.Count.Should().Be(1); _list.Remove(exam.Date, out var removedExam) .Should().BeTrue(); _list.Count.Should().Be(0); removedExam.Should().NotBeNull() .And.BeSameAs(exam); _list.ToArray().Length.Should().Be(0); } private void CheckSubject(int index, string expectedSubject) { _list.GetAt(index)?.Subject .Should().NotBeNull().And.Be(expectedSubject); } private void InsertSampleExams() { _list.Insert(CreateExam("E", new DateTime(2022, 11, 10))); _list.Insert(CreateExam("LOAL", new DateTime(2022, 11, 17))); _list.Insert(CreateExam("M", new DateTime(2022, 11, 18))); _list.Insert(CreateExam("D", new DateTime(2022, 11, 21))); _list.Insert(CreateExam("PR", new DateTime(2022, 11, 30))); } private static Exam CreateExam(string subject, DateTime date, string teacher = "HASLM") => new(subject, date, teacher); }