[ { "name": "a mark exactly on the top boundary earns the top grade", "args": [ 78, 100, [ { "grade": "9", "minMark": 78 }, { "grade": "8", "minMark": 68 }, { "grade": "7", "minMark": 58 }, { "grade": "6", "minMark": 48 }, { "grade": "5", "minMark": 39 }, { "grade": "4", "minMark": 30 }, { "grade": "3", "minMark": 21 }, { "grade": "2", "minMark": 13 }, { "grade": "1", "minMark": 5 } ] ], "expect": { "grade": "9", "minMark": 78, "nextGrade": null, "marksToNext": null } }, { "name": "one mark below a boundary is the grade beneath it", "args": [ 77, 100, [ { "grade": "9", "minMark": 78 }, { "grade": "8", "minMark": 68 }, { "grade": "7", "minMark": 58 }, { "grade": "6", "minMark": 48 }, { "grade": "5", "minMark": 39 }, { "grade": "4", "minMark": 30 }, { "grade": "3", "minMark": 21 }, { "grade": "2", "minMark": 13 }, { "grade": "1", "minMark": 5 } ] ], "expect": { "grade": "8", "minMark": 68, "nextGrade": "9", "marksToNext": 1 } }, { "name": "full marks", "args": [ 100, 100, [ { "grade": "9", "minMark": 78 }, { "grade": "8", "minMark": 68 }, { "grade": "7", "minMark": 58 }, { "grade": "6", "minMark": 48 }, { "grade": "5", "minMark": 39 }, { "grade": "4", "minMark": 30 }, { "grade": "3", "minMark": 21 }, { "grade": "2", "minMark": 13 }, { "grade": "1", "minMark": 5 } ] ], "expect": { "grade": "9", "minMark": 78, "nextGrade": null, "marksToNext": null } }, { "name": "a mid-table mark, and the marks to the next grade", "args": [ 30, 100, [ { "grade": "9", "minMark": 78 }, { "grade": "8", "minMark": 68 }, { "grade": "7", "minMark": 58 }, { "grade": "6", "minMark": 48 }, { "grade": "5", "minMark": 39 }, { "grade": "4", "minMark": 30 }, { "grade": "3", "minMark": 21 }, { "grade": "2", "minMark": 13 }, { "grade": "1", "minMark": 5 } ] ], "expect": { "grade": "4", "minMark": 30, "nextGrade": "5", "marksToNext": 9 } }, { "name": "one mark below the lowest boundary is ungraded", "args": [ 4, 100, [ { "grade": "9", "minMark": 78 }, { "grade": "8", "minMark": 68 }, { "grade": "7", "minMark": 58 }, { "grade": "6", "minMark": 48 }, { "grade": "5", "minMark": 39 }, { "grade": "4", "minMark": 30 }, { "grade": "3", "minMark": 21 }, { "grade": "2", "minMark": 13 }, { "grade": "1", "minMark": 5 } ] ], "expect": { "grade": null, "minMark": null, "nextGrade": "1", "marksToNext": 1 } }, { "name": "zero is ungraded and the whole lowest boundary away", "args": [ 0, 100, [ { "grade": "9", "minMark": 78 }, { "grade": "8", "minMark": 68 }, { "grade": "7", "minMark": 58 }, { "grade": "6", "minMark": 48 }, { "grade": "5", "minMark": 39 }, { "grade": "4", "minMark": 30 }, { "grade": "3", "minMark": 21 }, { "grade": "2", "minMark": 13 }, { "grade": "1", "minMark": 5 } ] ], "expect": { "grade": null, "minMark": null, "nextGrade": "1", "marksToNext": 5 } }, { "name": "a table in no particular order: 59 is a C, one short of a B, not the last row read", "args": [ 59, 100, [ { "grade": "C", "minMark": 50 }, { "grade": "A*", "minMark": 80 }, { "grade": "E", "minMark": 30 }, { "grade": "A", "minMark": 70 }, { "grade": "D", "minMark": 40 }, { "grade": "B", "minMark": 60 } ] ], "expect": { "grade": "C", "minMark": 50, "nextGrade": "B", "marksToNext": 1 } }, { "name": "A* at its boundary in a shuffled table", "args": [ 80, 100, [ { "grade": "C", "minMark": 50 }, { "grade": "A*", "minMark": 80 }, { "grade": "E", "minMark": 30 }, { "grade": "A", "minMark": 70 }, { "grade": "D", "minMark": 40 }, { "grade": "B", "minMark": 60 } ] ], "expect": { "grade": "A*", "minMark": 80, "nextGrade": null, "marksToNext": null } }, { "name": "a lowest row at 0 means no mark is ungraded", "args": [ 0, 100, [ { "grade": "Distinction", "minMark": 70 }, { "grade": "Merit", "minMark": 60 }, { "grade": "Pass", "minMark": 40 }, { "grade": "Fail", "minMark": 0 } ] ], "expect": { "grade": "Fail", "minMark": 0, "nextGrade": "Pass", "marksToNext": 40 } }, { "name": "a single-row table: pass at the boundary", "args": [ 50, 50, [ { "grade": "Pass", "minMark": 50 } ] ], "expect": { "grade": "Pass", "minMark": 50, "nextGrade": null, "marksToNext": null } }, { "name": "a single-row table: below it is ungraded", "args": [ 49, 50, [ { "grade": "Pass", "minMark": 50 } ] ], "expect": { "grade": null, "minMark": null, "nextGrade": "Pass", "marksToNext": 1 } }, { "name": "a mark above maxMark is an error", "args": [ 101, 100, [ { "grade": "9", "minMark": 78 }, { "grade": "8", "minMark": 68 }, { "grade": "7", "minMark": 58 }, { "grade": "6", "minMark": 48 }, { "grade": "5", "minMark": 39 }, { "grade": "4", "minMark": 30 }, { "grade": "3", "minMark": 21 }, { "grade": "2", "minMark": 13 }, { "grade": "1", "minMark": 5 } ] ], "expectError": "mark must be a whole number from 0 to maxMark (100)" }, { "name": "a negative mark is an error", "args": [ -1, 100, [ { "grade": "9", "minMark": 78 }, { "grade": "8", "minMark": 68 }, { "grade": "7", "minMark": 58 }, { "grade": "6", "minMark": 48 }, { "grade": "5", "minMark": 39 }, { "grade": "4", "minMark": 30 }, { "grade": "3", "minMark": 21 }, { "grade": "2", "minMark": 13 }, { "grade": "1", "minMark": 5 } ] ], "expectError": "mark must be a whole number from 0 to maxMark (100)" }, { "name": "a half mark is an error", "args": [ 12.5, 100, [ { "grade": "9", "minMark": 78 }, { "grade": "8", "minMark": 68 }, { "grade": "7", "minMark": 58 }, { "grade": "6", "minMark": 48 }, { "grade": "5", "minMark": 39 }, { "grade": "4", "minMark": 30 }, { "grade": "3", "minMark": 21 }, { "grade": "2", "minMark": 13 }, { "grade": "1", "minMark": 5 } ] ], "expectError": "mark must be a whole number from 0 to maxMark (100)" }, { "name": "maxMark of zero is an error", "args": [ 0, 0, [ { "grade": "9", "minMark": 78 }, { "grade": "8", "minMark": 68 }, { "grade": "7", "minMark": 58 }, { "grade": "6", "minMark": 48 }, { "grade": "5", "minMark": 39 }, { "grade": "4", "minMark": 30 }, { "grade": "3", "minMark": 21 }, { "grade": "2", "minMark": 13 }, { "grade": "1", "minMark": 5 } ] ], "expectError": "maxMark must be a positive whole number" }, { "name": "an empty table is an error", "args": [ 10, 100, [] ], "expectError": "boundaries must not be empty" }, { "name": "a grade named twice is an error", "args": [ 10, 100, [ { "grade": "A", "minMark": 70 }, { "grade": "A", "minMark": 60 } ] ], "expectError": "grade A appears twice in boundaries" }, { "name": "two grades on one boundary is an error", "args": [ 10, 100, [ { "grade": "A", "minMark": 70 }, { "grade": "B", "minMark": 70 } ] ], "expectError": "grades A and B share the boundary 70" }, { "name": "a boundary above maxMark is an error", "args": [ 10, 60, [ { "grade": "9", "minMark": 78 }, { "grade": "8", "minMark": 68 }, { "grade": "7", "minMark": 58 }, { "grade": "6", "minMark": 48 }, { "grade": "5", "minMark": 39 }, { "grade": "4", "minMark": 30 }, { "grade": "3", "minMark": 21 }, { "grade": "2", "minMark": 13 }, { "grade": "1", "minMark": 5 } ] ], "expectError": "boundary minMark must be a whole number from 0 to maxMark (60), received 78 for grade 9" }, { "name": "an empty grade name is an error", "args": [ 10, 100, [ { "grade": "", "minMark": 70 } ] ], "expectError": "every boundary needs a non-empty grade" } ]