diff --git a/app/lib/grades/grades_service/grades_service.dart b/app/lib/grades/grades_service/grades_service.dart index e0cd4b045..c8b5ad4c0 100644 --- a/app/lib/grades/grades_service/grades_service.dart +++ b/app/lib/grades/grades_service/grades_service.dart @@ -382,6 +382,38 @@ class GradesService { _updateState(newState); } + /// Edits properties of a custom grade type. + /// + /// Throws [ArgumentError] if the [displayName] is empty. + /// + /// Throws [GradeTypeNotFoundException] if the grade type with the given [id] + /// does not exist. + /// + /// Throws [ArgumentError] if the grade type with the given [id] is a + /// predefined grade type. + void editCustomGradeType( + {required GradeTypeId id, required String displayName}) { + if (displayName.isEmpty) { + throw ArgumentError('The display name must not be empty.'); + } + + final isPredefinedGradeType = + GradeType.predefinedGradeTypes.map((gt) => gt.id).contains(id); + if (isPredefinedGradeType) { + throw ArgumentError('Cannot edit a predefined grade type.'); + } + if (!_hasGradeTypeWithId(id)) { + throw GradeTypeNotFoundException(id); + } + + final newCustomGradeTypes = _customGradeTypes.replaceAllWhere( + (element) => element.id == id, + GradeType(id: id, displayName: displayName)); + + final newState = _state.copyWith(customGradeTypes: newCustomGradeTypes); + _updateState(newState); + } + /// Deletes a custom grade type and removes it from all weight maps. /// /// A custom grade type can only be deleted if it is not assigned to any grade diff --git a/app/test/grades/grade_types_test.dart b/app/test/grades/grade_types_test.dart index 293a4835c..5f52e15a2 100644 --- a/app/test/grades/grade_types_test.dart +++ b/app/test/grades/grade_types_test.dart @@ -371,5 +371,68 @@ void main() { expect(gradeTypeIds, containsOnce(const GradeTypeId('custom'))); expect(gradeTypeIds, containsOnce(GradeType.oralParticipation.id)); }); + test('Trying to edit a predefined grade type will throw an ArgumentError', + () { + final controller = GradesTestController(); + + for (final gradeType in controller.getPossibleGradeTypes()) { + expect( + () => controller.editCustomGradeType(gradeType.id, + displayName: 'foo'), + throwsArgumentError); + } + }); + test( + 'Trying to edit an unknown custom grade type will throw an $GradeTypeNotFoundException', + () { + final controller = GradesTestController(); + + expect( + () => controller.editCustomGradeType(const GradeTypeId('foo'), + displayName: 'foo'), + throwsA(const GradeTypeNotFoundException(GradeTypeId('foo')))); + }); + test('One can change the name of a custom grade type', () { + final controller = GradesTestController(); + controller.createCustomGradeType( + const GradeType(id: GradeTypeId('foo'), displayName: 'foo')); + + controller.createTerm(termWith( + id: const TermId('foo'), + finalGradeType: const GradeTypeId('foo'), + subjects: [ + subjectWith( + id: const SubjectId('bar'), + finalGradeType: const GradeTypeId('foo'), + grades: [ + gradeWith( + id: const GradeId('bar'), + type: const GradeTypeId('foo'), + value: 3, + ), + ], + ), + ], + )); + + controller.editCustomGradeType(const GradeTypeId('foo'), + displayName: 'bar'); + + expect(controller.getCustomGradeTypes().single.displayName, 'bar'); + expect(controller.term(const TermId('foo')).finalGradeType.displayName, + 'bar'); + }); + test( + 'Trying to edit the name of a custom grade type to an empty string throws an $ArgumentError', + () { + final controller = GradesTestController(); + controller.createCustomGradeType( + const GradeType(id: GradeTypeId('foo'), displayName: 'foo')); + + expect( + () => controller.editCustomGradeType(const GradeTypeId('foo'), + displayName: ''), + throwsArgumentError); + }); }); } diff --git a/app/test/grades/grades_test_common.dart b/app/test/grades/grades_test_common.dart index 2215654ee..d9058e69c 100644 --- a/app/test/grades/grades_test_common.dart +++ b/app/test/grades/grades_test_common.dart @@ -307,6 +307,10 @@ class GradesTestController { {required TermId termId, required GradeTypeId gradeTypeId}) { service.editTerm(id: termId, finalGradeType: gradeTypeId); } + + void editCustomGradeType(GradeTypeId id, {required String displayName}) { + service.editCustomGradeType(id: id, displayName: displayName); + } } TestTerm termWith({