diff --git a/exercises/practice/allergies/.meta/test_generator.py b/exercises/practice/allergies/.meta/test_generator.py new file mode 100644 index 00000000..c2856403 --- /dev/null +++ b/exercises/practice/allergies/.meta/test_generator.py @@ -0,0 +1,31 @@ +from lib import ( + assert_eq, + assert_false, + assert_true, + d_array, + d_inline_array, + d_int, + d_string, +) + + +def describe(case): + (parent,) = case["parents"] + return f"{parent.rstrip(':')}: {case['description']}" + + +def gen_case(case): + score = d_int(case["input"]["score"]) + lines = [f"scope Allergies allergies = new Allergies({score});"] + if case["property"] == "allergicTo": + call = f"allergies.allergicTo({d_string(case['input']['item'])})" + lines.append(assert_true(call) if case["expected"] else assert_false(call)) + return lines + + allergens = case["expected"] + render = d_array if len(allergens) > 2 else d_inline_array + expected = render(allergens, d_string) + lines.append("string[] result = allergies.list();") + lines.append(f"string[] expected = {expected};") + lines.append(assert_eq("result", "expected")) + return lines diff --git a/exercises/practice/allergies/example/allergies.d b/exercises/practice/allergies/example/allergies.d index 3d233758..56f0089c 100644 --- a/exercises/practice/allergies/example/allergies.d +++ b/exercises/practice/allergies/example/allergies.d @@ -41,4 +41,4 @@ private: "pollen", "cats" ]; -} \ No newline at end of file +} diff --git a/exercises/practice/allergies/source/allergies.d b/exercises/practice/allergies/source/allergies.d index 616695ae..2d2039dc 100644 --- a/exercises/practice/allergies/source/allergies.d +++ b/exercises/practice/allergies/source/allergies.d @@ -30,7 +30,6 @@ unittest static if (allTestsEnabled) { - // testing for eggs allergy: allergic only to eggs { scope Allergies allergies = new Allergies(1); @@ -55,7 +54,7 @@ unittest assert(allergies.allergicTo("eggs")); } - // testing for peanuts allergy: not allergic to peanuts + // testing for peanuts allergy: not allergic to anything { scope Allergies allergies = new Allergies(0); assert(!allergies.allergicTo("peanuts")); @@ -85,7 +84,7 @@ unittest assert(allergies.allergicTo("peanuts")); } - // testing for shellfish allergy: not allergic to shellfish + // testing for shellfish allergy: not allergic to anything { scope Allergies allergies = new Allergies(0); assert(!allergies.allergicTo("shellfish")); @@ -115,61 +114,7 @@ unittest assert(allergies.allergicTo("shellfish")); } - // testing for eggs allergy: allergic only to eggs - { - scope Allergies allergies = new Allergies(1); - assert(allergies.allergicTo("eggs")); - } - - // testing for eggs allergy: allergic to eggs and something else - { - scope Allergies allergies = new Allergies(3); - assert(allergies.allergicTo("eggs")); - } - - // testing for eggs allergy: allergic to something, but not eggs - { - scope Allergies allergies = new Allergies(2); - assert(!allergies.allergicTo("eggs")); - } - - // testing for eggs allergy: allergic to everything - { - scope Allergies allergies = new Allergies(255); - assert(allergies.allergicTo("eggs")); - } - - // testing for peanuts allergy: not allergic to peanuts - { - scope Allergies allergies = new Allergies(0); - assert(!allergies.allergicTo("peanuts")); - } - - // testing for peanuts allergy: allergic only to peanuts - { - scope Allergies allergies = new Allergies(2); - assert(allergies.allergicTo("peanuts")); - } - - // testing for peanuts allergy: allergic to peanuts and something else - { - scope Allergies allergies = new Allergies(7); - assert(allergies.allergicTo("peanuts")); - } - - // testing for peanuts allergy: allergic to something, but not peanuts - { - scope Allergies allergies = new Allergies(5); - assert(!allergies.allergicTo("peanuts")); - } - - // testing for peanuts allergy: allergic to everything - { - scope Allergies allergies = new Allergies(255); - assert(allergies.allergicTo("peanuts")); - } - - // testing for strawberries allergy: not allergic to strawberries + // testing for strawberries allergy: not allergic to anything { scope Allergies allergies = new Allergies(0); assert(!allergies.allergicTo("strawberries")); @@ -199,7 +144,7 @@ unittest assert(allergies.allergicTo("strawberries")); } - // testing for tomatoes allergy: not allergic to tomatoes + // testing for tomatoes allergy: not allergic to anything { scope Allergies allergies = new Allergies(0); assert(!allergies.allergicTo("tomatoes")); @@ -229,7 +174,7 @@ unittest assert(allergies.allergicTo("tomatoes")); } - // testing for chocolate allergy: not allergic to chocolate + // testing for chocolate allergy: not allergic to anything { scope Allergies allergies = new Allergies(0); assert(!allergies.allergicTo("chocolate")); @@ -259,7 +204,7 @@ unittest assert(allergies.allergicTo("chocolate")); } - // testing for pollen allergy: not allergic to pollen + // testing for pollen allergy: not allergic to anything { scope Allergies allergies = new Allergies(0); assert(!allergies.allergicTo("pollen")); @@ -289,7 +234,7 @@ unittest assert(allergies.allergicTo("pollen")); } - // testing for cats allergy: not allergic to cats + // testing for cats allergy: not allergic to anything { scope Allergies allergies = new Allergies(0); assert(!allergies.allergicTo("cats")); @@ -376,7 +321,7 @@ unittest "tomatoes", "chocolate", "pollen", - "cats" + "cats", ]; assert(result == expected); } @@ -393,7 +338,7 @@ unittest "tomatoes", "chocolate", "pollen", - "cats" + "cats", ]; assert(result == expected); } @@ -409,7 +354,7 @@ unittest "tomatoes", "chocolate", "pollen", - "cats" + "cats", ]; assert(result == expected); } @@ -422,5 +367,4 @@ unittest assert(result == expected); } } - } diff --git a/exercises/practice/anagram/.meta/test_generator.py b/exercises/practice/anagram/.meta/test_generator.py new file mode 100644 index 00000000..0de52a96 --- /dev/null +++ b/exercises/practice/anagram/.meta/test_generator.py @@ -0,0 +1,20 @@ +from lib import assert_eq, d_inline_array, d_string + + +def describe(case): + return case["description"] + + +def gen_case(case): + prop = case["property"] + subject = d_string(case["input"]["subject"]) + candidates = d_inline_array(case["input"]["candidates"], d_string) + expected = d_inline_array(case["expected"], d_string) + return [ + f"immutable string subject = {subject};", + f"immutable string[] candidates = {candidates};", + f"string[] actual = {prop}(subject, candidates);", + f"string[] expected = {expected};", + "", + assert_eq("actual", "expected"), + ] diff --git a/exercises/practice/anagram/example/anagram.d b/exercises/practice/anagram/example/anagram.d index ce5bc3cc..6c423522 100644 --- a/exercises/practice/anagram/example/anagram.d +++ b/exercises/practice/anagram/example/anagram.d @@ -21,4 +21,3 @@ pure string[] findAnagrams(immutable string subject, immutable string[] candidat } return results; } - diff --git a/exercises/practice/anagram/source/anagram.d b/exercises/practice/anagram/source/anagram.d index 50aee2f3..2eba666c 100644 --- a/exercises/practice/anagram/source/anagram.d +++ b/exercises/practice/anagram/source/anagram.d @@ -21,7 +21,6 @@ unittest static if (allTestsEnabled) { - // detects two anagrams { immutable string subject = "solemn"; @@ -165,7 +164,7 @@ unittest // words other than themselves can be anagrams { immutable string subject = "LISTEN"; - immutable string[] candidates = ["Listen", "Silent", "LISTEN"]; + immutable string[] candidates = ["LISTEN", "Silent"]; string[] actual = findAnagrams(subject, candidates); string[] expected = ["Silent"]; @@ -183,4 +182,3 @@ unittest } } } - diff --git a/exercises/practice/binary-search/.meta/test_generator.py b/exercises/practice/binary-search/.meta/test_generator.py new file mode 100644 index 00000000..bcf58547 --- /dev/null +++ b/exercises/practice/binary-search/.meta/test_generator.py @@ -0,0 +1,15 @@ +from lib import assert_eq, assert_throws, d_inline_array, d_int, is_error + + +def gen_case(case): + prop = case["property"] + array = d_inline_array(case["input"]["array"]) + value = d_int(case["input"]["value"]) + call = f"bs.{prop}({value})" + + lines = [f"BinarySearch bs = new BinarySearch({array});"] + if is_error(case["expected"]): + lines.append(assert_throws(call)) + else: + lines.append(assert_eq(call, d_int(case["expected"]))) + return lines diff --git a/exercises/practice/binary-search/source/binary_search.d b/exercises/practice/binary-search/source/binary_search.d index 4390f04f..b8ad1be4 100644 --- a/exercises/practice/binary-search/source/binary_search.d +++ b/exercises/practice/binary-search/source/binary_search.d @@ -15,7 +15,9 @@ class BinarySearch unittest { - const int allTestsEnabled = 0; + import std.exception : assertThrown; + + immutable int allTestsEnabled = 0; // Finds a value in an array with one element { @@ -25,9 +27,6 @@ unittest static if (allTestsEnabled) { - - import std.exception : assertThrown; - // Finds a value in the middle of an array { BinarySearch bs = new BinarySearch([1, 3, 4, 6, 8, 9, 11]); @@ -87,6 +86,5 @@ unittest BinarySearch bs = new BinarySearch([1, 2]); assertThrown(bs.find(0)); } - } } diff --git a/exercises/practice/circular-buffer/.meta/test_generator.py b/exercises/practice/circular-buffer/.meta/test_generator.py new file mode 100644 index 00000000..3eb80a54 --- /dev/null +++ b/exercises/practice/circular-buffer/.meta/test_generator.py @@ -0,0 +1,45 @@ +from lib import assert_eq, d_int + +EMPTY = "Empty buffer should throw exception if popped!" +FULL = "Full buffer should throw exception if new element pushed!" + +# The element type used to instantiate the template in each test case. +TYPES = { + "reading empty buffer should fail": "int", + "each item may only be read once": "short", + "full buffer can't be written to": "long", + "read position is maintained even across multiple writes": "int", + "clear frees up capacity for another write": "short", + "overwrite acts like write on non-full buffer": "long", + "overwrite replaces the oldest item remaining in buffer following a read": "int", +} + + +def d_item(item, kind): + return f"'{item}'" if kind == "char" else d_int(item) + + +def gen_operation(operation, kind): + name = operation["operation"] + if name == "clear": + return "myBuffer.clear();" + if name == "overwrite": + return f"myBuffer.forcePush({d_item(operation['item'], kind)});" + if name == "write": + call = f"myBuffer.push({d_item(operation['item'], kind)})" + if operation["should_succeed"]: + return f"{call};" + return f'assertThrown({call}, "{FULL}");' + if operation["should_succeed"]: + return assert_eq("myBuffer.pop()", d_item(operation["expected"], kind)) + return f'assertThrown(myBuffer.pop(), "{EMPTY}");' + + +def gen_case(case): + kind = TYPES.get(case["description"], "char") + capacity = d_int(case["input"]["capacity"]) + operations = case["input"]["operations"] + return [ + f"auto myBuffer = new Buffer!({kind})({capacity});", + *(gen_operation(operation, kind) for operation in operations), + ] diff --git a/exercises/practice/circular-buffer/source/circular_buffer.d b/exercises/practice/circular-buffer/source/circular_buffer.d index 93cb26de..21e178cf 100644 --- a/exercises/practice/circular-buffer/source/circular_buffer.d +++ b/exercises/practice/circular-buffer/source/circular_buffer.d @@ -35,15 +35,14 @@ unittest immutable int allTestsEnabled = 0; - // Reading empty buffer should fail" + // Reading empty buffer should fail { - auto myBuffer = new Buffer!(int)(1UL); + auto myBuffer = new Buffer!(int)(1); assertThrown(myBuffer.pop(), "Empty buffer should throw exception if popped!"); } static if (allTestsEnabled) { - // Can read an item just written { auto myBuffer = new Buffer!(char)(1); @@ -51,11 +50,11 @@ unittest assert(myBuffer.pop() == '1'); } - // Each item may only be read once" + // Each item may only be read once { - auto myBuffer = new Buffer!(char)(1); - myBuffer.push('1'); - assert(myBuffer.pop() == '1'); + auto myBuffer = new Buffer!(short)(1); + myBuffer.push(1); + assert(myBuffer.pop() == 1); assertThrown(myBuffer.pop(), "Empty buffer should throw exception if popped!"); } @@ -70,10 +69,9 @@ unittest // Full buffer can't be written to { - auto myBuffer = new Buffer!(char)(1); - myBuffer.push('1'); - assertThrown(myBuffer.push('2'), - "Full buffer should throw exception if new element pushed!"); + auto myBuffer = new Buffer!(long)(1); + myBuffer.push(1); + assertThrown(myBuffer.push(2), "Full buffer should throw exception if new element pushed!"); } // A read frees up capacity for another write @@ -87,13 +85,13 @@ unittest // Read position is maintained even across multiple writes { - auto myBuffer = new Buffer!(char)(3); - myBuffer.push('1'); - myBuffer.push('2'); - assert(myBuffer.pop() == '1'); - myBuffer.push('3'); - assert(myBuffer.pop() == '2'); - assert(myBuffer.pop() == '3'); + auto myBuffer = new Buffer!(int)(3); + myBuffer.push(1); + myBuffer.push(2); + assert(myBuffer.pop() == 1); + myBuffer.push(3); + assert(myBuffer.pop() == 2); + assert(myBuffer.pop() == 3); } // Items cleared out of buffer can't be read @@ -106,11 +104,11 @@ unittest // Clear frees up capacity for another write { - auto myBuffer = new Buffer!(char)(1); - myBuffer.push('1'); + auto myBuffer = new Buffer!(short)(1); + myBuffer.push(1); myBuffer.clear(); - myBuffer.push('2'); - assert(myBuffer.pop() == '2'); + myBuffer.push(2); + assert(myBuffer.pop() == 2); } // Clear does nothing on empty buffer @@ -123,11 +121,11 @@ unittest // Overwrite acts like write on non-full buffer { - auto myBuffer = new Buffer!(char)(2); - myBuffer.push('1'); - myBuffer.forcePush('2'); - assert(myBuffer.pop() == '1'); - assert(myBuffer.pop() == '2'); + auto myBuffer = new Buffer!(long)(2); + myBuffer.push(1); + myBuffer.forcePush(2); + assert(myBuffer.pop() == 1); + assert(myBuffer.pop() == 2); } // Overwrite replaces the oldest item on full buffer @@ -142,16 +140,16 @@ unittest // Overwrite replaces the oldest item remaining in buffer following a read { - auto myBuffer = new Buffer!(char)(3); - myBuffer.push('1'); - myBuffer.push('2'); - myBuffer.push('3'); - assert(myBuffer.pop() == '1'); - myBuffer.push('4'); - myBuffer.forcePush('5'); - assert(myBuffer.pop() == '3'); - assert(myBuffer.pop() == '4'); - assert(myBuffer.pop() == '5'); + auto myBuffer = new Buffer!(int)(3); + myBuffer.push(1); + myBuffer.push(2); + myBuffer.push(3); + assert(myBuffer.pop() == 1); + myBuffer.push(4); + myBuffer.forcePush(5); + assert(myBuffer.pop() == 3); + assert(myBuffer.pop() == 4); + assert(myBuffer.pop() == 5); } // Initial clear does not affect wrapping around @@ -166,7 +164,5 @@ unittest assert(myBuffer.pop() == '4'); assertThrown(myBuffer.pop(), "Empty buffer should throw exception if popped!"); } - } - } diff --git a/exercises/practice/collatz-conjecture/.meta/test_generator.py b/exercises/practice/collatz-conjecture/.meta/test_generator.py new file mode 100644 index 00000000..8e32f679 --- /dev/null +++ b/exercises/practice/collatz-conjecture/.meta/test_generator.py @@ -0,0 +1,10 @@ +from lib import assert_eq, assert_throws, d_int, is_error + + +def gen_case(case): + prop = case["property"] + number = d_int(case["input"]["number"]) + call = f"{prop}({number})" + if is_error(case["expected"]): + return assert_throws(call) + return assert_eq(call, d_int(case["expected"])) diff --git a/exercises/practice/collatz-conjecture/source/collatz_conjecture.d b/exercises/practice/collatz-conjecture/source/collatz_conjecture.d index 608e5412..a4fe227d 100644 --- a/exercises/practice/collatz-conjecture/source/collatz_conjecture.d +++ b/exercises/practice/collatz-conjecture/source/collatz_conjecture.d @@ -9,7 +9,7 @@ unittest { import std.exception : assertThrown; - const int allTestsEnabled = 0; + immutable int allTestsEnabled = 0; // Zero steps for one assert(steps(1) == 0); diff --git a/exercises/practice/difference-of-squares/.meta/test_generator.py b/exercises/practice/difference-of-squares/.meta/test_generator.py new file mode 100644 index 00000000..64256862 --- /dev/null +++ b/exercises/practice/difference-of-squares/.meta/test_generator.py @@ -0,0 +1,19 @@ +from lib import assert_eq, d_grouped_int, d_int + +PROPERTIES = { + "squareOfSum": "squareOfSum", + "sumOfSquares": "sumOfSquares", + "differenceOfSquares": "difference", +} + + +def describe(case): + description = case["description"] + return description[:1].upper() + description[1:] + + +def gen_case(case): + prop = PROPERTIES[case["property"]] + number = d_int(case["input"]["number"]) + expected = d_grouped_int(case["expected"]) + return assert_eq(f"squares({number}).{prop}", expected) diff --git a/exercises/practice/difference-of-squares/source/difference_of_squares.d b/exercises/practice/difference-of-squares/source/difference_of_squares.d index e7c512d5..e3cec529 100644 --- a/exercises/practice/difference-of-squares/source/difference_of_squares.d +++ b/exercises/practice/difference-of-squares/source/difference_of_squares.d @@ -24,8 +24,13 @@ unittest // Sum of squares 100 assert(squares(100).sumOfSquares == 338_350); + // Difference of squares 1 + assert(squares(1).difference == 0); + + // Difference of squares 5 + assert(squares(5).difference == 170); + // Difference of squares 100 assert(squares(100).difference == 25_164_150); } - } diff --git a/exercises/practice/gigasecond/.meta/test_generator.py b/exercises/practice/gigasecond/.meta/test_generator.py new file mode 100644 index 00000000..d148363d --- /dev/null +++ b/exercises/practice/gigasecond/.meta/test_generator.py @@ -0,0 +1,16 @@ +import re + +from lib import assert_eq + + +def d_date_time(moment): + """Render a moment such as 2015-01-24T22:00:00 as a DateTime.""" + fields = [str(int(field)) for field in re.split("[-T:]", moment)] + return f"DateTime({', '.join(fields)})" + + +def gen_case(case): + prop = case["property"] + moment = d_date_time(case["input"]["moment"]) + expected = d_date_time(case["expected"]) + return assert_eq(f"{prop}({moment})", expected) diff --git a/exercises/practice/gigasecond/.meta/tests.toml b/exercises/practice/gigasecond/.meta/tests.toml index a7caf00d..003e6b74 100644 --- a/exercises/practice/gigasecond/.meta/tests.toml +++ b/exercises/practice/gigasecond/.meta/tests.toml @@ -26,3 +26,5 @@ description = "full time with day roll-over" [fcec307c-7529-49ab-b0fe-20309197618a] description = "does not mutate the input" +include = false +comment = "DateTime is passed by value" diff --git a/exercises/practice/gigasecond/source/gigasecond.d b/exercises/practice/gigasecond/source/gigasecond.d index a665e438..6df4c799 100644 --- a/exercises/practice/gigasecond/source/gigasecond.d +++ b/exercises/practice/gigasecond/source/gigasecond.d @@ -11,7 +11,7 @@ unittest static if (allTestsEnabled) { - // Second test for date only specification of time" + // Second test for date only specification of time assert(add(DateTime(1977, 6, 13)) == DateTime(2009, 2, 19, 1, 46, 40)); // Third test for date only specification of time @@ -22,11 +22,5 @@ unittest // Full time with day roll-over assert(add(DateTime(2015, 1, 24, 23, 59, 59)) == DateTime(2046, 10, 3, 1, 46, 39)); - - // Does not mutate the input - auto d = DateTime(2015, 1, 24, 23, 59, 59); - assert(add(d) == DateTime(2046, 10, 3, 1, 46, 39)); - assert(d == DateTime(2015, 1, 24, 23, 59, 59)); } - } diff --git a/exercises/practice/grade-school/.meta/test_generator.py b/exercises/practice/grade-school/.meta/test_generator.py new file mode 100644 index 00000000..46bc17f0 --- /dev/null +++ b/exercises/practice/grade-school/.meta/test_generator.py @@ -0,0 +1,22 @@ +from lib import assert_eq, assert_false, assert_true, d_inline_array, d_string + + +def gen_case(case): + prop = case["property"] + expected = case["expected"] + lines = ["GradeSchool school;"] + for index, (student, grade) in enumerate(case["input"]["students"]): + call = f"school.add({d_string(student)}, {grade})" + if prop != "add": + lines.append(f"{call};") + elif expected[index]: + lines.append(assert_true(call)) + else: + lines.append(assert_false(call)) + + if prop == "roster": + lines.append(assert_eq("school.roster()", d_inline_array(expected, d_string))) + elif prop == "grade": + call = f"school.grade({case['input']['desiredGrade']})" + lines.append(assert_eq(call, d_inline_array(expected, d_string))) + return lines diff --git a/exercises/practice/grade-school/source/grade_school.d b/exercises/practice/grade-school/source/grade_school.d index 2a309ab2..dca756f9 100644 --- a/exercises/practice/grade-school/source/grade_school.d +++ b/exercises/practice/grade-school/source/grade_school.d @@ -63,10 +63,10 @@ unittest // Cannot add student to same grade in the roster more than once { GradeSchool school; - school.add("Blair", 2); + assert(school.add("Blair", 2)); assert(school.add("James", 2)); assert(!school.add("James", 2)); - school.add("Paul", 2); + assert(school.add("Paul", 2)); } // Student not added to same grade in the roster more than once @@ -97,10 +97,10 @@ unittest // Cannot add same student to multiple grades in the roster { GradeSchool school; - school.add("Blair", 2); + assert(school.add("Blair", 2)); assert(school.add("James", 2)); assert(!school.add("James", 3)); - school.add("Paul", 3); + assert(school.add("Paul", 3)); } // Student not added to multiple grades in the roster diff --git a/exercises/practice/grains/.meta/test_generator.py b/exercises/practice/grains/.meta/test_generator.py new file mode 100644 index 00000000..62c110e8 --- /dev/null +++ b/exercises/practice/grains/.meta/test_generator.py @@ -0,0 +1,18 @@ +from lib import assert_eq, assert_throws, d_grouped_int, d_int, is_error + + +def describe(case): + if is_error(case["expected"]): + description = case["description"].replace("is invalid", "raises an exception") + else: + description = " - ".join((*case["parents"], case["description"])) + return description[:1].upper() + description[1:] + + +def gen_case(case): + prop = case["property"] + arguments = ", ".join(d_int(value) for value in case["input"].values()) + call = f"{prop}({arguments})" + if is_error(case["expected"]): + return assert_throws(call) + return assert_eq(call, d_grouped_int(case["expected"])) diff --git a/exercises/practice/grains/source/grains.d b/exercises/practice/grains/source/grains.d index 092c7085..0417f260 100644 --- a/exercises/practice/grains/source/grains.d +++ b/exercises/practice/grains/source/grains.d @@ -16,17 +16,28 @@ unittest immutable int allTestsEnabled = 0; - // Returns the number of grains on the square + // Returns the number of grains on the square - grains on square 1 assert(square(1) == 1); static if (allTestsEnabled) { + // Returns the number of grains on the square - grains on square 2 assert(square(2) == 2); + + // Returns the number of grains on the square - grains on square 3 assert(square(3) == 4); + + // Returns the number of grains on the square - grains on square 4 assert(square(4) == 8); + + // Returns the number of grains on the square - grains on square 16 assert(square(16) == 32_768); - assert(square(32) == 2_147_483_648uL); - assert(square(64) == 9_223_372_036_854_775_808uL); + + // Returns the number of grains on the square - grains on square 32 + assert(square(32) == 2_147_483_648); + + // Returns the number of grains on the square - grains on square 64 + assert(square(64) == 9_223_372_036_854_775_808); // Square 0 raises an exception assertThrown(square(0)); @@ -38,6 +49,6 @@ unittest assertThrown(square(65)); // Returns the total number of grains on the board - assert(total() == 18_446_744_073_709_551_615uL); + assert(total() == 18_446_744_073_709_551_615); } } diff --git a/exercises/practice/hamming/.meta/test_generator.py b/exercises/practice/hamming/.meta/test_generator.py new file mode 100644 index 00000000..395bf389 --- /dev/null +++ b/exercises/practice/hamming/.meta/test_generator.py @@ -0,0 +1,11 @@ +from lib import assert_eq, assert_throws, d_int, d_string, is_error + + +def gen_case(case): + prop = case["property"] + strand1 = d_string(case["input"]["strand1"]) + strand2 = d_string(case["input"]["strand2"]) + call = f"{prop}({strand1}, {strand2})" + if is_error(case["expected"]): + return assert_throws(call) + return assert_eq(call, d_int(case["expected"])) diff --git a/exercises/practice/hamming/.meta/tests.toml b/exercises/practice/hamming/.meta/tests.toml index 0caf456c..5dc17ed4 100644 --- a/exercises/practice/hamming/.meta/tests.toml +++ b/exercises/practice/hamming/.meta/tests.toml @@ -26,6 +26,7 @@ description = "long different strands" [919f8ef0-b767-4d1b-8516-6379d07fcb28] description = "disallow first strand longer" +include = false [b9228bb1-465f-4141-b40f-1f99812de5a8] description = "disallow first strand longer" @@ -33,6 +34,7 @@ reimplements = "919f8ef0-b767-4d1b-8516-6379d07fcb28" [8a2d4ed0-ead5-4fdd-924d-27c4cf56e60e] description = "disallow second strand longer" +include = false [dab38838-26bb-4fff-acbe-3b0a9bfeba2d] description = "disallow second strand longer" @@ -40,9 +42,11 @@ reimplements = "8a2d4ed0-ead5-4fdd-924d-27c4cf56e60e" [5dce058b-28d4-4ca7-aa64-adfe4e17784c] description = "disallow left empty strand" +include = false [db92e77e-7c72-499d-8fe6-9354d2bfd504] description = "disallow left empty strand" +include = false reimplements = "5dce058b-28d4-4ca7-aa64-adfe4e17784c" [b764d47c-83ff-4de2-ab10-6cfe4b15c0f3] @@ -51,9 +55,11 @@ reimplements = "db92e77e-7c72-499d-8fe6-9354d2bfd504" [38826d4b-16fb-4639-ac3e-ba027dec8b5f] description = "disallow right empty strand" +include = false [920cd6e3-18f4-4143-b6b8-74270bb8f8a3] description = "disallow right empty strand" +include = false reimplements = "38826d4b-16fb-4639-ac3e-ba027dec8b5f" [9ab9262f-3521-4191-81f5-0ed184a5aa89] diff --git a/exercises/practice/hamming/source/hamming.d b/exercises/practice/hamming/source/hamming.d index 676f4a52..e4d38ff3 100644 --- a/exercises/practice/hamming/source/hamming.d +++ b/exercises/practice/hamming/source/hamming.d @@ -28,17 +28,16 @@ unittest // Long different strands assert(distance("GGACGGATTCTG", "AGGACGGATTCT") == 9); - // Disallow first strand longer + // Disallow first strand longer assertThrown(distance("AATG", "AAA")); // Disallow second strand longer - assertThrown(distance("AAA", "AGTG")); + assertThrown(distance("ATA", "AGTG")); - // Disallow left empty strand + // Disallow empty first strand assertThrown(distance("", "G")); - // Disallow right empty strand + // Disallow empty second strand assertThrown(distance("G", "")); } - } diff --git a/exercises/practice/isogram/.meta/test_generator.py b/exercises/practice/isogram/.meta/test_generator.py new file mode 100644 index 00000000..69be40f8 --- /dev/null +++ b/exercises/practice/isogram/.meta/test_generator.py @@ -0,0 +1,10 @@ +from lib import assert_false, assert_true, d_string + + +def gen_case(case): + prop = case["property"] + phrase = d_string(case["input"]["phrase"]) + call = f"{prop}({phrase})" + if case["expected"]: + return assert_true(call) + return assert_false(call) diff --git a/exercises/practice/isogram/source/isogram.d b/exercises/practice/isogram/source/isogram.d index 6b4ade1d..6e24d2b8 100644 --- a/exercises/practice/isogram/source/isogram.d +++ b/exercises/practice/isogram/source/isogram.d @@ -49,5 +49,8 @@ unittest // Same first and last characters assert(!isIsogram("angola")); + + // Word with duplicated character and with two hyphens + assert(!isIsogram("up-to-date")); } } diff --git a/exercises/practice/killer-sudoku-helper/.meta/test_generator.py b/exercises/practice/killer-sudoku-helper/.meta/test_generator.py new file mode 100644 index 00000000..77af68c5 --- /dev/null +++ b/exercises/practice/killer-sudoku-helper/.meta/test_generator.py @@ -0,0 +1,19 @@ +from lib import assert_eq, d_inline_array, d_int + + +def bitset(digits): + """Represent a set of digits as an integer, with bit 0 for the digit 1.""" + return sum(1 << (digit - 1) for digit in digits) + + +def gen_case(case): + prop = case["property"] + cage = case["input"]["cage"] + total = d_int(cage["sum"]) + size = d_int(cage["size"]) + exclude = d_int(bitset(cage["exclude"])) + expected = d_inline_array(sorted(bitset(digits) for digits in case["expected"])) + return [ + f"ushort[] expected = {expected};", + assert_eq(f"{prop}({total}, {size}, {exclude})", "expected"), + ] diff --git a/exercises/practice/killer-sudoku-helper/source/killer_sudoku_helper.d b/exercises/practice/killer-sudoku-helper/source/killer_sudoku_helper.d index ac950c9b..1c16d454 100644 --- a/exercises/practice/killer-sudoku-helper/source/killer_sudoku_helper.d +++ b/exercises/practice/killer-sudoku-helper/source/killer_sudoku_helper.d @@ -7,11 +7,9 @@ pure ushort[] combinations(int sum, int size, ushort exclude) unittest { - import std.algorithm.comparison : equal; - immutable int allTestsEnabled = 0; - // Trivial 1-digit cages-1 + // Trivial 1-digit cages - 1 { ushort[] expected = [1]; assert(combinations(1, 1, 0) == expected); @@ -19,49 +17,49 @@ unittest static if (allTestsEnabled) { - // Trivial 1-digit cages-2 + // Trivial 1-digit cages - 2 { ushort[] expected = [2]; assert(combinations(2, 1, 0) == expected); } - // Trivial 1-digit cages-3 + // Trivial 1-digit cages - 3 { ushort[] expected = [4]; assert(combinations(3, 1, 0) == expected); } - // Trivial 1-digit cages-4 + // Trivial 1-digit cages - 4 { ushort[] expected = [8]; assert(combinations(4, 1, 0) == expected); } - // Trivial 1-digit cages-5 + // Trivial 1-digit cages - 5 { ushort[] expected = [16]; assert(combinations(5, 1, 0) == expected); } - // Trivial 1-digit cages-6 + // Trivial 1-digit cages - 6 { ushort[] expected = [32]; assert(combinations(6, 1, 0) == expected); } - // Trivial 1-digit cages-7 + // Trivial 1-digit cages - 7 { ushort[] expected = [64]; assert(combinations(7, 1, 0) == expected); } - // Trivial 1-digit cages-8 + // Trivial 1-digit cages - 8 { ushort[] expected = [128]; assert(combinations(8, 1, 0) == expected); } - // Trivial 1-digit cages-9 + // Trivial 1-digit cages - 9 { ushort[] expected = [256]; assert(combinations(9, 1, 0) == expected); diff --git a/exercises/practice/nth-prime/.meta/test_generator.py b/exercises/practice/nth-prime/.meta/test_generator.py new file mode 100644 index 00000000..ee94fb31 --- /dev/null +++ b/exercises/practice/nth-prime/.meta/test_generator.py @@ -0,0 +1,10 @@ +from lib import assert_eq, assert_throws, d_grouped_int, is_error + + +def gen_case(case): + prop = case["property"] + number = d_grouped_int(case["input"]["number"]) + call = f"{prop}({number})" + if is_error(case["expected"]): + return assert_throws(call) + return assert_eq(call, d_grouped_int(case["expected"])) diff --git a/exercises/practice/nth-prime/source/nth_prime.d b/exercises/practice/nth-prime/source/nth_prime.d index 866d59fa..d6ba9b02 100644 --- a/exercises/practice/nth-prime/source/nth_prime.d +++ b/exercises/practice/nth-prime/source/nth_prime.d @@ -23,10 +23,9 @@ unittest assert(prime(6) == 13); // Big prime - assert(prime(10_001) == 10_4743); + assert(prime(10_001) == 104_743); // There is no zeroth prime assertThrown(prime(0)); } - } diff --git a/exercises/practice/pangram/.meta/additional-test-cases.json b/exercises/practice/pangram/.meta/additional-test-cases.json new file mode 100644 index 00000000..0d88e307 --- /dev/null +++ b/exercises/practice/pangram/.meta/additional-test-cases.json @@ -0,0 +1,18 @@ +[ + { + "description": "upper case and punctuation", + "property": "isPangram", + "input": { + "sentence": "\"FIVE QUACKING ZEPHYRS JOLT MY WAX BED.\"" + }, + "expected": true + }, + { + "description": "upper case, missing the letter 'x'", + "property": "isPangram", + "input": { + "sentence": "THE QUICK BROWN FISH JUMPS OVER THE LAZY DOG" + }, + "expected": false + } +] diff --git a/exercises/practice/pangram/.meta/test_generator.py b/exercises/practice/pangram/.meta/test_generator.py new file mode 100644 index 00000000..5f67300f --- /dev/null +++ b/exercises/practice/pangram/.meta/test_generator.py @@ -0,0 +1,14 @@ +from lib import assert_false, assert_true, d_string + + +def describe(case): + return case["description"] + + +def gen_case(case): + prop = case["property"] + sentence = d_string(case["input"]["sentence"]) + call = f"{prop}({sentence})" + if case["expected"]: + return assert_true(call) + return assert_false(call) diff --git a/exercises/practice/pangram/source/pangram.d b/exercises/practice/pangram/source/pangram.d index f37aabaa..0ba51f98 100644 --- a/exercises/practice/pangram/source/pangram.d +++ b/exercises/practice/pangram/source/pangram.d @@ -9,36 +9,42 @@ unittest { immutable int allTestsEnabled = 0; - // Empty sentence + // empty sentence assert(!isPangram("")); static if (allTestsEnabled) { - // Perfect lower case + // perfect lower case assert(isPangram("abcdefghijklmnopqrstuvwxyz")); - // Only lower case - assert(!isPangram("the quick brown fish jumps over the lazy dog")); + // only lower case + assert(isPangram("the quick brown fox jumps over the lazy dog")); - // Missing the letter 'x' + // missing the letter 'x' assert(!isPangram("a quick movement of the enemy will jeopardize five gunboats")); - // Missing the letter 'h' + // missing the letter 'h' assert(!isPangram("five boxing wizards jump quickly at it")); - // With underscores + // with underscores assert(isPangram("the_quick_brown_fox_jumps_over_the_lazy_dog")); - // With numbers + // with numbers assert(isPangram("the 1 quick brown fox jumps over the 2 lazy dogs")); - // Missing letters replaced by numbers + // missing letters replaced by numbers assert(!isPangram("7h3 qu1ck brown fox jumps ov3r 7h3 lazy dog")); - // Mixed case and punctuation - assert(isPangram("\"Five quacking Zephyrs jolt my wax bed\"")); + // mixed case and punctuation + assert(isPangram("\"Five quacking Zephyrs jolt my wax bed.\"")); // a-m and A-M are 26 different characters but not a pangram assert(!isPangram("abcdefghijklm ABCDEFGHIJKLM")); + + // upper case and punctuation + assert(isPangram("\"FIVE QUACKING ZEPHYRS JOLT MY WAX BED.\"")); + + // upper case, missing the letter 'x' + assert(!isPangram("THE QUICK BROWN FISH JUMPS OVER THE LAZY DOG")); } } diff --git a/exercises/practice/perfect-numbers/.meta/test_generator.py b/exercises/practice/perfect-numbers/.meta/test_generator.py new file mode 100644 index 00000000..1cefa2b6 --- /dev/null +++ b/exercises/practice/perfect-numbers/.meta/test_generator.py @@ -0,0 +1,14 @@ +from lib import assert_eq, assert_throws, d_grouped_int, is_error + + +def describe(case): + return case["description"] + + +def gen_case(case): + prop = case["property"] + number = d_grouped_int(case["input"]["number"]) + call = f"{prop}({number})" + if is_error(case["expected"]): + return assert_throws(call) + return assert_eq(call, f"Classification.{case['expected'].upper()}") diff --git a/exercises/practice/perfect-numbers/source/perfect_numbers.d b/exercises/practice/perfect-numbers/source/perfect_numbers.d index 9dfcef67..ac1754bb 100644 --- a/exercises/practice/perfect-numbers/source/perfect_numbers.d +++ b/exercises/practice/perfect-numbers/source/perfect_numbers.d @@ -18,20 +18,16 @@ unittest immutable int allTestsEnabled = 0; - // Perfect numbers - // Smallest perfect number is classified correctly assert(classify(6) == Classification.PERFECT); - // Medium perfect number is classified correctly - assert(classify(28) == Classification.PERFECT); - - // Large perfect number is classified correctly - assert(classify(33_550_336) == Classification.PERFECT); - static if (allTestsEnabled) { - // Abundant numbers + // Medium perfect number is classified correctly + assert(classify(28) == Classification.PERFECT); + + // Large perfect number is classified correctly + assert(classify(33_550_336) == Classification.PERFECT); // Smallest abundant number is classified correctly assert(classify(12) == Classification.ABUNDANT); @@ -45,8 +41,6 @@ unittest // Perfect square abundant number is classified correctly assert(classify(196) == Classification.ABUNDANT); - // Deficient numbers - // Smallest prime deficient number is classified correctly assert(classify(2) == Classification.DEFICIENT); @@ -62,13 +56,10 @@ unittest // Edge case (no factors other than itself) is classified correctly assert(classify(1) == Classification.DEFICIENT); - // Invalid inputs - - // Zero is rejected (not a natural number) + // Zero is rejected (as it is not a positive integer) assertThrown(classify(0)); - // Negative integer is rejected (not a natural number) + // Negative integer is rejected (as it is not a positive integer) assertThrown(classify(-1)); } - } diff --git a/exercises/practice/prime-factors/.meta/test_generator.py b/exercises/practice/prime-factors/.meta/test_generator.py new file mode 100644 index 00000000..81a64fa2 --- /dev/null +++ b/exercises/practice/prime-factors/.meta/test_generator.py @@ -0,0 +1,8 @@ +from lib import assert_eq, d_grouped_int, d_inline_array + + +def gen_case(case): + prop = case["property"] + value = d_grouped_int(case["input"]["value"]) + expected = d_inline_array(case["expected"], d_grouped_int) + return assert_eq(f"{prop}({value})", expected) diff --git a/exercises/practice/prime-factors/source/prime_factors.d b/exercises/practice/prime-factors/source/prime_factors.d index b80bc529..39c7992e 100644 --- a/exercises/practice/prime-factors/source/prime_factors.d +++ b/exercises/practice/prime-factors/source/prime_factors.d @@ -17,12 +17,27 @@ unittest // Prime number assert(factors(2) == [2]); + // Another prime number + assert(factors(3) == [3]); + // Square of a prime assert(factors(9) == [3, 3]); + // Product of first prime + assert(factors(4) == [2, 2]); + // Cube of a prime assert(factors(8) == [2, 2, 2]); + // Product of second prime + assert(factors(27) == [3, 3, 3]); + + // Product of third prime + assert(factors(625) == [5, 5, 5, 5]); + + // Product of first and second prime + assert(factors(6) == [2, 3]); + // Product of primes and non-primes assert(factors(12) == [2, 2, 3]); diff --git a/exercises/practice/protein-translation/.meta/test_generator.py b/exercises/practice/protein-translation/.meta/test_generator.py new file mode 100644 index 00000000..2703ea5b --- /dev/null +++ b/exercises/practice/protein-translation/.meta/test_generator.py @@ -0,0 +1,10 @@ +from lib import assert_eq, assert_throws, d_inline_array, d_string, is_error + + +def gen_case(case): + prop = case["property"] + strand = d_string(case["input"]["strand"]) + call = f"{prop}({strand})" + if is_error(case["expected"]): + return assert_throws(call) + return assert_eq(call, d_inline_array(case["expected"], d_string)) diff --git a/exercises/practice/protein-translation/.meta/tests.toml b/exercises/practice/protein-translation/.meta/tests.toml index de680e39..b465aed2 100644 --- a/exercises/practice/protein-translation/.meta/tests.toml +++ b/exercises/practice/protein-translation/.meta/tests.toml @@ -92,7 +92,6 @@ description = "Sequence of two non-STOP codons does not translate to a STOP codo [1e75ea2a-f907-4994-ae5c-118632a1cb0f] description = "Non-existing codon can't translate" -include = false [9eac93f3-627a-4c90-8653-6d0a0595bc6f] description = "Unknown amino acids, not part of a codon, can't translate" diff --git a/exercises/practice/protein-translation/example/protein_translation.d b/exercises/practice/protein-translation/example/protein_translation.d index 95131c2f..8d2cc695 100644 --- a/exercises/practice/protein-translation/example/protein_translation.d +++ b/exercises/practice/protein-translation/example/protein_translation.d @@ -28,18 +28,17 @@ pure string[] proteins(immutable string strand) { string[] codons = strand.chunks(3).map!(chunk => chunk.array.to!string).array; string[] results = []; - + foreach (codon; codons) { if(codon!in availableProteins) throw new Exception("Invalid codon"); - + string protein = availableProteins[codon]; if (protein == "STOP") return results; - + results ~= protein; }; - + return results; } - diff --git a/exercises/practice/protein-translation/source/protein_translation.d b/exercises/practice/protein-translation/source/protein_translation.d index cecde626..b4ab5a17 100644 --- a/exercises/practice/protein-translation/source/protein_translation.d +++ b/exercises/practice/protein-translation/source/protein_translation.d @@ -9,7 +9,7 @@ unittest { import std.exception : assertThrown; - immutable int allTestsEnabled = 1; + immutable int allTestsEnabled = 0; // Empty RNA sequence results in no proteins assert(proteins("") == []); @@ -107,4 +107,3 @@ unittest assert(proteins("UUCUUCUAAUGGU") == ["Phenylalanine", "Phenylalanine"]); } } - diff --git a/exercises/practice/proverb/.meta/test_generator.py b/exercises/practice/proverb/.meta/test_generator.py new file mode 100644 index 00000000..469b0713 --- /dev/null +++ b/exercises/practice/proverb/.meta/test_generator.py @@ -0,0 +1,11 @@ +from lib import INDENT, assert_eq, d_inline_array, d_lines, d_string + + +def gen_case(case): + prop = case["property"] + strings = d_inline_array(case["input"]["strings"], d_string) + expected = d_lines(case["expected"]) or INDENT + '""' + return [ + f"string expected =\n{expected};", + assert_eq(f"{prop}({strings})", "expected"), + ] diff --git a/exercises/practice/proverb/example/proverb.d b/exercises/practice/proverb/example/proverb.d index 54b9b79e..1ee7f08e 100644 --- a/exercises/practice/proverb/example/proverb.d +++ b/exercises/practice/proverb/example/proverb.d @@ -5,14 +5,14 @@ import std.array; pure string recite(immutable string[] strings) { if (strings.length == 0) return ""; - + string[] fragments; foreach (i, str; strings[0 .. strings.length - 1]) { fragments ~= "For want of a " ~ str ~ " the " ~ strings[i+1] ~ " was lost."; } - + fragments ~= "And all for the want of a " ~ strings[0] ~ "."; - + return fragments.join("\n"); } diff --git a/exercises/practice/proverb/source/proverb.d b/exercises/practice/proverb/source/proverb.d index d4cf5c9e..a51dec2d 100644 --- a/exercises/practice/proverb/source/proverb.d +++ b/exercises/practice/proverb/source/proverb.d @@ -11,7 +11,8 @@ unittest // Zero pieces { - string expected = ""; + string expected = + ""; assert(recite([]) == expected); } @@ -19,47 +20,48 @@ unittest { // One piece { - string expected = "And all for the want of a nail."; + string expected = + "And all for the want of a nail."; assert(recite(["nail"]) == expected); } // Two pieces { - string expected = "For want of a nail the shoe was lost.\n" - ~ "And all for the want of a nail."; + string expected = + "For want of a nail the shoe was lost.\n" ~ + "And all for the want of a nail."; assert(recite(["nail", "shoe"]) == expected); } // Three pieces { - string expected = "For want of a nail the shoe was lost.\n" - ~ "For want of a shoe the horse was lost.\n" - ~ "And all for the want of a nail."; + string expected = + "For want of a nail the shoe was lost.\n" ~ + "For want of a shoe the horse was lost.\n" ~ + "And all for the want of a nail."; assert(recite(["nail", "shoe", "horse"]) == expected); } // Full proverb { - string expected = "For want of a nail the shoe was lost.\n" - ~ "For want of a shoe the horse was lost.\n" - ~ "For want of a horse the rider was lost.\n" - ~ "For want of a rider the message was lost.\n" - ~ "For want of a message the battle was lost.\n" - ~ "For want of a battle the kingdom was lost.\n" - ~ "And all for the want of a nail."; - immutable string[] strings = [ - "nail", "shoe", "horse", "rider", - "message", "battle", "kingdom" - ]; - assert(recite(strings) == expected); + string expected = + "For want of a nail the shoe was lost.\n" ~ + "For want of a shoe the horse was lost.\n" ~ + "For want of a horse the rider was lost.\n" ~ + "For want of a rider the message was lost.\n" ~ + "For want of a message the battle was lost.\n" ~ + "For want of a battle the kingdom was lost.\n" ~ + "And all for the want of a nail."; + assert(recite(["nail", "shoe", "horse", "rider", "message", "battle", "kingdom"]) == expected); } // Four pieces modernized { - string expected = "For want of a pin the gun was lost.\n" - ~ "For want of a gun the soldier was lost.\n" - ~ "For want of a soldier the battle was lost.\n" - ~ "And all for the want of a pin."; + string expected = + "For want of a pin the gun was lost.\n" ~ + "For want of a gun the soldier was lost.\n" ~ + "For want of a soldier the battle was lost.\n" ~ + "And all for the want of a pin."; assert(recite(["pin", "gun", "soldier", "battle"]) == expected); } } diff --git a/exercises/practice/rna-transcription/.meta/test_generator.py b/exercises/practice/rna-transcription/.meta/test_generator.py new file mode 100644 index 00000000..5095004b --- /dev/null +++ b/exercises/practice/rna-transcription/.meta/test_generator.py @@ -0,0 +1,8 @@ +from lib import assert_eq, d_string + + +def gen_case(case): + prop = case["property"] + dna = d_string(case["input"]["dna"]) + expected = d_string(case["expected"]) + return assert_eq(f"{prop}({dna})", expected) diff --git a/exercises/practice/rna-transcription/source/rna_transcription.d b/exercises/practice/rna-transcription/source/rna_transcription.d index 49a8ddf1..bfd9a12d 100644 --- a/exercises/practice/rna-transcription/source/rna_transcription.d +++ b/exercises/practice/rna-transcription/source/rna_transcription.d @@ -7,8 +7,6 @@ pure string toRna(immutable string dna) unittest { - import std.exception : assertThrown; - immutable int allTestsEnabled = 0; // Empty RNA sequence @@ -31,5 +29,4 @@ unittest // RNA complement assert(toRna("ACGTGGTCTTAA") == "UGCACCAGAAUU"); } - } diff --git a/exercises/practice/rotational-cipher/.meta/test_generator.py b/exercises/practice/rotational-cipher/.meta/test_generator.py new file mode 100644 index 00000000..cf4a69ec --- /dev/null +++ b/exercises/practice/rotational-cipher/.meta/test_generator.py @@ -0,0 +1,13 @@ +from lib import assert_eq, d_int, d_string + + +def describe(case): + return case["description"] + + +def gen_case(case): + prop = case["property"] + text = d_string(case["input"]["text"]) + shift_key = d_int(case["input"]["shiftKey"]) + expected = d_string(case["expected"]) + return [assert_eq(expected, f"{prop}({text}, {shift_key})")] diff --git a/exercises/practice/rotational-cipher/source/rotational_cipher.d b/exercises/practice/rotational-cipher/source/rotational_cipher.d index d8c010ae..0f43342b 100644 --- a/exercises/practice/rotational-cipher/source/rotational_cipher.d +++ b/exercises/practice/rotational-cipher/source/rotational_cipher.d @@ -7,7 +7,6 @@ pure string rotate(immutable string text, immutable int shiftKey) unittest { - immutable int allTestsEnabled = 0; // rotate a by 0, same output as input @@ -59,10 +58,7 @@ unittest // rotate all letters { - immutable text = "The quick brown fox jumps over the lazy dog."; - immutable shiftKey = 13; - immutable expected = "Gur dhvpx oebja sbk whzcf bire gur ynml qbt."; - assert(expected == rotate(text, shiftKey)); + assert("Gur dhvpx oebja sbk whzcf bire gur ynml qbt." == rotate("The quick brown fox jumps over the lazy dog.", 13)); } } -} \ No newline at end of file +} diff --git a/exercises/practice/sum-of-multiples/.meta/test_generator.py b/exercises/practice/sum-of-multiples/.meta/test_generator.py new file mode 100644 index 00000000..2a2c531c --- /dev/null +++ b/exercises/practice/sum-of-multiples/.meta/test_generator.py @@ -0,0 +1,8 @@ +from lib import assert_eq, d_inline_array, d_int + + +def gen_case(case): + factors = d_inline_array(case["input"]["factors"]) + limit = d_int(case["input"]["limit"]) + expected = d_int(case["expected"]) + return assert_eq(f"calculateSum({factors}, {limit})", expected) diff --git a/exercises/practice/sum-of-multiples/source/sum_of_multiples.d b/exercises/practice/sum-of-multiples/source/sum_of_multiples.d index 0641ab82..e42a46b5 100644 --- a/exercises/practice/sum-of-multiples/source/sum_of_multiples.d +++ b/exercises/practice/sum-of-multiples/source/sum_of_multiples.d @@ -48,7 +48,7 @@ unittest assert(calculateSum([1], 100) == 4950); // No factors means an empty sum - assert(calculateSum([0], 10000) == 0); + assert(calculateSum([], 10000) == 0); // The only multiple of 0 is 0 assert(calculateSum([0], 1) == 0); diff --git a/exercises/practice/wordy/.meta/additional-test-cases.json b/exercises/practice/wordy/.meta/additional-test-cases.json new file mode 100644 index 00000000..b26a7cf5 --- /dev/null +++ b/exercises/practice/wordy/.meta/additional-test-cases.json @@ -0,0 +1,18 @@ +[ + { + "description": "large number multiplication and addition", + "property": "answer", + "input": { + "question": "What is 342668567865 multiplied by 348 plus 6576456942334?" + }, + "expected": 125825118559354 + }, + { + "description": "large number division and subtraction", + "property": "answer", + "input": { + "question": "What is 6548074074001254 divided by 654 minus 9876543210001?" + }, + "expected": 135802468900 + } +] diff --git a/exercises/practice/wordy/.meta/test_generator.py b/exercises/practice/wordy/.meta/test_generator.py new file mode 100644 index 00000000..0f413a53 --- /dev/null +++ b/exercises/practice/wordy/.meta/test_generator.py @@ -0,0 +1,14 @@ +from lib import assert_eq, assert_throws, d_int, d_string, is_error + + +def gen_case(case): + prop = case["property"] + question = d_string(case["input"]["question"]) + call = f"{prop}(question)" + + lines = [f"immutable question = {question};"] + if is_error(case["expected"]): + lines.append(assert_throws(call)) + else: + lines.append(assert_eq(call, d_int(case["expected"]))) + return lines diff --git a/exercises/practice/wordy/source/wordy.d b/exercises/practice/wordy/source/wordy.d index 61ca263a..1c589258 100644 --- a/exercises/practice/wordy/source/wordy.d +++ b/exercises/practice/wordy/source/wordy.d @@ -178,13 +178,13 @@ unittest // Large number multiplication and addition { immutable question = "What is 342668567865 multiplied by 348 plus 6576456942334?"; - assert(answer(question) == 125825118559354L); + assert(answer(question) == 125825118559354); } // Large number division and subtraction { immutable question = "What is 6548074074001254 divided by 654 minus 9876543210001?"; - assert(answer(question) == 135802468900L); + assert(answer(question) == 135802468900); } } } diff --git a/exercises/practice/zebra-puzzle/.meta/test_generator.py b/exercises/practice/zebra-puzzle/.meta/test_generator.py new file mode 100644 index 00000000..be58a8e5 --- /dev/null +++ b/exercises/practice/zebra-puzzle/.meta/test_generator.py @@ -0,0 +1,10 @@ +from lib import assert_eq + + +def gen_case(case): + prop = case["property"] + expected = case["expected"].lower() + return [ + "ZebraPuzzle zebraPuzzle = new ZebraPuzzle();", + assert_eq(f"zebraPuzzle.{prop}()", f"Nationality.{expected}"), + ] diff --git a/exercises/practice/zebra-puzzle/source/zebra_puzzle.d b/exercises/practice/zebra-puzzle/source/zebra_puzzle.d index 9927bd1f..2be5ad72 100644 --- a/exercises/practice/zebra-puzzle/source/zebra_puzzle.d +++ b/exercises/practice/zebra-puzzle/source/zebra_puzzle.d @@ -29,7 +29,20 @@ class ZebraPuzzle unittest { - ZebraPuzzle zebraPuzzle = new ZebraPuzzle(); - assert(zebraPuzzle.drinksWater() == Nationality.norwegian); - assert(zebraPuzzle.ownsZebra() == Nationality.japanese); + immutable int allTestsEnabled = 0; + + // Resident who drinks water + { + ZebraPuzzle zebraPuzzle = new ZebraPuzzle(); + assert(zebraPuzzle.drinksWater() == Nationality.norwegian); + } + + static if (allTestsEnabled) + { + // Resident who owns zebra + { + ZebraPuzzle zebraPuzzle = new ZebraPuzzle(); + assert(zebraPuzzle.ownsZebra() == Nationality.japanese); + } + } }