[ { "name": "level 5 at 1 and level 6 at 2: 63 and 70.33 make 67.89, a 2:1 (credits alone would say 66.67)", "args": [ [ { "level": 5, "mark": 65, "credits": 20 }, { "level": 5, "mark": 58, "credits": 20 }, { "level": 5, "mark": 72, "credits": 20 }, { "level": 5, "mark": 61, "credits": 20 }, { "level": 5, "mark": 55, "credits": 20 }, { "level": 5, "mark": 67, "credits": 20 }, { "level": 6, "mark": 71, "credits": 20 }, { "level": 6, "mark": 68, "credits": 20 }, { "level": 6, "mark": 74, "credits": 40 }, { "level": 6, "mark": 66, "credits": 20 }, { "level": 6, "mark": 69, "credits": 20 } ], [ { "level": 5, "weight": 1 }, { "level": 6, "weight": 2 } ], 0, "half-up" ], "expect": { "average": { "numerator": 611, "denominator": 9 }, "scaled": 68, "decimals": 0, "classification": "upper-second", "label": "Upper second (2:1)", "countedCredits": 240 } }, { "name": "first-year modules are left out when level 4 is not weighted", "args": [ [ { "level": 4, "mark": 30, "credits": 120 }, { "level": 5, "mark": 65, "credits": 20 }, { "level": 5, "mark": 58, "credits": 20 }, { "level": 5, "mark": 72, "credits": 20 }, { "level": 5, "mark": 61, "credits": 20 }, { "level": 5, "mark": 55, "credits": 20 }, { "level": 5, "mark": 67, "credits": 20 }, { "level": 6, "mark": 71, "credits": 20 }, { "level": 6, "mark": 68, "credits": 20 }, { "level": 6, "mark": 74, "credits": 40 }, { "level": 6, "mark": 66, "credits": 20 }, { "level": 6, "mark": 69, "credits": 20 } ], [ { "level": 5, "weight": 1 }, { "level": 6, "weight": 2 } ], 0, "half-up" ], "expect": { "average": { "numerator": 611, "denominator": 9 }, "scaled": 68, "decimals": 0, "classification": "upper-second", "label": "Upper second (2:1)", "countedCredits": 240 } }, { "name": "50:50 in basis points", "args": [ [ { "level": 5, "mark": 65, "credits": 20 }, { "level": 5, "mark": 58, "credits": 20 }, { "level": 5, "mark": 72, "credits": 20 }, { "level": 5, "mark": 61, "credits": 20 }, { "level": 5, "mark": 55, "credits": 20 }, { "level": 5, "mark": 67, "credits": 20 }, { "level": 6, "mark": 71, "credits": 20 }, { "level": 6, "mark": 68, "credits": 20 }, { "level": 6, "mark": 74, "credits": 40 }, { "level": 6, "mark": 66, "credits": 20 }, { "level": 6, "mark": 69, "credits": 20 } ], [ { "level": 5, "weight": 5000 }, { "level": 6, "weight": 5000 } ], 0, "half-up" ], "expect": { "average": { "numerator": 200, "denominator": 3 }, "scaled": 67, "decimals": 0, "classification": "upper-second", "label": "Upper second (2:1)", "countedCredits": 240 } }, { "name": "final year only: a large module counts double its credits, 70.33 is a First", "args": [ [ { "level": 5, "mark": 65, "credits": 20 }, { "level": 5, "mark": 58, "credits": 20 }, { "level": 5, "mark": 72, "credits": 20 }, { "level": 5, "mark": 61, "credits": 20 }, { "level": 5, "mark": 55, "credits": 20 }, { "level": 5, "mark": 67, "credits": 20 }, { "level": 6, "mark": 71, "credits": 20 }, { "level": 6, "mark": 68, "credits": 20 }, { "level": 6, "mark": 74, "credits": 40 }, { "level": 6, "mark": 66, "credits": 20 }, { "level": 6, "mark": 69, "credits": 20 } ], [ { "level": 5, "weight": 0 }, { "level": 6, "weight": 1 } ], 0, "half-up" ], "expect": { "average": { "numerator": 211, "denominator": 3 }, "scaled": 70, "decimals": 0, "classification": "first", "label": "First", "countedCredits": 120 } }, { "name": "69.5 rounded to a whole mark is a First", "args": [ [ { "level": 6, "mark": 69, "credits": 60 }, { "level": 6, "mark": 70, "credits": 60 } ], [ { "level": 6, "weight": 1 } ], 0, "half-up" ], "expect": { "average": { "numerator": 139, "denominator": 2 }, "scaled": 70, "decimals": 0, "classification": "first", "label": "First", "countedCredits": 120 } }, { "name": "the same 69.5 rounded to one place stays a 2:1", "args": [ [ { "level": 6, "mark": 69, "credits": 60 }, { "level": 6, "mark": 70, "credits": 60 } ], [ { "level": 6, "weight": 1 } ], 1, "half-up" ], "expect": { "average": { "numerator": 139, "denominator": 2 }, "scaled": 695, "decimals": 1, "classification": "upper-second", "label": "Upper second (2:1)", "countedCredits": 120 } }, { "name": "the same 69.5 truncated stays a 2:1", "args": [ [ { "level": 6, "mark": 69, "credits": 60 }, { "level": 6, "mark": 70, "credits": 60 } ], [ { "level": 6, "weight": 1 } ], 0, "down" ], "expect": { "average": { "numerator": 139, "denominator": 2 }, "scaled": 69, "decimals": 0, "classification": "upper-second", "label": "Upper second (2:1)", "countedCredits": 120 } }, { "name": "exactly 60 is a 2:1", "args": [ [ { "level": 6, "mark": 60, "credits": 40 }, { "level": 6, "mark": 59, "credits": 40 }, { "level": 6, "mark": 61, "credits": 40 } ], [ { "level": 6, "weight": 1 } ], 0, "half-up" ], "expect": { "average": { "numerator": 60, "denominator": 1 }, "scaled": 60, "decimals": 0, "classification": "upper-second", "label": "Upper second (2:1)", "countedCredits": 120 } }, { "name": "exactly 50 is a 2:2", "args": [ [ { "level": 6, "mark": 50, "credits": 120 } ], [ { "level": 6, "weight": 1 } ], 0, "half-up" ], "expect": { "average": { "numerator": 50, "denominator": 1 }, "scaled": 50, "decimals": 0, "classification": "lower-second", "label": "Lower second (2:2)", "countedCredits": 120 } }, { "name": "exactly 40 is a Third", "args": [ [ { "level": 6, "mark": 40, "credits": 120 } ], [ { "level": 6, "weight": 1 } ], 0, "half-up" ], "expect": { "average": { "numerator": 40, "denominator": 1 }, "scaled": 40, "decimals": 0, "classification": "third", "label": "Third", "countedCredits": 120 } }, { "name": "39 is below a Third", "args": [ [ { "level": 6, "mark": 39, "credits": 120 } ], [ { "level": 6, "weight": 1 } ], 0, "half-up" ], "expect": { "average": { "numerator": 39, "denominator": 1 }, "scaled": 39, "decimals": 0, "classification": "unclassified", "label": "Unclassified", "countedCredits": 120 } }, { "name": "full marks", "args": [ [ { "level": 6, "mark": 100, "credits": 120 } ], [ { "level": 6, "weight": 1 } ], 0, "half-up" ], "expect": { "average": { "numerator": 100, "denominator": 1 }, "scaled": 100, "decimals": 0, "classification": "first", "label": "First", "countedCredits": 120 } }, { "name": "zero", "args": [ [ { "level": 6, "mark": 0, "credits": 120 } ], [ { "level": 6, "weight": 1 } ], 0, "half-up" ], "expect": { "average": { "numerator": 0, "denominator": 1 }, "scaled": 0, "decimals": 0, "classification": "unclassified", "label": "Unclassified", "countedCredits": 120 } }, { "name": "a mark above 100 is an error", "args": [ [ { "level": 6, "mark": 101, "credits": 120 } ], [ { "level": 6, "weight": 1 } ], 0, "half-up" ], "expectError": "mark must be a whole number from 0 to 100, received 101" }, { "name": "a half mark is an error", "args": [ [ { "level": 6, "mark": 69.5, "credits": 120 } ], [ { "level": 6, "weight": 1 } ], 0, "half-up" ], "expectError": "mark must be a whole number from 0 to 100, received 69.5" }, { "name": "zero credits is an error", "args": [ [ { "level": 6, "mark": 60, "credits": 0 } ], [ { "level": 6, "weight": 1 } ], 0, "half-up" ], "expectError": "credits must be a whole number of 1 or more, received 0" }, { "name": "no level weights is an error", "args": [ [ { "level": 6, "mark": 71, "credits": 20 }, { "level": 6, "mark": 68, "credits": 20 }, { "level": 6, "mark": 74, "credits": 40 }, { "level": 6, "mark": 66, "credits": 20 }, { "level": 6, "mark": 69, "credits": 20 } ], [], 0, "half-up" ], "expectError": "levelWeights must name at least one level" }, { "name": "a level weighted twice is an error", "args": [ [ { "level": 6, "mark": 71, "credits": 20 }, { "level": 6, "mark": 68, "credits": 20 }, { "level": 6, "mark": 74, "credits": 40 }, { "level": 6, "mark": 66, "credits": 20 }, { "level": 6, "mark": 69, "credits": 20 } ], [ { "level": 6, "weight": 1 }, { "level": 6, "weight": 2 } ], 0, "half-up" ], "expectError": "level 6 appears twice in levelWeights" }, { "name": "a negative weight is an error", "args": [ [ { "level": 6, "mark": 71, "credits": 20 }, { "level": 6, "mark": 68, "credits": 20 }, { "level": 6, "mark": 74, "credits": 40 }, { "level": 6, "mark": 66, "credits": 20 }, { "level": 6, "mark": 69, "credits": 20 } ], [ { "level": 6, "weight": -1 } ], 0, "half-up" ], "expectError": "weight must be a whole number of 0 or more, received -1 for level 6" }, { "name": "all-zero weights are an error", "args": [ [ { "level": 6, "mark": 71, "credits": 20 }, { "level": 6, "mark": 68, "credits": 20 }, { "level": 6, "mark": 74, "credits": 40 }, { "level": 6, "mark": 66, "credits": 20 }, { "level": 6, "mark": 69, "credits": 20 } ], [ { "level": 6, "weight": 0 } ], 0, "half-up" ], "expectError": "levelWeights must not all be zero" }, { "name": "a weighted level with no modules is an error", "args": [ [ { "level": 5, "mark": 65, "credits": 20 }, { "level": 5, "mark": 58, "credits": 20 }, { "level": 5, "mark": 72, "credits": 20 }, { "level": 5, "mark": 61, "credits": 20 }, { "level": 5, "mark": 55, "credits": 20 }, { "level": 5, "mark": 67, "credits": 20 } ], [ { "level": 5, "weight": 1 }, { "level": 6, "weight": 2 } ], 0, "half-up" ], "expectError": "no modules at level 6, which levelWeights counts" }, { "name": "seven decimal places is an error", "args": [ [ { "level": 6, "mark": 71, "credits": 20 }, { "level": 6, "mark": 68, "credits": 20 }, { "level": 6, "mark": 74, "credits": 40 }, { "level": 6, "mark": 66, "credits": 20 }, { "level": 6, "mark": 69, "credits": 20 } ], [ { "level": 6, "weight": 1 } ], 7, "half-up" ], "expectError": "decimals must be a whole number from 0 to 6, received 7" }, { "name": "an unknown rounding mode is an error", "args": [ [ { "level": 6, "mark": 71, "credits": 20 }, { "level": 6, "mark": 68, "credits": 20 }, { "level": 6, "mark": 74, "credits": 40 }, { "level": 6, "mark": 66, "credits": 20 }, { "level": 6, "mark": 69, "credits": 20 } ], [ { "level": 6, "weight": 1 } ], 0, "nearest" ], "expectError": "unknown rounding mode \"nearest\"" } ]