diff --git a/exercises/practice/grade-school/.meta/example.lua b/exercises/practice/grade-school/.meta/example.lua index d4d7ba17..68983ce7 100644 --- a/exercises/practice/grade-school/.meta/example.lua +++ b/exercises/practice/grade-school/.meta/example.lua @@ -6,23 +6,36 @@ function School:new() end function School:roster() - return self.db + local roster = {} + for _, grade in pairs(self.db) do + for _, student in ipairs(grade) do + table.insert(roster, student) + end + end + return roster end function School:add(name, grade) + for _, grade in pairs(self.db) do + for _, student in ipairs(grade) do + if student == name then + return false + end + end + end + if self.db[grade] then table.insert(self.db[grade], name) table.sort(self.db[grade]) else self.db[grade] = { name } end + + return true end function School:grade(grade) - if self.db[grade] then - return self.db[grade] - end - return {} + return self.db[grade] or {} end return School diff --git a/exercises/practice/grade-school/.meta/spec_generator.lua b/exercises/practice/grade-school/.meta/spec_generator.lua new file mode 100644 index 00000000..ed1e930b --- /dev/null +++ b/exercises/practice/grade-school/.meta/spec_generator.lua @@ -0,0 +1,46 @@ +local function map(t, f) + local mapped = {} + for i, v in ipairs(t) do + mapped[i] = f(v) + end + return mapped +end + +local function stringify(x) + return ("'%s'"):format(x) +end + +return { + module_name = 'School', + + generate_test = function(case) + local lines = { 'local school = School:new()' } + + if case.property == 'grade' or case.property == 'roster' then + for _, input in ipairs(case.input.students) do + local student, grade = table.unpack(input) + table.insert(lines, ('school:add(%s, %d)'):format(stringify(student), grade)) + end + table.insert(lines, + ('assert.are.same({ %s }, school:%s(%s))'):format(table.concat(map(case.expected, stringify), ', '), + case.property, case.input.desiredGrade or '')) + elseif case.property == 'add' then + for i, input in ipairs(case.input.students) do + local student, grade = table.unpack(input) + local expected + do + if type(case.expected) == 'table' then + expected = case.expected[i] + else + expected = case.expected + end + end + table.insert(lines, ('assert.is_%s(school:add(%s, %d))'):format(expected, stringify(student), grade)) + end + else + error("Unknown property: " .. case.property) + end + + return table.concat(lines, '\n') + end +} diff --git a/exercises/practice/grade-school/.meta/tests.toml b/exercises/practice/grade-school/.meta/tests.toml index eada129d..50c9e2e5 100644 --- a/exercises/practice/grade-school/.meta/tests.toml +++ b/exercises/practice/grade-school/.meta/tests.toml @@ -1,24 +1,86 @@ -# This is an auto-generated file. Regular comments will be removed when this -# file is regenerated. Regenerating will not touch any manually added keys, -# so comments can be added in a "comment" key. +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[a3f0fb58-f240-4723-8ddc-e644666b85cc] +description = "Roster is empty when no student is added" + +[9337267f-7793-4b90-9b4a-8e3978408824] +description = "Add a student" [6d0a30e4-1b4e-472e-8e20-c41702125667] -description = "Adding a student adds them to the sorted roster" +description = "Student is added to the roster" + +[73c3ca75-0c16-40d7-82f5-ed8fe17a8e4a] +description = "Adding multiple students in the same grade in the roster" [233be705-dd58-4968-889d-fb3c7954c9cc] -description = "Adding more student adds them to the sorted roster" +description = "Multiple students in the same grade are added to the roster" + +[87c871c1-6bde-4413-9c44-73d59a259d83] +description = "Cannot add student to same grade in the roster more than once" + +[c125dab7-2a53-492f-a99a-56ad511940d8] +description = "A student can't be in two different grades" +include = false + +[a0c7b9b8-0e89-47f8-8b4a-c50f885e79d1] +description = "A student can only be added to the same grade in the roster once" +include = false +reimplements = "c125dab7-2a53-492f-a99a-56ad511940d8" + +[d7982c4f-1602-49f6-a651-620f2614243a] +description = "Student not added to same grade in the roster more than once" +reimplements = "a0c7b9b8-0e89-47f8-8b4a-c50f885e79d1" + +[e70d5d8f-43a9-41fd-94a4-1ea0fa338056] +description = "Adding students in multiple grades" [75a51579-d1d7-407c-a2f8-2166e984e8ab] -description = "Adding students to different grades adds them to the same sorted roster" +description = "Students in multiple grades are added to the roster" -[a3f0fb58-f240-4723-8ddc-e644666b85cc] -description = "Roster returns an empty list if there are no students enrolled" +[7df542f1-57ce-433c-b249-ff77028ec479] +description = "Cannot add same student to multiple grades in the roster" -[180a8ff9-5b94-43fc-9db1-d46b4a8c93b6] -description = "Student names with grades are displayed in the same sorted roster" +[6a03b61e-1211-4783-a3cc-fc7f773fba3f] +description = "A student cannot be added to more than one grade in the sorted roster" +include = false +reimplements = "c125dab7-2a53-492f-a99a-56ad511940d8" -[1bfbcef1-e4a3-49e8-8d22-f6f9f386187e] -description = "Grade returns the students in that grade in alphabetical order" +[c7ec1c5e-9ab7-4d3b-be5c-29f2f7a237c5] +description = "Student not added to multiple grades in the roster" +reimplements = "6a03b61e-1211-4783-a3cc-fc7f773fba3f" + +[d9af4f19-1ba1-48e7-94d0-dabda4e5aba6] +description = "Students are sorted by grades in the roster" + +[d9fb5bea-f5aa-4524-9d61-c158d8906807] +description = "Students are sorted by name in the roster" + +[180a8ff9-5b94-43fc-9db1-d46b4a8c93b6] +description = "Students are sorted by grades and then by name in the roster" [5e67aa3c-a3c6-4407-a183-d8fe59cd1630] -description = "Grade returns an empty list if there are no students in that grade" +description = "Grade is empty if no students in the roster" + +[1e0cf06b-26e0-4526-af2d-a2e2df6a51d6] +description = "Grade is empty if no students in that grade" + +[2bfc697c-adf2-4b65-8d0f-c46e085f796e] +description = "Student not added to same grade more than once" + +[66c8e141-68ab-4a04-a15a-c28bc07fe6b9] +description = "Student not added to multiple grades" + +[c9c1fc2f-42e0-4d2c-b361-99271f03eda7] +description = "Student not added to other grade for multiple grades" + +[1bfbcef1-e4a3-49e8-8d22-f6f9f386187e] +description = "Students are sorted by name in a grade" diff --git a/exercises/practice/grade-school/grade-school_spec.lua b/exercises/practice/grade-school/grade-school_spec.lua index c926bc8f..55bbd123 100644 --- a/exercises/practice/grade-school/grade-school_spec.lua +++ b/exercises/practice/grade-school/grade-school_spec.lua @@ -1,65 +1,158 @@ local School = require('grade-school') describe('grade-school', function() - it('a new school has an empty roster', function() + it('roster is empty when no student is added', function() local school = School:new() - local expected = {} - local result = school:roster() - assert.are.same(expected, result) + assert.are.same({}, school:roster()) end) - it('adding a student adds them to the roster for the given grade', function() + it('add a student', function() + local school = School:new() + assert.is_true(school:add('Aimee', 2)) + end) + + it('student is added to the roster', function() local school = School:new() school:add('Aimee', 2) - local expected = { [2] = { 'Aimee' } } - local result = school:roster() - assert.are.same(expected, result) + assert.are.same({ 'Aimee' }, school:roster()) + end) + + it('adding multiple students in the same grade in the roster', function() + local school = School:new() + assert.is_true(school:add('Blair', 2)) + assert.is_true(school:add('James', 2)) + assert.is_true(school:add('Paul', 2)) + end) + + it('multiple students in the same grade are added to the roster', function() + local school = School:new() + school:add('Blair', 2) + school:add('James', 2) + school:add('Paul', 2) + assert.are.same({ 'Blair', 'James', 'Paul' }, school:roster()) + end) + + it('cannot add student to same grade in the roster more than once', function() + local school = School:new() + assert.is_true(school:add('Blair', 2)) + assert.is_true(school:add('James', 2)) + assert.is_false(school:add('James', 2)) + assert.is_true(school:add('Paul', 2)) end) - it('adding more students to the same grade adds them to the roster', function() + it('student not added to same grade in the roster more than once', function() local school = School:new() school:add('Blair', 2) school:add('James', 2) + school:add('James', 2) school:add('Paul', 2) - local expected = { [2] = { 'Blair', 'James', 'Paul' } } - local result = school:roster() - assert.are.same(expected, result) + assert.are.same({ 'Blair', 'James', 'Paul' }, school:roster()) + end) + + it('adding students in multiple grades', function() + local school = School:new() + assert.is_true(school:add('Chelsea', 3)) + assert.is_true(school:add('Logan', 7)) end) - it('adding students to different grades adds them to the roster', function() + it('students in multiple grades are added to the roster', function() local school = School:new() school:add('Chelsea', 3) school:add('Logan', 7) - local expected = { [3] = { 'Chelsea' }, [7] = { 'Logan' } } - local result = school:roster() - assert.are.same(expected, result) + assert.are.same({ 'Chelsea', 'Logan' }, school:roster()) end) - it('grade returns the students in that grade in alphabetical order', function() + it('cannot add same student to multiple grades in the roster', function() local school = School:new() - school:add('Franklin', 5) - school:add('Bradley', 5) - school:add('Jeff', 1) - local expected = { 'Bradley', 'Franklin' } - local result = school:grade(5) - assert.are.same(expected, result) + assert.is_true(school:add('Blair', 2)) + assert.is_true(school:add('James', 2)) + assert.is_false(school:add('James', 3)) + assert.is_true(school:add('Paul', 3)) + end) + + it('student not added to multiple grades in the roster', function() + local school = School:new() + school:add('Blair', 2) + school:add('James', 2) + school:add('James', 3) + school:add('Paul', 3) + assert.are.same({ 'Blair', 'James', 'Paul' }, school:roster()) + end) + + it('students are sorted by grades in the roster', function() + local school = School:new() + school:add('Jim', 3) + school:add('Peter', 2) + school:add('Anna', 1) + assert.are.same({ 'Anna', 'Peter', 'Jim' }, school:roster()) end) - it('grade returns an empty array if there are no students in that grade', function() + it('students are sorted by name in the roster', function() local school = School:new() - local result = school:grade(1) - local expected = {} - assert.are.same(expected, result) + school:add('Peter', 2) + school:add('Zoe', 2) + school:add('Alex', 2) + assert.are.same({ 'Alex', 'Peter', 'Zoe' }, school:roster()) end) - it('the students names in each grade in the roster are sorted', function() + it('students are sorted by grades and then by name in the roster', function() local school = School:new() - school:add('Jennifer', 4) - school:add('Kareem', 6) - school:add('Christopher', 4) - school:add('Kyle', 3) - local expected = { [3] = { 'Kyle' }, [4] = { 'Christopher', 'Jennifer' }, [6] = { 'Kareem' } } - local result = school:roster() - assert.are.same(expected, result) + school:add('Peter', 2) + school:add('Anna', 1) + school:add('Barb', 1) + school:add('Zoe', 2) + school:add('Alex', 2) + school:add('Jim', 3) + school:add('Charlie', 1) + assert.are.same({ 'Anna', 'Barb', 'Charlie', 'Alex', 'Peter', 'Zoe', 'Jim' }, school:roster()) + end) + + it('grade is empty if no students in the roster', function() + local school = School:new() + assert.are.same({}, school:grade(1)) + end) + + it('grade is empty if no students in that grade', function() + local school = School:new() + school:add('Peter', 2) + school:add('Zoe', 2) + school:add('Alex', 2) + school:add('Jim', 3) + assert.are.same({}, school:grade(1)) + end) + + it('student not added to same grade more than once', function() + local school = School:new() + school:add('Blair', 2) + school:add('James', 2) + school:add('James', 2) + school:add('Paul', 2) + assert.are.same({ 'Blair', 'James', 'Paul' }, school:grade(2)) + end) + + it('student not added to multiple grades', function() + local school = School:new() + school:add('Blair', 2) + school:add('James', 2) + school:add('James', 3) + school:add('Paul', 3) + assert.are.same({ 'Blair', 'James' }, school:grade(2)) + end) + + it('student not added to other grade for multiple grades', function() + local school = School:new() + school:add('Blair', 2) + school:add('James', 2) + school:add('James', 3) + school:add('Paul', 3) + assert.are.same({ 'Paul' }, school:grade(3)) + end) + + it('students are sorted by name in a grade', function() + local school = School:new() + school:add('Franklin', 5) + school:add('Bradley', 5) + school:add('Jeff', 1) + assert.are.same({ 'Bradley', 'Franklin' }, school:grade(5)) end) end)