diff --git a/exercises/practice/acronym/.meta/test_generator.py b/exercises/practice/acronym/.meta/test_generator.py new file mode 100644 index 00000000..4362bc68 --- /dev/null +++ b/exercises/practice/acronym/.meta/test_generator.py @@ -0,0 +1,11 @@ +from lib import assert_eq, d_string + + +def gen_case(case): + prop = case["property"] + phrase = d_string(case["input"]["phrase"]) + expected = d_string(case["expected"]) + return [ + f"string phrase = {phrase};", + assert_eq(f"{prop}(phrase)", expected), + ] diff --git a/exercises/practice/acronym/source/acronym.d b/exercises/practice/acronym/source/acronym.d index 7982a3f9..f17c56f5 100644 --- a/exercises/practice/acronym/source/acronym.d +++ b/exercises/practice/acronym/source/acronym.d @@ -9,7 +9,7 @@ unittest { immutable int allTestsEnabled = 0; - // Basic abbreviation + // Basic { string phrase = "Portable Network Graphics"; assert(abbreviate(phrase) == "PNG"); @@ -17,7 +17,6 @@ unittest static if (allTestsEnabled) { - // Lowercase words { string phrase = "Ruby on Rails"; @@ -36,7 +35,7 @@ unittest assert(abbreviate(phrase) == "GIMP"); } - // punctuation without whitespace + // Punctuation without whitespace { string phrase = "Complementary metal-oxide semiconductor"; assert(abbreviate(phrase) == "CMOS"); diff --git a/exercises/practice/affine-cipher/.meta/test_generator.py b/exercises/practice/affine-cipher/.meta/test_generator.py new file mode 100644 index 00000000..057eaf11 --- /dev/null +++ b/exercises/practice/affine-cipher/.meta/test_generator.py @@ -0,0 +1,12 @@ +from lib import assert_equal, assert_throws, d_int, d_string, is_error + + +def gen_case(case): + prop = case["property"] + phrase = d_string(case["input"]["phrase"]) + a = d_int(case["input"]["key"]["a"]) + b = d_int(case["input"]["key"]["b"]) + call = f"{prop}({phrase}, {a}, {b})" + if is_error(case["expected"]): + return assert_throws(call) + return assert_equal(d_string(case["expected"]), call) diff --git a/exercises/practice/affine-cipher/example/affine_cipher.d b/exercises/practice/affine-cipher/example/affine_cipher.d index 6324dc55..5a921679 100644 --- a/exercises/practice/affine-cipher/example/affine_cipher.d +++ b/exercises/practice/affine-cipher/example/affine_cipher.d @@ -72,62 +72,3 @@ private immutable uint[] inverses = [ 25, 0 ]; - -unittest -{ - import std.algorithm.comparison : equal; - import std.exception : assertThrown; - - immutable int allTestsEnabled = 0; - - // Encode-encode yes - assert(equal("xbt", encode("yes", 5, 7))); - - static if (allTestsEnabled) - { - // Encode-encode no - assert(equal("fu", encode("no", 15, 18))); - - // Encode-encode OMG - assert(equal("lvz", encode("OMG", 21, 3))); - - // Encode-encode O M G - assert(equal("hjp", encode("O M G", 25, 47))); - - // Encode-encode mindblowingly - assert(equal("rzcwa gnxzc dgt", encode("mindblowingly", 11, 15))); - - // Encode-encode numbers - assert(equal("jqgjc rw123 jqgjc rw", encode("Testing,1 2 3, testing.", 3, 4))); - - // Encode-encode deep thought - assert(equal("iynia fdqfb ifje", encode("Truth is fiction.", 5, 17))); - - // Encode-encode all the letters - assert(equal("swxtj npvyk lruol iejdc blaxk swxmh qzglf", encode("The quick brown fox jumps over the lazy dog.", 17, 33))); - - // Encode-encode with a not coprime to m - assertThrown(encode("This is a test.", 6, 17)); - - // Decode-decode exercism - assert(equal("exercism", decode("tytgn fjr", 3, 7))); - - // Decode-decode a sentence - assert(equal("anobstacleisoftenasteppingstone", decode("qdwju nqcro muwhn odqun oppmd aunwd o", 19, 16))); - - // Decode-decode numbers - assert(equal("testing123testing", decode("odpoz ub123 odpoz ub", 25, 7))); - - // Decode-decode all the letters - assert(equal("thequickbrownfoxjumpsoverthelazydog", decode("swxtj npvyk lruol iejdc blaxk swxmh qzglf", 17, 33))); - - // Decode-decode with no spaces in input - assert(equal("thequickbrownfoxjumpsoverthelazydog", decode("swxtjnpvyklruoliejdcblaxkswxmhqzglf", 17, 33))); - - // Decode-decode with too many spaces - assert(equal("jollygreengiant", decode("vszzm cly yd cg qdp", 15, 16))); - - // Decode-decode with a not coprime to m - assertThrown(decode("Test", 13, 5)); - } -} diff --git a/exercises/practice/affine-cipher/source/affine_cipher.d b/exercises/practice/affine-cipher/source/affine_cipher.d index ee9f7ce9..932df912 100644 --- a/exercises/practice/affine-cipher/source/affine_cipher.d +++ b/exercises/practice/affine-cipher/source/affine_cipher.d @@ -17,54 +17,54 @@ unittest immutable int allTestsEnabled = 0; - // Encode-encode yes + // Encode - encode yes assert(equal("xbt", encode("yes", 5, 7))); static if (allTestsEnabled) { - // Encode-encode no + // Encode - encode no assert(equal("fu", encode("no", 15, 18))); - // Encode-encode OMG + // Encode - encode OMG assert(equal("lvz", encode("OMG", 21, 3))); - // Encode-encode O M G + // Encode - encode O M G assert(equal("hjp", encode("O M G", 25, 47))); - // Encode-encode mindblowingly + // Encode - encode mindblowingly assert(equal("rzcwa gnxzc dgt", encode("mindblowingly", 11, 15))); - // Encode-encode numbers + // Encode - encode numbers assert(equal("jqgjc rw123 jqgjc rw", encode("Testing,1 2 3, testing.", 3, 4))); - // Encode-encode deep thought + // Encode - encode deep thought assert(equal("iynia fdqfb ifje", encode("Truth is fiction.", 5, 17))); - // Encode-encode all the letters + // Encode - encode all the letters assert(equal("swxtj npvyk lruol iejdc blaxk swxmh qzglf", encode("The quick brown fox jumps over the lazy dog.", 17, 33))); - // Encode-encode with a not coprime to m + // Encode - encode with a not coprime to m assertThrown(encode("This is a test.", 6, 17)); - // Decode-decode exercism + // Decode - decode exercism assert(equal("exercism", decode("tytgn fjr", 3, 7))); - // Decode-decode a sentence + // Decode - decode a sentence assert(equal("anobstacleisoftenasteppingstone", decode("qdwju nqcro muwhn odqun oppmd aunwd o", 19, 16))); - // Decode-decode numbers + // Decode - decode numbers assert(equal("testing123testing", decode("odpoz ub123 odpoz ub", 25, 7))); - // Decode-decode all the letters + // Decode - decode all the letters assert(equal("thequickbrownfoxjumpsoverthelazydog", decode("swxtj npvyk lruol iejdc blaxk swxmh qzglf", 17, 33))); - // Decode-decode with no spaces in input + // Decode - decode with no spaces in input assert(equal("thequickbrownfoxjumpsoverthelazydog", decode("swxtjnpvyklruoliejdcblaxkswxmhqzglf", 17, 33))); - // Decode-decode with too many spaces + // Decode - decode with too many spaces assert(equal("jollygreengiant", decode("vszzm cly yd cg qdp", 15, 16))); - // Decode-decode with a not coprime to m + // Decode - decode with a not coprime to m assertThrown(decode("Test", 13, 5)); } } diff --git a/exercises/practice/all-your-base/.meta/test_generator.py b/exercises/practice/all-your-base/.meta/test_generator.py index 06c83f6c..b572bd8f 100644 --- a/exercises/practice/all-your-base/.meta/test_generator.py +++ b/exercises/practice/all-your-base/.meta/test_generator.py @@ -14,4 +14,4 @@ def gen_case(case): else: lines.append(f"int[] expected = {d_array(case['expected'])};") lines.append(assert_eq(call, "expected")) - return "\n".join(lines) + return lines diff --git a/exercises/practice/alphametics/.meta/test_generator.py b/exercises/practice/alphametics/.meta/test_generator.py new file mode 100644 index 00000000..1e16671a --- /dev/null +++ b/exercises/practice/alphametics/.meta/test_generator.py @@ -0,0 +1,15 @@ +from lib import assert_eq, assert_throws, d_string + + +def solution(puzzle, digits): + """Replace each letter of the puzzle by its digit.""" + return "".join(str(digits.get(char, char)) for char in puzzle) + + +def gen_case(case): + prop = case["property"] + puzzle = case["input"]["puzzle"] + call = f"{prop}({d_string(puzzle)})" + if case["expected"] is None: + return assert_throws(call) + return assert_eq(call, d_string(solution(puzzle, case["expected"]))) diff --git a/exercises/practice/armstrong-numbers/.meta/test_generator.py b/exercises/practice/armstrong-numbers/.meta/test_generator.py new file mode 100644 index 00000000..40bae996 --- /dev/null +++ b/exercises/practice/armstrong-numbers/.meta/test_generator.py @@ -0,0 +1,10 @@ +from lib import assert_false, assert_true, d_int + + +def gen_case(case): + prop = case["property"] + number = d_int(case["input"]["number"]) + call = f"{prop}({number})" + if case["expected"]: + return assert_true(call) + return assert_false(call) diff --git a/exercises/practice/armstrong-numbers/source/armstrong_numbers.d b/exercises/practice/armstrong-numbers/source/armstrong_numbers.d index 56cd127b..b1fa28f4 100644 --- a/exercises/practice/armstrong-numbers/source/armstrong_numbers.d +++ b/exercises/practice/armstrong-numbers/source/armstrong_numbers.d @@ -14,28 +14,28 @@ unittest static if (allTestsEnabled) { - // Single digit numbers are Armstrong numbers + // Single-digit numbers are Armstrong numbers assert(isArmstrongNumber(5)); - // There are no 2 digit Armstrong numbers + // There are no two-digit Armstrong numbers assert(!isArmstrongNumber(10)); - // Three digit number that is an Armstrong number + // Three-digit number that is an Armstrong number assert(isArmstrongNumber(153)); - // Three digit number that is not an Armstrong number + // Three-digit number that is not an Armstrong number assert(!isArmstrongNumber(100)); - // Four digit number that is an Armstrong number + // Four-digit number that is an Armstrong number assert(isArmstrongNumber(9474)); - // Four digit number that is not an Armstrong number + // Four-digit number that is not an Armstrong number assert(!isArmstrongNumber(9475)); - // Seven digit number that is an Armstrong number + // Seven-digit number that is an Armstrong number assert(isArmstrongNumber(9926315)); - // Seven digit number that is not an Armstrong number + // Seven-digit number that is not an Armstrong number assert(!isArmstrongNumber(9926314)); } } diff --git a/exercises/practice/atbash-cipher/.meta/test_generator.py b/exercises/practice/atbash-cipher/.meta/test_generator.py new file mode 100644 index 00000000..0c740860 --- /dev/null +++ b/exercises/practice/atbash-cipher/.meta/test_generator.py @@ -0,0 +1,13 @@ +from lib import assert_eq, d_string + + +def describe(case): + description = case["description"] + return description[:1].upper() + description[1:] + + +def gen_case(case): + prop = case["property"] + phrase = d_string(case["input"]["phrase"]) + expected = d_string(case["expected"]) + return assert_eq(f"{prop}({phrase})", expected) diff --git a/exercises/practice/bob/.meta/test_generator.py b/exercises/practice/bob/.meta/test_generator.py new file mode 100644 index 00000000..39887266 --- /dev/null +++ b/exercises/practice/bob/.meta/test_generator.py @@ -0,0 +1,7 @@ +from lib import assert_eq, d_string + + +def gen_case(case): + text = d_string(case["input"]["heyBob"]) + expected = d_string(case["expected"]) + return assert_eq(f"hey({text})", expected) diff --git a/exercises/practice/book-store/.meta/test_generator.py b/exercises/practice/book-store/.meta/test_generator.py new file mode 100644 index 00000000..50c27dea --- /dev/null +++ b/exercises/practice/book-store/.meta/test_generator.py @@ -0,0 +1,11 @@ +from lib import assert_eq, d_inline_array, d_int + + +def gen_case(case): + prop = case["property"] + basket = d_inline_array(case["input"]["basket"]) + expected = d_int(case["expected"]) + return [ + f"immutable int[] basket = {basket};", + assert_eq(f"{prop}(basket)", expected), + ] diff --git a/exercises/practice/book-store/source/book_store.d b/exercises/practice/book-store/source/book_store.d index bad41786..9ebcec5c 100644 --- a/exercises/practice/book-store/source/book_store.d +++ b/exercises/practice/book-store/source/book_store.d @@ -101,11 +101,9 @@ unittest assert(total(basket) == 10240); } - // Check that groups of four are created properly even when there are - // more groups of three than groups of five + // Check that groups of four are created properly even when there are more groups of three than groups of five { - immutable int[] basket = [1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 4, 4, 5, 5]; + immutable int[] basket = [1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5]; assert(total(basket) == 14560); } @@ -115,8 +113,7 @@ unittest assert(total(basket) == 3360); } - // One group of one and two plus three groups of four is cheaper than - // one group of each size + // One group of one and two plus three groups of four is cheaper than one group of each size { immutable int[] basket = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5]; assert(total(basket) == 10000); diff --git a/exercises/practice/bottle-song/.meta/test_generator.py b/exercises/practice/bottle-song/.meta/test_generator.py new file mode 100644 index 00000000..6a7367fd --- /dev/null +++ b/exercises/practice/bottle-song/.meta/test_generator.py @@ -0,0 +1,11 @@ +from lib import assert_eq, d_int, d_lines + + +def gen_case(case): + prop = case["property"] + start_bottles = d_int(case["input"]["startBottles"]) + take_down = d_int(case["input"]["takeDown"]) + return [ + f"string expected =\n{d_lines(case['expected'])};", + assert_eq(f"{prop}({start_bottles}, {take_down})", "expected"), + ] diff --git a/exercises/practice/bottle-song/source/bottle_song.d b/exercises/practice/bottle-song/source/bottle_song.d index a791ab56..32a275e5 100644 --- a/exercises/practice/bottle-song/source/bottle_song.d +++ b/exercises/practice/bottle-song/source/bottle_song.d @@ -9,7 +9,7 @@ unittest { immutable int allTestsEnabled = 0; - // Verse-single verse-first generic verse + // Verse - single verse - first generic verse { string expected = "Ten green bottles hanging on the wall,\n" ~ @@ -21,7 +21,7 @@ unittest static if (allTestsEnabled) { - // Verse-single verse-last generic verse + // Verse - single verse - last generic verse { string expected = "Three green bottles hanging on the wall,\n" ~ @@ -31,7 +31,7 @@ unittest assert(recite(3, 1) == expected); } - // Verse-single verse-verse with 2 bottles + // Verse - single verse - verse with 2 bottles { string expected = "Two green bottles hanging on the wall,\n" ~ @@ -41,7 +41,7 @@ unittest assert(recite(2, 1) == expected); } - // Verse-single verse-verse with 1 bottle + // Verse - single verse - verse with 1 bottle { string expected = "One green bottle hanging on the wall,\n" ~ @@ -51,7 +51,7 @@ unittest assert(recite(1, 1) == expected); } - // Lyrics-multiple verses-first two verses + // Lyrics - multiple verses - first two verses { string expected = "Ten green bottles hanging on the wall,\n" ~ @@ -66,7 +66,7 @@ unittest assert(recite(10, 2) == expected); } - // Lyrics-multiple verses-last three verses + // Lyrics - multiple verses - last three verses { string expected = "Three green bottles hanging on the wall,\n" ~ @@ -86,7 +86,7 @@ unittest assert(recite(3, 3) == expected); } - // Lyrics-multiple verses-all verses + // Lyrics - multiple verses - all verses { string expected = "Ten green bottles hanging on the wall,\n" ~ diff --git a/exercises/practice/change/.meta/test_generator.py b/exercises/practice/change/.meta/test_generator.py new file mode 100644 index 00000000..c7ec5aa0 --- /dev/null +++ b/exercises/practice/change/.meta/test_generator.py @@ -0,0 +1,16 @@ +from lib import assert_equal, assert_throws, d_array, d_int, is_error + + +def gen_case(case): + prop = case["property"] + coins = d_array(case["input"]["coins"]) + target = d_int(case["input"]["target"]) + call = f"{prop}(coins, {target})" + + lines = [f"immutable ushort[] coins = {coins};"] + if is_error(case["expected"]): + lines.append(assert_throws(call)) + else: + lines.append(f"ushort[] expected = {d_array(case['expected'])};") + lines.append(assert_equal(call, "expected")) + return lines diff --git a/exercises/practice/connect/.meta/test_generator.py b/exercises/practice/connect/.meta/test_generator.py new file mode 100644 index 00000000..a9677147 --- /dev/null +++ b/exercises/practice/connect/.meta/test_generator.py @@ -0,0 +1,11 @@ +from lib import assert_eq, d_array, d_string + + +def gen_case(case): + prop = case["property"] + board = d_array(case["input"]["board"], d_string) + expected = d_string(case["expected"]) + return [ + f"immutable string[] board = {board};", + assert_eq(f"{prop}(board)", expected), + ] diff --git a/exercises/practice/darts/.meta/test_generator.py b/exercises/practice/darts/.meta/test_generator.py new file mode 100644 index 00000000..c6e6107d --- /dev/null +++ b/exercises/practice/darts/.meta/test_generator.py @@ -0,0 +1,9 @@ +from lib import assert_eq, d_int + + +def gen_case(case): + prop = case["property"] + x = case["input"]["x"] + y = case["input"]["y"] + expected = d_int(case["expected"]) + return assert_eq(f"{prop}({x}, {y})", expected) diff --git a/exercises/practice/darts/source/darts.d b/exercises/practice/darts/source/darts.d index fa8a6563..7188c0ef 100644 --- a/exercises/practice/darts/source/darts.d +++ b/exercises/practice/darts/source/darts.d @@ -23,10 +23,10 @@ unittest // On the inner circle assert(score(0, -1) == 10); - // Exactly on centre + // Exactly on center assert(score(0, 0) == 10); - // Near the centre + // Near the center assert(score(-0.1, -0.1) == 10); // Just within the inner circle diff --git a/exercises/practice/diamond/.meta/test_generator.py b/exercises/practice/diamond/.meta/test_generator.py new file mode 100644 index 00000000..ecc80b3a --- /dev/null +++ b/exercises/practice/diamond/.meta/test_generator.py @@ -0,0 +1,11 @@ +from lib import assert_eq, d_array, d_string + + +def gen_case(case): + prop = case["property"] + letter = case["input"]["letter"] + expected = d_array(case["expected"], d_string) + return [ + f"string[] expected = {expected};", + assert_eq(f"{prop}('{letter}')", "expected"), + ] diff --git a/exercises/practice/dominoes/.meta/test_generator.py b/exercises/practice/dominoes/.meta/test_generator.py new file mode 100644 index 00000000..423d13e7 --- /dev/null +++ b/exercises/practice/dominoes/.meta/test_generator.py @@ -0,0 +1,19 @@ +from lib import assert_false, assert_true, d_inline_array + + +def d_stone(stone): + left, right = stone + return f"Stone({left}, {right})" + + +def gen_case(case): + prop = case["property"] + dominoes = case["input"]["dominoes"] + declaration = "immutable Stone[] dominoes" + if dominoes: + declaration += f" = {d_inline_array(dominoes, d_stone)}" + call = f"{prop}(dominoes)" + return [ + f"{declaration};", + assert_true(call) if case["expected"] else assert_false(call), + ] diff --git a/exercises/practice/eliuds-eggs/.meta/test_generator.py b/exercises/practice/eliuds-eggs/.meta/test_generator.py new file mode 100644 index 00000000..f6697c90 --- /dev/null +++ b/exercises/practice/eliuds-eggs/.meta/test_generator.py @@ -0,0 +1,8 @@ +from lib import assert_eq, d_grouped_int, d_int + + +def gen_case(case): + prop = case["property"] + number = d_grouped_int(case["input"]["number"]) + expected = d_int(case["expected"]) + return assert_eq(f"{prop}({number})", expected) diff --git a/exercises/practice/eliuds-eggs/source/eliuds_eggs.d b/exercises/practice/eliuds-eggs/source/eliuds_eggs.d index fc9f4b79..6ce4f244 100644 --- a/exercises/practice/eliuds-eggs/source/eliuds_eggs.d +++ b/exercises/practice/eliuds-eggs/source/eliuds_eggs.d @@ -23,5 +23,4 @@ unittest // 13 eggs assert(eggCount(2_000_000_000) == 13); } - } diff --git a/exercises/practice/flower-field/.meta/test_generator.py b/exercises/practice/flower-field/.meta/test_generator.py new file mode 100644 index 00000000..1039a08b --- /dev/null +++ b/exercises/practice/flower-field/.meta/test_generator.py @@ -0,0 +1,12 @@ +from lib import assert_eq, d_array, d_string + + +def gen_case(case): + prop = case["property"] + garden = d_array(case["input"]["garden"], d_string) + expected = d_array(case["expected"], d_string) + return [ + f"immutable string[] garden = {garden};", + f"string[] expected = {expected};", + assert_eq(f"{prop}(garden)", "expected"), + ] diff --git a/exercises/practice/food-chain/.meta/test_generator.py b/exercises/practice/food-chain/.meta/test_generator.py new file mode 100644 index 00000000..13cbc88b --- /dev/null +++ b/exercises/practice/food-chain/.meta/test_generator.py @@ -0,0 +1,11 @@ +from lib import assert_eq, d_int, d_lines + + +def gen_case(case): + prop = case["property"] + start_verse = d_int(case["input"]["startVerse"]) + end_verse = d_int(case["input"]["endVerse"]) + return [ + f"string expected =\n{d_lines(case['expected'])};", + assert_eq(f"{prop}({start_verse}, {end_verse})", "expected"), + ] diff --git a/exercises/practice/game-of-life/.meta/test_generator.py b/exercises/practice/game-of-life/.meta/test_generator.py index 54cd1575..a4d6d782 100644 --- a/exercises/practice/game-of-life/.meta/test_generator.py +++ b/exercises/practice/game-of-life/.meta/test_generator.py @@ -5,10 +5,8 @@ def gen_case(case): prop = case["property"] matrix = d_array(case["input"]["matrix"], d_inline_array) expected = d_array(case["expected"], d_inline_array) - return "\n".join( - [ - f"immutable int[][] matrix = {matrix};", - f"int[][] expected = {expected};", - assert_eq(f"{prop}(matrix)", "expected"), - ] - ) + return [ + f"immutable int[][] matrix = {matrix};", + f"int[][] expected = {expected};", + assert_eq(f"{prop}(matrix)", "expected"), + ] diff --git a/exercises/practice/hello-world/.meta/test_generator.py b/exercises/practice/hello-world/.meta/test_generator.py new file mode 100644 index 00000000..a51abc8a --- /dev/null +++ b/exercises/practice/hello-world/.meta/test_generator.py @@ -0,0 +1,7 @@ +from lib import assert_eq, d_string + + +def gen_case(case): + prop = case["property"] + expected = d_string(case["expected"]) + return assert_eq(f"{prop}()", expected) diff --git a/exercises/practice/hello-world/source/hello_world.d b/exercises/practice/hello-world/source/hello_world.d index c8a142ea..5652b1e3 100644 --- a/exercises/practice/hello-world/source/hello_world.d +++ b/exercises/practice/hello-world/source/hello_world.d @@ -7,5 +7,6 @@ string hello() unittest { + // Say Hi! assert(hello() == "Hello, World!"); } diff --git a/exercises/practice/house/.meta/test_generator.py b/exercises/practice/house/.meta/test_generator.py new file mode 100644 index 00000000..13cbc88b --- /dev/null +++ b/exercises/practice/house/.meta/test_generator.py @@ -0,0 +1,11 @@ +from lib import assert_eq, d_int, d_lines + + +def gen_case(case): + prop = case["property"] + start_verse = d_int(case["input"]["startVerse"]) + end_verse = d_int(case["input"]["endVerse"]) + return [ + f"string expected =\n{d_lines(case['expected'])};", + assert_eq(f"{prop}({start_verse}, {end_verse})", "expected"), + ] diff --git a/exercises/practice/intergalactic-transmission/.meta/test_generator.py b/exercises/practice/intergalactic-transmission/.meta/test_generator.py new file mode 100644 index 00000000..02e3f380 --- /dev/null +++ b/exercises/practice/intergalactic-transmission/.meta/test_generator.py @@ -0,0 +1,16 @@ +from lib import assert_eq, assert_throws, d_inline_array, is_error + + +def gen_case(case): + prop = case["property"] + message = d_inline_array(case["input"]["message"], str) + call = f"{prop}(message)" + + lines = [f"immutable ubyte[] message = {message};"] + if is_error(case["expected"]): + lines.append(assert_throws(call)) + else: + expected = d_inline_array(case["expected"], str) + lines.append(f"ubyte[] expected = {expected};") + lines.append(assert_eq(call, "expected")) + return lines diff --git a/exercises/practice/kindergarten-garden/.meta/test_generator.py b/exercises/practice/kindergarten-garden/.meta/test_generator.py new file mode 100644 index 00000000..9fd7d0bd --- /dev/null +++ b/exercises/practice/kindergarten-garden/.meta/test_generator.py @@ -0,0 +1,13 @@ +from lib import assert_eq, d_array, d_string + + +def gen_case(case): + prop = case["property"] + diagram = d_string(case["input"]["diagram"]) + student = d_string(case["input"]["student"]) + expected = d_array(case["expected"], d_string) + return [ + f"immutable string diagram = {diagram};", + f"string[4] expected = {expected};", + assert_eq(f"{prop}(diagram, {student})", "expected"), + ] diff --git a/exercises/practice/kindergarten-garden/source/kindergarten_garden.d b/exercises/practice/kindergarten-garden/source/kindergarten_garden.d index 86fc27fa..cc0db620 100644 --- a/exercises/practice/kindergarten-garden/source/kindergarten_garden.d +++ b/exercises/practice/kindergarten-garden/source/kindergarten_garden.d @@ -9,7 +9,7 @@ unittest { immutable int allTestsEnabled = 0; - // Partial garden with single student + // Partial garden - garden with single student { immutable string diagram = "RC\nGG"; string[4] expected = [ @@ -23,7 +23,7 @@ unittest static if (allTestsEnabled) { - // Partial garden-different garden with single student + // Partial garden - different garden with single student { immutable string diagram = "VC\nRC"; string[4] expected = [ @@ -35,7 +35,7 @@ unittest assert(plants(diagram, "Alice") == expected); } - // Partial garden with two students + // Partial garden - garden with two students { immutable string diagram = "VVCG\nVVRC"; string[4] expected = [ @@ -47,8 +47,7 @@ unittest assert(plants(diagram, "Bob") == expected); } - // Partial garden-multiple students for the same garden with three - // students-second student's garden + // Partial garden - multiple students for the same garden with three students - second student's garden { immutable string diagram = "VVCCGG\nVVCCGG"; string[4] expected = [ @@ -60,8 +59,7 @@ unittest assert(plants(diagram, "Bob") == expected); } - // Partial garden-multiple students for the same garden with three - // students-third student's garden + // Partial garden - multiple students for the same garden with three students - third student's garden { immutable string diagram = "VVCCGG\nVVCCGG"; string[4] expected = [ @@ -73,7 +71,7 @@ unittest assert(plants(diagram, "Charlie") == expected); } - // Full garden-for Alice, first student's garden + // Full garden - for Alice, first student's garden { immutable string diagram = "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV"; string[4] expected = [ @@ -85,7 +83,7 @@ unittest assert(plants(diagram, "Alice") == expected); } - // Full garden-for Bob, second student's garden + // Full garden - for Bob, second student's garden { immutable string diagram = "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV"; string[4] expected = [ @@ -97,7 +95,7 @@ unittest assert(plants(diagram, "Bob") == expected); } - // Full garden-for Charlie + // Full garden - for Charlie { immutable string diagram = "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV"; string[4] expected = [ @@ -109,7 +107,7 @@ unittest assert(plants(diagram, "Charlie") == expected); } - // Full garden-for David + // Full garden - for David { immutable string diagram = "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV"; string[4] expected = [ @@ -121,7 +119,7 @@ unittest assert(plants(diagram, "David") == expected); } - // Full garden-for Eve + // Full garden - for Eve { immutable string diagram = "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV"; string[4] expected = [ @@ -133,7 +131,7 @@ unittest assert(plants(diagram, "Eve") == expected); } - // Full garden-for Fred + // Full garden - for Fred { immutable string diagram = "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV"; string[4] expected = [ @@ -145,7 +143,7 @@ unittest assert(plants(diagram, "Fred") == expected); } - // Full garden-for Ginny + // Full garden - for Ginny { immutable string diagram = "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV"; string[4] expected = [ @@ -157,7 +155,7 @@ unittest assert(plants(diagram, "Ginny") == expected); } - // Full garden-for Harriet + // Full garden - for Harriet { immutable string diagram = "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV"; string[4] expected = [ @@ -169,7 +167,7 @@ unittest assert(plants(diagram, "Harriet") == expected); } - // Full garden-for Ileana + // Full garden - for Ileana { immutable string diagram = "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV"; string[4] expected = [ @@ -181,7 +179,7 @@ unittest assert(plants(diagram, "Ileana") == expected); } - // Full garden-for Joseph + // Full garden - for Joseph { immutable string diagram = "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV"; string[4] expected = [ @@ -193,7 +191,7 @@ unittest assert(plants(diagram, "Joseph") == expected); } - // Full garden-for Kincaid, second to last student's garden + // Full garden - for Kincaid, second to last student's garden { immutable string diagram = "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV"; string[4] expected = [ @@ -205,7 +203,7 @@ unittest assert(plants(diagram, "Kincaid") == expected); } - // Full garden-for Larry, last student's garden + // Full garden - for Larry, last student's garden { immutable string diagram = "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV"; string[4] expected = [ diff --git a/exercises/practice/knapsack/.meta/test_generator.py b/exercises/practice/knapsack/.meta/test_generator.py new file mode 100644 index 00000000..cbcbd91e --- /dev/null +++ b/exercises/practice/knapsack/.meta/test_generator.py @@ -0,0 +1,16 @@ +from lib import assert_eq, d_array, d_int + + +def d_item(item): + return f"Item({item['weight']}, {item['value']})" + + +def gen_case(case): + prop = case["property"] + items = d_array(case["input"]["items"], d_item) + maximum_weight = d_int(case["input"]["maximumWeight"]) + expected = d_int(case["expected"]) + return [ + f"Item[] items = {items};", + assert_eq(f"{prop}(items, {maximum_weight})", expected), + ] diff --git a/exercises/practice/leap/.meta/test_generator.py b/exercises/practice/leap/.meta/test_generator.py new file mode 100644 index 00000000..9d431dca --- /dev/null +++ b/exercises/practice/leap/.meta/test_generator.py @@ -0,0 +1,9 @@ +from lib import assert_false, assert_true, d_int + + +def gen_case(case): + year = d_int(case["input"]["year"]) + call = f"isLeap({year})" + if case["expected"]: + return assert_true(call) + return assert_false(call) diff --git a/exercises/practice/leap/source/leap.d b/exercises/practice/leap/source/leap.d index 7de24b0a..e6523fdb 100644 --- a/exercises/practice/leap/source/leap.d +++ b/exercises/practice/leap/source/leap.d @@ -24,7 +24,7 @@ unittest // Year divisible by 100 but not by 3 is still not a leap year assert(!isLeap(1900)); - // Year divisible by 400 in leap year + // Year divisible by 400 is leap year assert(isLeap(2000)); // Year divisible by 400 but not by 125 is still a leap year diff --git a/exercises/practice/line-up/.meta/test_generator.py b/exercises/practice/line-up/.meta/test_generator.py new file mode 100644 index 00000000..283fe152 --- /dev/null +++ b/exercises/practice/line-up/.meta/test_generator.py @@ -0,0 +1,9 @@ +from lib import assert_equal, d_int, d_string + + +def gen_case(case): + prop = case["property"] + name = d_string(case["input"]["name"]) + number = d_int(case["input"]["number"]) + expected = d_string(case["expected"]) + return assert_equal(expected, f"{prop}({name}, {number})", wrap=True) diff --git a/exercises/practice/line-up/source/line_up.d b/exercises/practice/line-up/source/line_up.d index eccba87f..9923b801 100644 --- a/exercises/practice/line-up/source/line_up.d +++ b/exercises/practice/line-up/source/line_up.d @@ -8,6 +8,7 @@ pure string format(immutable string name, uint number) unittest { import std.algorithm.comparison : equal; + immutable int allTestsEnabled = 0; // Format smallest non-exceptional ordinal numeral 4 diff --git a/exercises/practice/luhn/.meta/test_generator.py b/exercises/practice/luhn/.meta/test_generator.py new file mode 100644 index 00000000..e2c91b2d --- /dev/null +++ b/exercises/practice/luhn/.meta/test_generator.py @@ -0,0 +1,10 @@ +from lib import assert_false, assert_true, d_string + + +def gen_case(case): + prop = case["property"] + value = d_string(case["input"]["value"]) + call = f"{prop}({value})" + if case["expected"]: + return assert_true(call) + return assert_false(call) diff --git a/exercises/practice/matching-brackets/.meta/test_generator.py b/exercises/practice/matching-brackets/.meta/test_generator.py new file mode 100644 index 00000000..e2c91b2d --- /dev/null +++ b/exercises/practice/matching-brackets/.meta/test_generator.py @@ -0,0 +1,10 @@ +from lib import assert_false, assert_true, d_string + + +def gen_case(case): + prop = case["property"] + value = d_string(case["input"]["value"]) + call = f"{prop}({value})" + if case["expected"]: + return assert_true(call) + return assert_false(call) diff --git a/exercises/practice/matching-brackets/source/matching_brackets.d b/exercises/practice/matching-brackets/source/matching_brackets.d index 5cb85e5e..121ac569 100644 --- a/exercises/practice/matching-brackets/source/matching_brackets.d +++ b/exercises/practice/matching-brackets/source/matching_brackets.d @@ -69,7 +69,6 @@ unittest assert(isPaired("(((185 + 223.85) * 15) - 543)/2")); // Complex latex expression - assert(isPaired( - "\\left(\\begin{array}{cc} \\frac{1}{3} & x\\\\ \\mathrm{e}^{x} &... x^2 \\end{array}\\right)")); + assert(isPaired("\\left(\\begin{array}{cc} \\frac{1}{3} & x\\\\ \\mathrm{e}^{x} &... x^2 \\end{array}\\right)")); } } diff --git a/exercises/practice/matrix/.meta/test_generator.py b/exercises/practice/matrix/.meta/test_generator.py index ecaff43f..99846fc6 100644 --- a/exercises/practice/matrix/.meta/test_generator.py +++ b/exercises/practice/matrix/.meta/test_generator.py @@ -6,10 +6,8 @@ def gen_case(case): numbers = d_string(case["input"]["string"]) index = d_int(case["input"]["index"]) expected = d_inline_array(case["expected"]) - return "\n".join( - [ - f"immutable string numbers = {numbers};", - f"int[] expected = {expected};", - assert_eq(f"{prop}(numbers, {index})", "expected"), - ] - ) + return [ + f"immutable string numbers = {numbers};", + f"int[] expected = {expected};", + assert_eq(f"{prop}(numbers, {index})", "expected"), + ] diff --git a/exercises/practice/meetup/.meta/test_generator.py b/exercises/practice/meetup/.meta/test_generator.py new file mode 100644 index 00000000..a830033d --- /dev/null +++ b/exercises/practice/meetup/.meta/test_generator.py @@ -0,0 +1,27 @@ +from lib import assert_eq, d_int, d_string + +MONTHS = [ + "jan", + "feb", + "mar", + "apr", + "may", + "jun", + "jul", + "aug", + "sep", + "oct", + "nov", + "dec", +] + + +def gen_case(case): + prop = case["property"] + inp = case["input"] + year = d_int(inp["year"]) + month = MONTHS[inp["month"] - 1] + week = inp["week"] + day = inp["dayofweek"][:3].lower() + call = f"{prop}({year}, Month.{month}, Week.{week}, DayOfWeek.{day})" + return assert_eq(call, d_string(case["expected"])) diff --git a/exercises/practice/micro-blog/.meta/test_generator.py b/exercises/practice/micro-blog/.meta/test_generator.py new file mode 100644 index 00000000..c47b8b77 --- /dev/null +++ b/exercises/practice/micro-blog/.meta/test_generator.py @@ -0,0 +1,8 @@ +from lib import assert_eq, d_string + + +def gen_case(case): + prop = case["property"] + phrase = d_string(case["input"]["phrase"]) + expected = d_string(case["expected"]) + return assert_eq(f"{prop}({phrase})", expected) diff --git a/exercises/practice/minesweeper/.meta/test_generator.py b/exercises/practice/minesweeper/.meta/test_generator.py new file mode 100644 index 00000000..a28b9f25 --- /dev/null +++ b/exercises/practice/minesweeper/.meta/test_generator.py @@ -0,0 +1,12 @@ +from lib import assert_eq, d_array, d_string + + +def gen_case(case): + prop = case["property"] + minefield = d_array(case["input"]["minefield"], d_string) + expected = d_array(case["expected"], d_string) + return [ + f"immutable string[] minefield = {minefield};", + f"string[] expected = {expected};", + assert_eq(f"{prop}(minefield)", "expected"), + ] diff --git a/exercises/practice/ocr-numbers/.meta/test_generator.py b/exercises/practice/ocr-numbers/.meta/test_generator.py new file mode 100644 index 00000000..faaad598 --- /dev/null +++ b/exercises/practice/ocr-numbers/.meta/test_generator.py @@ -0,0 +1,14 @@ +from lib import assert_eq, assert_throws, d_array, d_string, is_error + + +def gen_case(case): + prop = case["property"] + rows = d_array(case["input"]["rows"], d_string) + call = f"{prop}(rows)" + + lines = [f"immutable string[] rows = {rows};"] + if is_error(case["expected"]): + lines.append(assert_throws(call)) + else: + lines.append(assert_eq(call, d_string(case["expected"]))) + return lines diff --git a/exercises/practice/palindrome-products/.meta/test_generator.py b/exercises/practice/palindrome-products/.meta/test_generator.py new file mode 100644 index 00000000..76b7de82 --- /dev/null +++ b/exercises/practice/palindrome-products/.meta/test_generator.py @@ -0,0 +1,21 @@ +from lib import assert_eq, assert_throws, d_inline_array, d_int, is_error + + +def gen_case(case): + prop = case["property"] + minimum = d_int(case["input"]["min"]) + maximum = d_int(case["input"]["max"]) + call = f"{prop}({minimum}, {maximum})" + expected = case["expected"] + if is_error(expected): + return assert_throws(call) + + lines = [f"auto result = {call};"] + if expected["value"] is None: + lines.append(assert_eq("result.value", "0")) + lines.append(assert_eq("result.factors.length", "0")) + else: + factors = d_inline_array(expected["factors"], d_inline_array) + lines.append(assert_eq("result.value", d_int(expected["value"]))) + lines.append(assert_eq("result.factors", factors)) + return lines diff --git a/exercises/practice/pascals-triangle/.meta/test_generator.py b/exercises/practice/pascals-triangle/.meta/test_generator.py new file mode 100644 index 00000000..3d9392d7 --- /dev/null +++ b/exercises/practice/pascals-triangle/.meta/test_generator.py @@ -0,0 +1,11 @@ +from lib import assert_eq, d_array, d_inline_array, d_int + + +def gen_case(case): + prop = case["property"] + count = d_int(case["input"]["count"]) + expected = d_array(case["expected"], d_inline_array) + return [ + f"int[][] expected = {expected};", + assert_eq(f"{prop}({count})", "expected"), + ] diff --git a/exercises/practice/pig-latin/.meta/test_generator.py b/exercises/practice/pig-latin/.meta/test_generator.py new file mode 100644 index 00000000..8e3d7b49 --- /dev/null +++ b/exercises/practice/pig-latin/.meta/test_generator.py @@ -0,0 +1,12 @@ +from lib import assert_eq, d_string + + +def describe(case): + return case["description"] + + +def gen_case(case): + prop = case["property"] + phrase = d_string(case["input"]["phrase"]) + expected = d_string(case["expected"]) + return assert_eq(f"{prop}({phrase})", expected) diff --git a/exercises/practice/pig-latin/example/pig_latin.d b/exercises/practice/pig-latin/example/pig_latin.d index a85aecd6..048a02fa 100644 --- a/exercises/practice/pig-latin/example/pig_latin.d +++ b/exercises/practice/pig-latin/example/pig_latin.d @@ -23,4 +23,3 @@ string translate(immutable string input) } return results.join(" "); } - diff --git a/exercises/practice/pythagorean-triplet/.meta/test_generator.py b/exercises/practice/pythagorean-triplet/.meta/test_generator.py new file mode 100644 index 00000000..27a623ed --- /dev/null +++ b/exercises/practice/pythagorean-triplet/.meta/test_generator.py @@ -0,0 +1,16 @@ +from lib import assert_eq, d_array, d_int + + +def d_triplet(triplet): + a, b, c = triplet + return f"Triplet({a}, {b}, {c})" + + +def gen_case(case): + prop = case["property"] + n = d_int(case["input"]["n"]) + expected = d_array(case["expected"], d_triplet) + return [ + f"Triplet[] expected = {expected};", + assert_eq(f"{prop}({n})", "expected"), + ] diff --git a/exercises/practice/raindrops/.meta/test_generator.py b/exercises/practice/raindrops/.meta/test_generator.py new file mode 100644 index 00000000..e887dbe8 --- /dev/null +++ b/exercises/practice/raindrops/.meta/test_generator.py @@ -0,0 +1,8 @@ +from lib import assert_eq, d_int, d_string + + +def gen_case(case): + prop = case["property"] + number = d_int(case["input"]["number"]) + expected = d_string(case["expected"]) + return assert_eq(f"{prop}({number})", expected) diff --git a/exercises/practice/raindrops/source/raindrops.d b/exercises/practice/raindrops/source/raindrops.d index 09abc5f9..6b23949e 100644 --- a/exercises/practice/raindrops/source/raindrops.d +++ b/exercises/practice/raindrops/source/raindrops.d @@ -18,7 +18,7 @@ unittest // The sound for 5 is Plang assert(convert(5) == "Plang"); - // the sound for 7 is Plong + // The sound for 7 is Plong assert(convert(7) == "Plong"); // The sound for 6 is Pling as it has a factor 3 @@ -63,5 +63,4 @@ unittest // The sound for 3125 is Plang as it has a factor 5 assert(convert(3125) == "Plang"); } - } diff --git a/exercises/practice/rectangles/.meta/additional-test-cases.json b/exercises/practice/rectangles/.meta/additional-test-cases.json new file mode 100644 index 00000000..30f9be48 --- /dev/null +++ b/exercises/practice/rectangles/.meta/additional-test-cases.json @@ -0,0 +1,32 @@ +[ + { + "description": "very large input", + "property": "rectangles", + "input": { + "strings": [ + " +-----+--------+ +-----+ ", + "++---++-----+--------+---++-----++", + "||+--++-----+-+-++ | || ||", + "||| || +-+-++-+ | || ||", + "||| || | | || | | || ||", + "||| +++-----+-+-++-+-+---++-+ ||", + "||| ||| | | || | |+--++-+-+ ||", + "||| +++---+-+-+-++-+-++--++-+ | ||", + "||| |||+--+-+-+-+| | |+--++---+ ||", + "||| |||| | | | || | |+-+|| ||", + "||+-++++--+-+++-++-+-++-+++---++||", + "|| |+++--+-+++-+--+-+| ||| ||||", + "+++-+++++---++--+-++-++-+++---+|||", + " |+-+++++---++--+ || || ||| ||||", + " | +++++---++--+-++-++-++++ ||||", + " | |||| |+----++-++-++++--+++|", + " | |+++---+| || || || || |", + "+++ |||+---++----+| || || || |", + "||| +++----++----++-++-++----++-+", + "+++---++----++-----+-++-++----++ ", + " +-+ " + ] + }, + "expected": 2063 + } +] diff --git a/exercises/practice/rectangles/.meta/test_generator.py b/exercises/practice/rectangles/.meta/test_generator.py new file mode 100644 index 00000000..381f8cd7 --- /dev/null +++ b/exercises/practice/rectangles/.meta/test_generator.py @@ -0,0 +1,11 @@ +from lib import assert_eq, d_array, d_int, d_string + + +def gen_case(case): + prop = case["property"] + strings = d_array(case["input"]["strings"], d_string) + expected = d_int(case["expected"]) + return [ + f"immutable string[] strings = {strings};", + assert_eq(f"{prop}(strings)", expected), + ] diff --git a/exercises/practice/resistor-color-duo/.meta/test_generator.py b/exercises/practice/resistor-color-duo/.meta/test_generator.py new file mode 100644 index 00000000..55126db8 --- /dev/null +++ b/exercises/practice/resistor-color-duo/.meta/test_generator.py @@ -0,0 +1,8 @@ +from lib import assert_eq, d_inline_array, d_int, d_string + + +def gen_case(case): + prop = case["property"] + colors = d_inline_array(case["input"]["colors"], d_string) + expected = d_int(case["expected"]) + return assert_eq(f"ResistorColorDuo.{prop}({colors})", expected) diff --git a/exercises/practice/resistor-color-duo/source/resistor_color_duo.d b/exercises/practice/resistor-color-duo/source/resistor_color_duo.d index 3ec7338d..bc7c0a87 100644 --- a/exercises/practice/resistor-color-duo/source/resistor_color_duo.d +++ b/exercises/practice/resistor-color-duo/source/resistor_color_duo.d @@ -35,5 +35,4 @@ unittest // Black and brown, one-digit assert(ResistorColorDuo.value(["black", "brown"]) == 1); } - } diff --git a/exercises/practice/resistor-color-trio/.meta/test_generator.py b/exercises/practice/resistor-color-trio/.meta/test_generator.py new file mode 100644 index 00000000..9258fdc9 --- /dev/null +++ b/exercises/practice/resistor-color-trio/.meta/test_generator.py @@ -0,0 +1,9 @@ +from lib import assert_eq, d_inline_array, d_string + + +def gen_case(case): + prop = case["property"] + colors = d_inline_array(case["input"]["colors"], d_string) + expected = case["expected"] + label = d_string(f"{expected['value']} {expected['unit']}") + return assert_eq(f"ResistorColorTrio.{prop}({colors})", label) diff --git a/exercises/practice/resistor-color-trio/example/resistor_color_trio.d b/exercises/practice/resistor-color-trio/example/resistor_color_trio.d index 3fd36fe0..28c5573f 100644 --- a/exercises/practice/resistor-color-trio/example/resistor_color_trio.d +++ b/exercises/practice/resistor-color-trio/example/resistor_color_trio.d @@ -24,7 +24,7 @@ class ResistorColorTrio } private static immutable colors = [ - "black", "brown", "red", "orange", + "black", "brown", "red", "orange", "yellow", "green", "blue", "violet", "grey", "white" ]; diff --git a/exercises/practice/resistor-color-trio/source/resistor_color_trio.d b/exercises/practice/resistor-color-trio/source/resistor_color_trio.d index 6bcdc890..482e3e9d 100644 --- a/exercises/practice/resistor-color-trio/source/resistor_color_trio.d +++ b/exercises/practice/resistor-color-trio/source/resistor_color_trio.d @@ -16,7 +16,7 @@ unittest { // Blue and grey and brown assert(ResistorColorTrio.label(["blue", "grey", "brown"]) == "680 ohms"); - + // Red and black and red assert(ResistorColorTrio.label(["red", "black", "red"]) == "2 kiloohms"); @@ -29,10 +29,10 @@ unittest // Blue and violet and blue assert(ResistorColorTrio.label(["blue", "violet", "blue"]) == "67 megaohms"); - // Minimum possible label + // Minimum possible value assert(ResistorColorTrio.label(["black", "black", "black"]) == "0 ohms"); - // Maximum possible label + // Maximum possible value assert(ResistorColorTrio.label(["white", "white", "white"]) == "99 gigaohms"); // First two colors make an invalid octal number diff --git a/exercises/practice/resistor-color/.meta/test_generator.py b/exercises/practice/resistor-color/.meta/test_generator.py new file mode 100644 index 00000000..4d21030c --- /dev/null +++ b/exercises/practice/resistor-color/.meta/test_generator.py @@ -0,0 +1,16 @@ +from lib import assert_eq, d_inline_array, d_int, d_string + + +def describe(case): + return case["description"] + + +def gen_case(case): + prop = case["property"] + if prop == "colors": + expected = d_inline_array(case["expected"], d_string) + return assert_eq(f"ResistorColor.{prop}", expected) + + color = d_string(case["input"]["color"]) + expected = d_int(case["expected"]) + return assert_eq(f"ResistorColor.{prop}({color})", expected) diff --git a/exercises/practice/resistor-color/source/resistor_color.d b/exercises/practice/resistor-color/source/resistor_color.d index 3087e380..69e35f1e 100644 --- a/exercises/practice/resistor-color/source/resistor_color.d +++ b/exercises/practice/resistor-color/source/resistor_color.d @@ -16,10 +16,6 @@ unittest assert(ResistorColor.colorCode("orange") == 3); // Colors - assert(ResistorColor.colors == [ - "black", "brown", "red", "orange", "yellow", "green", "blue", - "violet", "grey", "white" - ]); + assert(ResistorColor.colors == ["black", "brown", "red", "orange", "yellow", "green", "blue", "violet", "grey", "white"]); } - } diff --git a/exercises/practice/reverse-string/.meta/test_generator.py b/exercises/practice/reverse-string/.meta/test_generator.py new file mode 100644 index 00000000..27032b47 --- /dev/null +++ b/exercises/practice/reverse-string/.meta/test_generator.py @@ -0,0 +1,7 @@ +from lib import assert_eq, d_string + + +def gen_case(case): + value = d_string(case["input"]["value"]) + expected = d_string(case["expected"]) + return assert_eq(f"reverseString({value})", expected) diff --git a/exercises/practice/robot-simulator/.meta/test_generator.py b/exercises/practice/robot-simulator/.meta/test_generator.py new file mode 100644 index 00000000..97a978f6 --- /dev/null +++ b/exercises/practice/robot-simulator/.meta/test_generator.py @@ -0,0 +1,21 @@ +from lib import assert_eq, d_int, d_string + + +def describe(case): + return " ".join((*case["parents"], case["description"])) + + +def gen_case(case): + inp = case["input"] + x = d_int(inp["position"]["x"]) + y = d_int(inp["position"]["y"]) + direction = d_string(inp["direction"]) + expected = case["expected"] + + lines = [f"RobotSimulator robot = new RobotSimulator({x}, {y}, {direction});"] + if case["property"] == "move": + lines.append(f"robot.move({d_string(inp['instructions'])});") + lines.append(assert_eq("robot.x", d_int(expected["position"]["x"]))) + lines.append(assert_eq("robot.y", d_int(expected["position"]["y"]))) + lines.append(assert_eq("robot.direction", d_string(expected["direction"]))) + return lines diff --git a/exercises/practice/robot-simulator/source/robot_simulator.d b/exercises/practice/robot-simulator/source/robot_simulator.d index 3ce83a0a..c0354725 100644 --- a/exercises/practice/robot-simulator/source/robot_simulator.d +++ b/exercises/practice/robot-simulator/source/robot_simulator.d @@ -179,5 +179,4 @@ unittest assert(robot.direction == "north"); } } - } diff --git a/exercises/practice/roman-numerals/.meta/test_generator.py b/exercises/practice/roman-numerals/.meta/test_generator.py new file mode 100644 index 00000000..3e11b83a --- /dev/null +++ b/exercises/practice/roman-numerals/.meta/test_generator.py @@ -0,0 +1,7 @@ +from lib import assert_eq, d_int, d_string + + +def gen_case(case): + number = d_int(case["input"]["number"]) + expected = d_string(case["expected"]) + return [assert_eq(expected, f"convert({number})")] diff --git a/exercises/practice/roman-numerals/source/roman_numerals.d b/exercises/practice/roman-numerals/source/roman_numerals.d index 9fef77bb..42288d42 100644 --- a/exercises/practice/roman-numerals/source/roman_numerals.d +++ b/exercises/practice/roman-numerals/source/roman_numerals.d @@ -9,145 +9,143 @@ string convert(ulong number) unittest { - immutable int allTestsEnabled = 0; - // one_yields_I + // 1 is I { assert("I" == convert(1)); } static if (allTestsEnabled) { - // two_yields_II + // 2 is II { assert("II" == convert(2)); } - // three_yields_III + // 3 is III { assert("III" == convert(3)); } - // four_yields_IV + // 4 is IV { assert("IV" == convert(4)); } - // five_yields_V + // 5 is V { assert("V" == convert(5)); } - // six_yields_VI + // 6 is VI { assert("VI" == convert(6)); } - // nine_yields_IX + // 9 is IX { assert("IX" == convert(9)); } - // sixteen_yields_XVI + // 16 is XVI { assert("XVI" == convert(16)); } - // twenty_seven_yields_XXVII + // 27 is XXVII { assert("XXVII" == convert(27)); } - // forty_eight_yields_XLVIII + // 48 is XLVIII { assert("XLVIII" == convert(48)); } - // forty_nine_yields_XLIX + // 49 is XLIX { assert("XLIX" == convert(49)); } - // fifty_nine_yields_LIX + // 59 is LIX { assert("LIX" == convert(59)); } - // sixty_six_yields_LXVI + // 66 is LXVI { assert("LXVI" == convert(66)); } - // ninety_three_yields_XCIII + // 93 is XCIII { assert("XCIII" == convert(93)); } - // one_hundred_forty_one_yields_CXLI + // 141 is CXLI { assert("CXLI" == convert(141)); } - // one_hundred_sixty_three_yields_CLXIII + // 163 is CLXIII { assert("CLXIII" == convert(163)); } - // one_hundred_sixty_six_yields_CLXVI + // 166 is CLXVI { assert("CLXVI" == convert(166)); } - // four_hundred_two_yields_CDII + // 402 is CDII { assert("CDII" == convert(402)); } - // five_hundred_seventy_five_yields_DLXXV + // 575 is DLXXV { assert("DLXXV" == convert(575)); } - // six_hundred_sixty_six_yields_DCLXVI + // 666 is DCLXVI { assert("DCLXVI" == convert(666)); } - // nine_hundred_eleven_yields_CMXI + // 911 is CMXI { assert("CMXI" == convert(911)); } - // one_thousand_twenty_four_yields_MXXIV + // 1024 is MXXIV { assert("MXXIV" == convert(1024)); } - // one_thousand_six_hundred_sixty_six_yields_MDCLXVI + // 1666 is MDCLXVI { assert("MDCLXVI" == convert(1666)); } - // three_thousand_yields_MMM + // 3000 is MMM { assert("MMM" == convert(3000)); } - // three_thousand_one_yields_MMMI + // 3001 is MMMI { assert("MMMI" == convert(3001)); } - // three_thousand_eight_hundred_eighty_eight_yields_MMMDCCCLXXXVIII + // 3888 is MMMDCCCLXXXVIII { assert("MMMDCCCLXXXVIII" == convert(3888)); } - // three_thousand_nine_hundred_ninety_nine_yields_MMMCMXCIX + // 3999 is MMMCMXCIX { assert("MMMCMXCIX" == convert(3999)); } } - } diff --git a/exercises/practice/run-length-encoding/.meta/test_generator.py b/exercises/practice/run-length-encoding/.meta/test_generator.py new file mode 100644 index 00000000..cb4f38ef --- /dev/null +++ b/exercises/practice/run-length-encoding/.meta/test_generator.py @@ -0,0 +1,15 @@ +from lib import assert_eq, d_string + + +def describe(case): + description = case["description"] + return description[:1].upper() + description[1:] + + +def gen_case(case): + prop = case["property"] + string = d_string(case["input"]["string"]) + expected = d_string(case["expected"]) + if prop == "consistency": + return assert_eq(f"{string}.encode.decode", expected) + return assert_eq(f"{prop}({string})", expected) diff --git a/exercises/practice/run-length-encoding/source/run_length_encoding.d b/exercises/practice/run-length-encoding/source/run_length_encoding.d index 5322bedc..3935a0f0 100644 --- a/exercises/practice/run-length-encoding/source/run_length_encoding.d +++ b/exercises/practice/run-length-encoding/source/run_length_encoding.d @@ -14,8 +14,6 @@ unittest { immutable int allTestsEnabled = 0; - // Run-length encode a string - // Empty string assert(encode("") == ""); @@ -36,28 +34,24 @@ unittest // Lowercase characters assert(encode("aabbbcccc") == "2a3b4c"); - // Sun-length decode a string - // Empty string assert(decode("") == ""); - // String with no single characters + // Single characters only assert(decode("XYZ") == "XYZ"); - // Single characters with repeated characters + // String with no single characters assert(decode("2A3B4C") == "AABBBCCCC"); - // Multiple whitespace mixed in string + // Single characters with repeated characters assert(decode("12WB12W3B24WB") == "WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB"); // Multiple whitespace mixed in string assert(decode("2 hs2q q2w2 ") == " hsqq qww "); - // Lower case string + // Lowercase string assert(decode("2a3b4c") == "aabbbcccc"); - // Encode and then decode - // Encode followed by decode gives original string assert("zzz ZZ zZ".encode.decode == "zzz ZZ zZ"); } diff --git a/exercises/practice/say/.meta/test_generator.py b/exercises/practice/say/.meta/test_generator.py new file mode 100644 index 00000000..87239e63 --- /dev/null +++ b/exercises/practice/say/.meta/test_generator.py @@ -0,0 +1,10 @@ +from lib import assert_equal, assert_throws, d_int, d_string, is_error + + +def gen_case(case): + prop = case["property"] + number = d_int(case["input"]["number"]) + "L" + call = f"{prop}({number})" + if is_error(case["expected"]): + return assert_throws(call) + return assert_equal(d_string(case["expected"]), call, wrap=True) diff --git a/exercises/practice/scrabble-score/.meta/test_generator.py b/exercises/practice/scrabble-score/.meta/test_generator.py new file mode 100644 index 00000000..ced0f85c --- /dev/null +++ b/exercises/practice/scrabble-score/.meta/test_generator.py @@ -0,0 +1,8 @@ +from lib import assert_eq, d_int, d_string + + +def gen_case(case): + prop = case["property"] + word = d_string(case["input"]["word"]) + expected = d_int(case["expected"]) + return assert_eq(f"{prop}({word})", expected) diff --git a/exercises/practice/scrabble-score/example/scrabble_score.d b/exercises/practice/scrabble-score/example/scrabble_score.d index ee50d408..bca09c8b 100644 --- a/exercises/practice/scrabble-score/example/scrabble_score.d +++ b/exercises/practice/scrabble-score/example/scrabble_score.d @@ -20,7 +20,7 @@ pure int score(immutable string word) case 'T': points += 1; break; - case 'D': + case 'D': case 'G': points += 2; break; @@ -33,7 +33,7 @@ pure int score(immutable string word) case 'F': case 'H': case 'V': - case 'W': + case 'W': case 'Y': points += 4; break; diff --git a/exercises/practice/scrabble-score/source/scrabble_score.d b/exercises/practice/scrabble-score/source/scrabble_score.d index 03a67092..acf09ac0 100644 --- a/exercises/practice/scrabble-score/source/scrabble_score.d +++ b/exercises/practice/scrabble-score/source/scrabble_score.d @@ -19,28 +19,28 @@ unittest // Valuable letter assert(score("f") == 4); - + // Short word assert(score("at") == 2); - + // Short, valuable word assert(score("zoo") == 12); - + // Medium word assert(score("street") == 6); - + // Medium, valuable word assert(score("quirky") == 22); - + // Long, mixed-case word assert(score("OxyphenButazone") == 41); - + // English-like word assert(score("pinata") == 8); - + // Empty input assert(score("") == 0); - + // Entire alphabet available assert(score("abcdefghijklmnopqrstuvwxyz") == 87); } diff --git a/exercises/practice/secret-handshake/.meta/test_generator.py b/exercises/practice/secret-handshake/.meta/test_generator.py new file mode 100644 index 00000000..f0e002eb --- /dev/null +++ b/exercises/practice/secret-handshake/.meta/test_generator.py @@ -0,0 +1,8 @@ +from lib import assert_eq, d_inline_array, d_int, d_string + + +def gen_case(case): + prop = case["property"] + number = d_int(case["input"]["number"]) + expected = d_inline_array(case["expected"], d_string) + return assert_eq(f"{prop}({number})", expected) diff --git a/exercises/practice/secret-handshake/example/secret_handshake.d b/exercises/practice/secret-handshake/example/secret_handshake.d index 6357adc2..eb5391ae 100644 --- a/exercises/practice/secret-handshake/example/secret_handshake.d +++ b/exercises/practice/secret-handshake/example/secret_handshake.d @@ -33,4 +33,3 @@ pure string[] commands(immutable int number) return actions; } - diff --git a/exercises/practice/secret-handshake/source/secret_handshake.d b/exercises/practice/secret-handshake/source/secret_handshake.d index 5c430fc1..f4033947 100644 --- a/exercises/practice/secret-handshake/source/secret_handshake.d +++ b/exercises/practice/secret-handshake/source/secret_handshake.d @@ -45,4 +45,3 @@ unittest assert(commands(0) == []); } } - diff --git a/exercises/practice/sieve/.meta/test_generator.py b/exercises/practice/sieve/.meta/test_generator.py new file mode 100644 index 00000000..d04dcb0e --- /dev/null +++ b/exercises/practice/sieve/.meta/test_generator.py @@ -0,0 +1,32 @@ +from lib import INDENT, assert_eq, d_inline_array, d_int + +COLUMNS = 14 + + +def d_table(values): + """Render an array literal as aligned rows of values.""" + rows = [] + for start in range(0, len(values), COLUMNS): + row = values[start : start + COLUMNS] + cells = [f"{value},".ljust(5) for value in row] + rows.append(INDENT + "".join(cells).rstrip()) + rows[-1] = rows[-1].rstrip(",") + return "\n".join(["[", *rows, "]"]) + + +def describe(case): + return case["description"] + + +def gen_case(case): + prop = case["property"] + limit = d_int(case["input"]["limit"]) + expected = case["expected"] + call = f"{prop}({limit})" + if len(expected) <= COLUMNS: + return [assert_eq(call, d_inline_array(expected))] + return [ + f"const int[] expected = {d_table(expected)};", + "", + assert_eq(call, "expected"), + ] diff --git a/exercises/practice/sieve/example/sieve.d b/exercises/practice/sieve/example/sieve.d index f7f9d24f..544f1d9b 100644 --- a/exercises/practice/sieve/example/sieve.d +++ b/exercises/practice/sieve/example/sieve.d @@ -12,7 +12,7 @@ pure int[] primes(immutable int limit) { int current = nums.front; results ~= nums.front; - + nums = nums.dropOne().filter!(n => n % current != 0).array; } diff --git a/exercises/practice/sieve/source/sieve.d b/exercises/practice/sieve/source/sieve.d index c3d2d950..31f3e4a6 100644 --- a/exercises/practice/sieve/source/sieve.d +++ b/exercises/practice/sieve/source/sieve.d @@ -50,7 +50,5 @@ unittest assert(primes(1000) == expected); } - } - } diff --git a/exercises/practice/space-age/.meta/test_generator.py b/exercises/practice/space-age/.meta/test_generator.py new file mode 100644 index 00000000..6aef1396 --- /dev/null +++ b/exercises/practice/space-age/.meta/test_generator.py @@ -0,0 +1,11 @@ +from lib import assert_true, d_grouped_int + + +def gen_case(case): + planet = case["input"]["planet"].lower() + seconds = d_grouped_int(case["input"]["seconds"]) + expected = case["expected"] + return [ + f"scope SpaceAge age = new SpaceAge({seconds});", + assert_true(f"age.on_{planet}().isClose({expected}, 0.01)"), + ] diff --git a/exercises/practice/space-age/example/space_age.d b/exercises/practice/space-age/example/space_age.d index 241c67f7..1b5ec12c 100644 --- a/exercises/practice/space-age/example/space_age.d +++ b/exercises/practice/space-age/example/space_age.d @@ -18,32 +18,32 @@ class SpaceAge { return this.on_earth() / 0.2408467; } - + final float on_venus() const { return this.on_earth() / 0.61519726; } - + final float on_mars() const { return this.on_earth() / 1.8808158; } - + final float on_jupiter() const { return this.on_earth() / 11.862615; } - + final float on_saturn() const { return this.on_earth() / 29.447498; } - + final float on_uranus() const { return this.on_earth() / 84.016846; } - + final float on_neptune() const { return this.on_earth() / 164.79132; @@ -52,4 +52,4 @@ class SpaceAge private: immutable float seconds_in_year = 31_557_600; immutable long seconds; -} \ No newline at end of file +} diff --git a/exercises/practice/space-age/source/space_age.d b/exercises/practice/space-age/source/space_age.d index be27b4d6..88239dc0 100644 --- a/exercises/practice/space-age/source/space_age.d +++ b/exercises/practice/space-age/source/space_age.d @@ -18,32 +18,32 @@ class SpaceAge { // implement this function } - + final float on_venus() const { // implement this function } - + final float on_mars() const { // implement this function } - + final float on_jupiter() const { // implement this function } - + final float on_saturn() const { // implement this function } - + final float on_uranus() const { // implement this function } - + final float on_neptune() const { // implement this function @@ -110,5 +110,4 @@ unittest assert(age.on_neptune().isClose(0.35, 0.01)); } } - } diff --git a/exercises/practice/square-root/.meta/test_generator.py b/exercises/practice/square-root/.meta/test_generator.py new file mode 100644 index 00000000..0eb06a34 --- /dev/null +++ b/exercises/practice/square-root/.meta/test_generator.py @@ -0,0 +1,12 @@ +from lib import assert_eq, d_int + + +def describe(case): + return case["description"] + + +def gen_case(case): + prop = case["property"] + radicand = d_int(case["input"]["radicand"]) + expected = d_int(case["expected"]) + return assert_eq(f"{prop}({radicand})", expected) diff --git a/exercises/practice/state-of-tic-tac-toe/.meta/test_generator.py b/exercises/practice/state-of-tic-tac-toe/.meta/test_generator.py new file mode 100644 index 00000000..c95f496b --- /dev/null +++ b/exercises/practice/state-of-tic-tac-toe/.meta/test_generator.py @@ -0,0 +1,14 @@ +from lib import assert_eq, assert_throws, d_array, d_string, is_error + + +def gen_case(case): + prop = case["property"] + board = d_array(case["input"]["board"], d_string) + call = f"{prop}(board)" + + lines = [f"immutable string[] board = {board};"] + if is_error(case["expected"]): + lines.append(assert_throws(call)) + else: + lines.append(assert_eq(call, f"State.{case['expected']}")) + return lines diff --git a/exercises/practice/state-of-tic-tac-toe/example/state_of_tic_tac_toe.d b/exercises/practice/state-of-tic-tac-toe/example/state_of_tic_tac_toe.d index d3f121cd..aeb05627 100644 --- a/exercises/practice/state-of-tic-tac-toe/example/state_of_tic_tac_toe.d +++ b/exercises/practice/state-of-tic-tac-toe/example/state_of_tic_tac_toe.d @@ -93,283 +93,3 @@ private pure bool is_win(immutable int bitset) return false; } - -unittest -{ - import std.exception : assertThrown; - - immutable int allTestsEnabled = 0; - - // Won games-Finished game where X won via left column victory - { - immutable string[] board = [ - "XOO", - "X ", - "X ", - ]; - assert(gamestate(board) == State.win); - } - - static if (allTestsEnabled) - { - // Won games-Finished game where X won via middle column victory - { - immutable string[] board = [ - "OXO", - " X ", - " X ", - ]; - assert(gamestate(board) == State.win); - } - - // Won games-Finished game where X won via right column victory - { - immutable string[] board = [ - "OOX", - " X", - " X", - ]; - assert(gamestate(board) == State.win); - } - - // Won games-Finished game where O won via left column victory - { - immutable string[] board = [ - "OXX", - "OX ", - "O ", - ]; - assert(gamestate(board) == State.win); - } - - // Won games-Finished game where O won via middle column victory - { - immutable string[] board = [ - "XOX", - " OX", - " O ", - ]; - assert(gamestate(board) == State.win); - } - - // Won games-Finished game where O won via right column victory - { - immutable string[] board = [ - "XXO", - " XO", - " O", - ]; - assert(gamestate(board) == State.win); - } - - // Won games-Finished game where X won via top row victory - { - immutable string[] board = [ - "XXX", - "XOO", - "O ", - ]; - assert(gamestate(board) == State.win); - } - - // Won games-Finished game where X won via middle row victory - { - immutable string[] board = [ - "O ", - "XXX", - " O ", - ]; - assert(gamestate(board) == State.win); - } - - // Won games-Finished game where X won via bottom row victory - { - immutable string[] board = [ - " OO", - "O X", - "XXX", - ]; - assert(gamestate(board) == State.win); - } - - // Won games-Finished game where O won via top row victory - { - immutable string[] board = [ - "OOO", - "XXO", - "XX ", - ]; - assert(gamestate(board) == State.win); - } - - // Won games-Finished game where O won via middle row victory - { - immutable string[] board = [ - "XX ", - "OOO", - "X ", - ]; - assert(gamestate(board) == State.win); - } - - // Won games-Finished game where O won via bottom row victory - { - immutable string[] board = [ - "XOX", - " XX", - "OOO", - ]; - assert(gamestate(board) == State.win); - } - - // Won games-Finished game where X won via falling diagonal victory - { - immutable string[] board = [ - "XOO", - " X ", - " X", - ]; - assert(gamestate(board) == State.win); - } - - // Won games-Finished game where X won via rising diagonal victory - { - immutable string[] board = [ - "O X", - "OX ", - "X ", - ]; - assert(gamestate(board) == State.win); - } - - // Won games-Finished game where O won via falling diagonal victory - { - immutable string[] board = [ - "OXX", - "OOX", - "X O", - ]; - assert(gamestate(board) == State.win); - } - - // Won games-Finished game where O won via rising diagonal victory - { - immutable string[] board = [ - " O", - " OX", - "OXX", - ]; - assert(gamestate(board) == State.win); - } - - // Won games-Finished game where X won via a row and a column victory - { - immutable string[] board = [ - "XXX", - "XOO", - "XOO", - ]; - assert(gamestate(board) == State.win); - } - - // Won games-Finished game where X won via two diagonal victories - { - immutable string[] board = [ - "XOX", - "OXO", - "XOX", - ]; - assert(gamestate(board) == State.win); - } - - // Drawn games-Draw - { - immutable string[] board = [ - "XOX", - "XXO", - "OXO", - ]; - assert(gamestate(board) == State.draw); - } - - // Drawn games-Another draw - { - immutable string[] board = [ - "XXO", - "OXX", - "XOO", - ]; - assert(gamestate(board) == State.draw); - } - - // Ongoing games-Ongoing game: one move in - { - immutable string[] board = [ - " ", - "X ", - " ", - ]; - assert(gamestate(board) == State.ongoing); - } - - // Ongoing games-Ongoing game: two moves in - { - immutable string[] board = [ - "O ", - " X ", - " ", - ]; - assert(gamestate(board) == State.ongoing); - } - - // Ongoing games-Ongoing game: five moves in - { - immutable string[] board = [ - "X ", - " XO", - "OX ", - ]; - assert(gamestate(board) == State.ongoing); - } - - // Invalid boards-Invalid board: X went twice - { - immutable string[] board = [ - "XX ", - " ", - " ", - ]; - assertThrown(gamestate(board)); - } - - // Invalid boards-Invalid board: O started - { - immutable string[] board = [ - "OOX", - " ", - " ", - ]; - assertThrown(gamestate(board)); - } - - // Invalid boards-Invalid board: X won and O kept playing - { - immutable string[] board = [ - "XXX", - "OOO", - " ", - ]; - assertThrown(gamestate(board)); - } - - // Invalid boards-Invalid board: players kept playing after a win - { - immutable string[] board = [ - "XXX", - "OOO", - "XOX", - ]; - assertThrown(gamestate(board)); - } - } -} diff --git a/exercises/practice/state-of-tic-tac-toe/source/state_of_tic_tac_toe.d b/exercises/practice/state-of-tic-tac-toe/source/state_of_tic_tac_toe.d index 3c1a3eda..deda2b2d 100644 --- a/exercises/practice/state-of-tic-tac-toe/source/state_of_tic_tac_toe.d +++ b/exercises/practice/state-of-tic-tac-toe/source/state_of_tic_tac_toe.d @@ -17,7 +17,7 @@ unittest immutable int allTestsEnabled = 0; - // Won games-Finished game where X won via left column victory + // Won games - Finished game where X won via left column victory { immutable string[] board = [ "XOO", @@ -29,7 +29,7 @@ unittest static if (allTestsEnabled) { - // Won games-Finished game where X won via middle column victory + // Won games - Finished game where X won via middle column victory { immutable string[] board = [ "OXO", @@ -39,7 +39,7 @@ unittest assert(gamestate(board) == State.win); } - // Won games-Finished game where X won via right column victory + // Won games - Finished game where X won via right column victory { immutable string[] board = [ "OOX", @@ -49,7 +49,7 @@ unittest assert(gamestate(board) == State.win); } - // Won games-Finished game where O won via left column victory + // Won games - Finished game where O won via left column victory { immutable string[] board = [ "OXX", @@ -59,7 +59,7 @@ unittest assert(gamestate(board) == State.win); } - // Won games-Finished game where O won via middle column victory + // Won games - Finished game where O won via middle column victory { immutable string[] board = [ "XOX", @@ -69,7 +69,7 @@ unittest assert(gamestate(board) == State.win); } - // Won games-Finished game where O won via right column victory + // Won games - Finished game where O won via right column victory { immutable string[] board = [ "XXO", @@ -79,7 +79,7 @@ unittest assert(gamestate(board) == State.win); } - // Won games-Finished game where X won via top row victory + // Won games - Finished game where X won via top row victory { immutable string[] board = [ "XXX", @@ -89,7 +89,7 @@ unittest assert(gamestate(board) == State.win); } - // Won games-Finished game where X won via middle row victory + // Won games - Finished game where X won via middle row victory { immutable string[] board = [ "O ", @@ -99,7 +99,7 @@ unittest assert(gamestate(board) == State.win); } - // Won games-Finished game where X won via bottom row victory + // Won games - Finished game where X won via bottom row victory { immutable string[] board = [ " OO", @@ -109,7 +109,7 @@ unittest assert(gamestate(board) == State.win); } - // Won games-Finished game where O won via top row victory + // Won games - Finished game where O won via top row victory { immutable string[] board = [ "OOO", @@ -119,7 +119,7 @@ unittest assert(gamestate(board) == State.win); } - // Won games-Finished game where O won via middle row victory + // Won games - Finished game where O won via middle row victory { immutable string[] board = [ "XX ", @@ -129,7 +129,7 @@ unittest assert(gamestate(board) == State.win); } - // Won games-Finished game where O won via bottom row victory + // Won games - Finished game where O won via bottom row victory { immutable string[] board = [ "XOX", @@ -139,7 +139,7 @@ unittest assert(gamestate(board) == State.win); } - // Won games-Finished game where X won via falling diagonal victory + // Won games - Finished game where X won via falling diagonal victory { immutable string[] board = [ "XOO", @@ -149,7 +149,7 @@ unittest assert(gamestate(board) == State.win); } - // Won games-Finished game where X won via rising diagonal victory + // Won games - Finished game where X won via rising diagonal victory { immutable string[] board = [ "O X", @@ -159,7 +159,7 @@ unittest assert(gamestate(board) == State.win); } - // Won games-Finished game where O won via falling diagonal victory + // Won games - Finished game where O won via falling diagonal victory { immutable string[] board = [ "OXX", @@ -169,7 +169,7 @@ unittest assert(gamestate(board) == State.win); } - // Won games-Finished game where O won via rising diagonal victory + // Won games - Finished game where O won via rising diagonal victory { immutable string[] board = [ " O", @@ -179,7 +179,7 @@ unittest assert(gamestate(board) == State.win); } - // Won games-Finished game where X won via a row and a column victory + // Won games - Finished game where X won via a row and a column victory { immutable string[] board = [ "XXX", @@ -189,7 +189,7 @@ unittest assert(gamestate(board) == State.win); } - // Won games-Finished game where X won via two diagonal victories + // Won games - Finished game where X won via two diagonal victories { immutable string[] board = [ "XOX", @@ -199,7 +199,7 @@ unittest assert(gamestate(board) == State.win); } - // Drawn games-Draw + // Drawn games - Draw { immutable string[] board = [ "XOX", @@ -209,7 +209,7 @@ unittest assert(gamestate(board) == State.draw); } - // Drawn games-Another draw + // Drawn games - Another draw { immutable string[] board = [ "XXO", @@ -219,7 +219,7 @@ unittest assert(gamestate(board) == State.draw); } - // Ongoing games-Ongoing game: one move in + // Ongoing games - Ongoing game: one move in { immutable string[] board = [ " ", @@ -229,7 +229,7 @@ unittest assert(gamestate(board) == State.ongoing); } - // Ongoing games-Ongoing game: two moves in + // Ongoing games - Ongoing game: two moves in { immutable string[] board = [ "O ", @@ -239,7 +239,7 @@ unittest assert(gamestate(board) == State.ongoing); } - // Ongoing games-Ongoing game: five moves in + // Ongoing games - Ongoing game: five moves in { immutable string[] board = [ "X ", @@ -249,7 +249,7 @@ unittest assert(gamestate(board) == State.ongoing); } - // Invalid boards-Invalid board: X went twice + // Invalid boards - Invalid board: X went twice { immutable string[] board = [ "XX ", @@ -259,7 +259,7 @@ unittest assertThrown(gamestate(board)); } - // Invalid boards-Invalid board: O started + // Invalid boards - Invalid board: O started { immutable string[] board = [ "OOX", @@ -269,7 +269,7 @@ unittest assertThrown(gamestate(board)); } - // Invalid boards-Invalid board: X won and O kept playing + // Invalid boards - Invalid board: X won and O kept playing { immutable string[] board = [ "XXX", @@ -279,7 +279,7 @@ unittest assertThrown(gamestate(board)); } - // Invalid boards-Invalid board: players kept playing after a win + // Invalid boards - Invalid board: players kept playing after a win { immutable string[] board = [ "XXX", @@ -289,7 +289,7 @@ unittest assertThrown(gamestate(board)); } - // Invalid boards-Invalid board: O kept playing after X wins + // Invalid boards - Invalid board: O kept playing after X wins { immutable string[] board = [ "OO ", @@ -299,7 +299,7 @@ unittest assertThrown(gamestate(board)); } - // Invalid boards-Invalid board: X kept playing after O wins + // Invalid boards - Invalid board: X kept playing after O wins { immutable string[] board = [ "XX ", diff --git a/exercises/practice/sublist/.meta/test_generator.py b/exercises/practice/sublist/.meta/test_generator.py new file mode 100644 index 00000000..f2c64e77 --- /dev/null +++ b/exercises/practice/sublist/.meta/test_generator.py @@ -0,0 +1,36 @@ +from lib import assert_eq, d_inline_array + +# The element type used to instantiate the template in each test case. +TYPES = { + "empty lists": "float", + "empty list within non empty list": "double", + "non empty list contains empty list": "uint", + "list equals itself": "ushort", + "different lists": "long", + "false start": "int", + "consecutive": "double", + "sublist at start": "double", + "sublist in middle": "ulong", + "sublist at end": "int", + "at start of superlist": "long", + "in middle of superlist": "float", + "at end of superlist": "ushort", + "first list missing element from second list": "short", + "second list missing element from first list": "ulong", + "first list missing additional digits from second list": "long", + "order matters to a list": "short", + "same digits but different numbers": "uint", +} + + +def gen_case(case): + kind = TYPES.get(case["description"], "int") + list_one = d_inline_array(case["input"]["listOne"]) + list_two = d_inline_array(case["input"]["listTwo"]) + return [ + f"immutable {kind}[] listOne = {list_one};", + f"immutable {kind}[] listTwo = {list_two};", + assert_eq( + f"compare!({kind})(listOne, listTwo)", f"Relation.{case['expected']}" + ), + ] diff --git a/exercises/practice/twelve-days/.meta/test_generator.py b/exercises/practice/twelve-days/.meta/test_generator.py new file mode 100644 index 00000000..13cbc88b --- /dev/null +++ b/exercises/practice/twelve-days/.meta/test_generator.py @@ -0,0 +1,11 @@ +from lib import assert_eq, d_int, d_lines + + +def gen_case(case): + prop = case["property"] + start_verse = d_int(case["input"]["startVerse"]) + end_verse = d_int(case["input"]["endVerse"]) + return [ + f"string expected =\n{d_lines(case['expected'])};", + assert_eq(f"{prop}({start_verse}, {end_verse})", "expected"), + ] diff --git a/exercises/practice/twelve-days/source/twelve_days.d b/exercises/practice/twelve-days/source/twelve_days.d index 06ebefb4..a0b9c40f 100644 --- a/exercises/practice/twelve-days/source/twelve_days.d +++ b/exercises/practice/twelve-days/source/twelve_days.d @@ -9,7 +9,7 @@ unittest { immutable int allTestsEnabled = 0; - // Verse-first day a partridge in a pear tree + // Verse - first day a partridge in a pear tree { string expected = "On the first day of Christmas my true love gave to me: a Partridge in a Pear Tree."; @@ -18,84 +18,84 @@ unittest static if (allTestsEnabled) { - // Verse-second day two turtle doves + // Verse - second day two turtle doves { string expected = "On the second day of Christmas my true love gave to me: two Turtle Doves, and a Partridge in a Pear Tree."; assert(recite(2, 2) == expected); } - // Verse-third day three french hens + // Verse - third day three french hens { string expected = "On the third day of Christmas my true love gave to me: three French Hens, two Turtle Doves, and a Partridge in a Pear Tree."; assert(recite(3, 3) == expected); } - // Verse-fourth day four calling birds + // Verse - fourth day four calling birds { string expected = "On the fourth day of Christmas my true love gave to me: four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree."; assert(recite(4, 4) == expected); } - // Verse-fifth day five gold rings + // Verse - fifth day five gold rings { string expected = "On the fifth day of Christmas my true love gave to me: five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree."; assert(recite(5, 5) == expected); } - // Verse-sixth day six geese-a-laying + // Verse - sixth day six geese-a-laying { string expected = "On the sixth day of Christmas my true love gave to me: six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree."; assert(recite(6, 6) == expected); } - // Verse-seventh day seven swans-a-swimming + // Verse - seventh day seven swans-a-swimming { string expected = "On the seventh day of Christmas my true love gave to me: seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree."; assert(recite(7, 7) == expected); } - // Verse-eighth day eight maids-a-milking + // Verse - eighth day eight maids-a-milking { string expected = "On the eighth day of Christmas my true love gave to me: eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree."; assert(recite(8, 8) == expected); } - // Verse-ninth day nine ladies dancing + // Verse - ninth day nine ladies dancing { string expected = "On the ninth day of Christmas my true love gave to me: nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree."; assert(recite(9, 9) == expected); } - // Verse-tenth day ten lords-a-leaping + // Verse - tenth day ten lords-a-leaping { string expected = "On the tenth day of Christmas my true love gave to me: ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree."; assert(recite(10, 10) == expected); } - // Verse-eleventh day eleven pipers piping + // Verse - eleventh day eleven pipers piping { string expected = "On the eleventh day of Christmas my true love gave to me: eleven Pipers Piping, ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree."; assert(recite(11, 11) == expected); } - // Verse-twelfth day twelve drummers drumming + // Verse - twelfth day twelve drummers drumming { string expected = "On the twelfth day of Christmas my true love gave to me: twelve Drummers Drumming, eleven Pipers Piping, ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree."; assert(recite(12, 12) == expected); } - // Lyrics-recites first three verses of the song + // Lyrics - recites first three verses of the song { string expected = "On the first day of Christmas my true love gave to me: a Partridge in a Pear Tree.\n" ~ @@ -104,7 +104,7 @@ unittest assert(recite(1, 3) == expected); } - // Lyrics-recites three verses from the middle of the song + // Lyrics - recites three verses from the middle of the song { string expected = "On the fourth day of Christmas my true love gave to me: four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n" ~ @@ -113,7 +113,7 @@ unittest assert(recite(4, 6) == expected); } - // Lyrics-recites the whole song + // Lyrics - recites the whole song { string expected = "On the first day of Christmas my true love gave to me: a Partridge in a Pear Tree.\n" ~ diff --git a/exercises/practice/two-bucket/.meta/test_generator.py b/exercises/practice/two-bucket/.meta/test_generator.py new file mode 100644 index 00000000..40b05077 --- /dev/null +++ b/exercises/practice/two-bucket/.meta/test_generator.py @@ -0,0 +1,22 @@ +from lib import assert_eq, assert_throws, d_int, d_string, is_error + + +def gen_case(case): + prop = case["property"] + inp = case["input"] + size1 = d_int(inp["bucketOne"]) + size2 = d_int(inp["bucketTwo"]) + goal = d_int(inp["goal"]) + start_bucket = d_string(inp["startBucket"]) + call = f"{prop}(TwoBucketInput({size1}, {size2}, {goal}, {start_bucket}))" + expected = case["expected"] + if is_error(expected): + return [assert_throws(call)] + + moves = d_int(expected["moves"]) + goal_bucket = d_string(expected["goalBucket"]) + other_amount = d_int(expected["otherBucket"]) + return [ + f"auto result = {call};", + assert_eq("result", f"TwoBucketResult({moves}, {goal_bucket}, {other_amount})"), + ] diff --git a/exercises/practice/two-fer/.meta/test_generator.py b/exercises/practice/two-fer/.meta/test_generator.py new file mode 100644 index 00000000..7d416d4c --- /dev/null +++ b/exercises/practice/two-fer/.meta/test_generator.py @@ -0,0 +1,9 @@ +from lib import assert_eq, d_string + + +def gen_case(case): + prop = case["property"] + name = case["input"]["name"] + argument = "" if name is None else d_string(name) + expected = d_string(case["expected"]) + return assert_eq(f"{prop}({argument})", expected) diff --git a/exercises/practice/two-fer/source/two_fer.d b/exercises/practice/two-fer/source/two_fer.d index 7384f155..8a2eadad 100644 --- a/exercises/practice/two-fer/source/two_fer.d +++ b/exercises/practice/two-fer/source/two_fer.d @@ -15,5 +15,4 @@ unittest // Another name given assert(twoFer("Bob") == "One for Bob, one for me."); } - } diff --git a/exercises/practice/variable-length-quantity/.meta/test_generator.py b/exercises/practice/variable-length-quantity/.meta/test_generator.py new file mode 100644 index 00000000..8b89b011 --- /dev/null +++ b/exercises/practice/variable-length-quantity/.meta/test_generator.py @@ -0,0 +1,26 @@ +from lib import assert_equal, assert_throws, d_inline_array, is_error + +TYPES = { + "encode": ("uint", "ubyte"), + "decode": ("ubyte", "uint"), +} + + +def describe(case): + return f"{case['property'].capitalize()} - {case['description']}" + + +def gen_case(case): + prop = case["property"] + input_type, expected_type = TYPES[prop] + integers = d_inline_array(case["input"]["integers"], hex) + call = f"{prop}(integers)" + + lines = [f"immutable {input_type}[] integers = {integers};"] + if is_error(case["expected"]): + lines.append(assert_throws(call)) + else: + expected = d_inline_array(case["expected"], hex) + lines.append(f"immutable {expected_type}[] expected = {expected};") + lines.append(assert_equal(call, "expected")) + return lines diff --git a/exercises/practice/variable-length-quantity/source/variable_length_quantity.d b/exercises/practice/variable-length-quantity/source/variable_length_quantity.d index 386619ea..fe5cb8e7 100644 --- a/exercises/practice/variable-length-quantity/source/variable_length_quantity.d +++ b/exercises/practice/variable-length-quantity/source/variable_length_quantity.d @@ -19,8 +19,8 @@ unittest // Encode - zero { - immutable uint[] integers = [ 0x0 ]; - immutable ubyte[] expected = [ 0x0 ]; + immutable uint[] integers = [0x0]; + immutable ubyte[] expected = [0x0]; assert(equal(encode(integers), expected)); } @@ -28,209 +28,209 @@ unittest { // Encode - arbitrary single byte { - immutable uint[] integers = [ 0x40 ]; - immutable ubyte[] expected = [ 0x40 ]; + immutable uint[] integers = [0x40]; + immutable ubyte[] expected = [0x40]; assert(equal(encode(integers), expected)); } // Encode - asymmetric single byte { - immutable uint[] integers = [ 0x53 ]; - immutable ubyte[] expected = [ 0x53 ]; + immutable uint[] integers = [0x53]; + immutable ubyte[] expected = [0x53]; assert(equal(encode(integers), expected)); } // Encode - largest single byte { - immutable uint[] integers = [ 0x7f ]; - immutable ubyte[] expected = [ 0x7f ]; + immutable uint[] integers = [0x7f]; + immutable ubyte[] expected = [0x7f]; assert(equal(encode(integers), expected)); } // Encode - smallest double byte { - immutable uint[] integers = [ 0x80 ]; - immutable ubyte[] expected = [ 0x81, 0x0 ]; + immutable uint[] integers = [0x80]; + immutable ubyte[] expected = [0x81, 0x0]; assert(equal(encode(integers), expected)); } // Encode - arbitrary double byte { - immutable uint[] integers = [ 0x2000 ]; - immutable ubyte[] expected = [ 0xc0, 0x0 ]; + immutable uint[] integers = [0x2000]; + immutable ubyte[] expected = [0xc0, 0x0]; assert(equal(encode(integers), expected)); } // Encode - asymmetric double byte { - immutable uint[] integers = [ 0xad ]; - immutable ubyte[] expected = [ 0x81, 0x2d ]; + immutable uint[] integers = [0xad]; + immutable ubyte[] expected = [0x81, 0x2d]; assert(equal(encode(integers), expected)); } // Encode - largest double byte { - immutable uint[] integers = [ 0x3fff ]; - immutable ubyte[] expected = [ 0xff, 0x7f ]; + immutable uint[] integers = [0x3fff]; + immutable ubyte[] expected = [0xff, 0x7f]; assert(equal(encode(integers), expected)); } // Encode - smallest triple byte { - immutable uint[] integers = [ 0x4000 ]; - immutable ubyte[] expected = [ 0x81, 0x80, 0x0 ]; + immutable uint[] integers = [0x4000]; + immutable ubyte[] expected = [0x81, 0x80, 0x0]; assert(equal(encode(integers), expected)); } // Encode - arbitrary triple byte { - immutable uint[] integers = [ 0x100000 ]; - immutable ubyte[] expected = [ 0xc0, 0x80, 0x0 ]; + immutable uint[] integers = [0x100000]; + immutable ubyte[] expected = [0xc0, 0x80, 0x0]; assert(equal(encode(integers), expected)); } // Encode - asymmetric triple byte { - immutable uint[] integers = [ 0x1d59c ]; - immutable ubyte[] expected = [ 0x87, 0xab, 0x1c ]; + immutable uint[] integers = [0x1d59c]; + immutable ubyte[] expected = [0x87, 0xab, 0x1c]; assert(equal(encode(integers), expected)); } // Encode - largest triple byte { - immutable uint[] integers = [ 0x1fffff ]; - immutable ubyte[] expected = [ 0xff, 0xff, 0x7f ]; + immutable uint[] integers = [0x1fffff]; + immutable ubyte[] expected = [0xff, 0xff, 0x7f]; assert(equal(encode(integers), expected)); } // Encode - smallest quadruple byte { - immutable uint[] integers = [ 0x200000 ]; - immutable ubyte[] expected = [ 0x81, 0x80, 0x80, 0x0 ]; + immutable uint[] integers = [0x200000]; + immutable ubyte[] expected = [0x81, 0x80, 0x80, 0x0]; assert(equal(encode(integers), expected)); } // Encode - arbitrary quadruple byte { - immutable uint[] integers = [ 0x8000000 ]; - immutable ubyte[] expected = [ 0xc0, 0x80, 0x80, 0x0 ]; + immutable uint[] integers = [0x8000000]; + immutable ubyte[] expected = [0xc0, 0x80, 0x80, 0x0]; assert(equal(encode(integers), expected)); } // Encode - asymmetric quadruple byte { - immutable uint[] integers = [ 0x357704 ]; - immutable ubyte[] expected = [ 0x81, 0xd5, 0xee, 0x4 ]; + immutable uint[] integers = [0x357704]; + immutable ubyte[] expected = [0x81, 0xd5, 0xee, 0x4]; assert(equal(encode(integers), expected)); } // Encode - largest quadruple byte { - immutable uint[] integers = [ 0xfffffff ]; - immutable ubyte[] expected = [ 0xff, 0xff, 0xff, 0x7f ]; + immutable uint[] integers = [0xfffffff]; + immutable ubyte[] expected = [0xff, 0xff, 0xff, 0x7f]; assert(equal(encode(integers), expected)); } // Encode - smallest quintuple byte { - immutable uint[] integers = [ 0x10000000 ]; - immutable ubyte[] expected = [ 0x81, 0x80, 0x80, 0x80, 0x0 ]; + immutable uint[] integers = [0x10000000]; + immutable ubyte[] expected = [0x81, 0x80, 0x80, 0x80, 0x0]; assert(equal(encode(integers), expected)); } // Encode - arbitrary quintuple byte { - immutable uint[] integers = [ 0xff000000 ]; - immutable ubyte[] expected = [ 0x8f, 0xf8, 0x80, 0x80, 0x0 ]; + immutable uint[] integers = [0xff000000]; + immutable ubyte[] expected = [0x8f, 0xf8, 0x80, 0x80, 0x0]; assert(equal(encode(integers), expected)); } // Encode - asymmetric quintuple byte { - immutable uint[] integers = [ 0x86656105 ]; - immutable ubyte[] expected = [ 0x88, 0xb3, 0x95, 0xc2, 0x5 ]; + immutable uint[] integers = [0x86656105]; + immutable ubyte[] expected = [0x88, 0xb3, 0x95, 0xc2, 0x5]; assert(equal(encode(integers), expected)); } // Encode - maximum 32-bit integer input { - immutable uint[] integers = [ 0xffffffff ]; - immutable ubyte[] expected = [ 0x8f, 0xff, 0xff, 0xff, 0x7f ]; + immutable uint[] integers = [0xffffffff]; + immutable ubyte[] expected = [0x8f, 0xff, 0xff, 0xff, 0x7f]; assert(equal(encode(integers), expected)); } // Encode - two single-byte values { - immutable uint[] integers = [ 0x40, 0x7f ]; - immutable ubyte[] expected = [ 0x40, 0x7f ]; + immutable uint[] integers = [0x40, 0x7f]; + immutable ubyte[] expected = [0x40, 0x7f]; assert(equal(encode(integers), expected)); } // Encode - two multi-byte values { - immutable uint[] integers = [ 0x4000, 0x123456 ]; - immutable ubyte[] expected = [ 0x81, 0x80, 0x0, 0xc8, 0xe8, 0x56 ]; + immutable uint[] integers = [0x4000, 0x123456]; + immutable ubyte[] expected = [0x81, 0x80, 0x0, 0xc8, 0xe8, 0x56]; assert(equal(encode(integers), expected)); } // Encode - many multi-byte values { - immutable uint[] integers = [ 0x2000, 0x123456, 0xfffffff, 0x0, 0x3fff, 0x4000 ]; - immutable ubyte[] expected = [ 0xc0, 0x0, 0xc8, 0xe8, 0x56, 0xff, 0xff, 0xff, 0x7f, 0x0, 0xff, 0x7f, 0x81, 0x80, 0x0 ]; + immutable uint[] integers = [0x2000, 0x123456, 0xfffffff, 0x0, 0x3fff, 0x4000]; + immutable ubyte[] expected = [0xc0, 0x0, 0xc8, 0xe8, 0x56, 0xff, 0xff, 0xff, 0x7f, 0x0, 0xff, 0x7f, 0x81, 0x80, 0x0]; assert(equal(encode(integers), expected)); } // Decode - one byte { - immutable ubyte[] integers = [ 0x7f ]; - immutable uint[] expected = [ 0x7f ]; + immutable ubyte[] integers = [0x7f]; + immutable uint[] expected = [0x7f]; assert(equal(decode(integers), expected)); } // Decode - two bytes { - immutable ubyte[] integers = [ 0xc0, 0x0 ]; - immutable uint[] expected = [ 0x2000 ]; + immutable ubyte[] integers = [0xc0, 0x0]; + immutable uint[] expected = [0x2000]; assert(equal(decode(integers), expected)); } // Decode - three bytes { - immutable ubyte[] integers = [ 0xff, 0xff, 0x7f ]; - immutable uint[] expected = [ 0x1fffff ]; + immutable ubyte[] integers = [0xff, 0xff, 0x7f]; + immutable uint[] expected = [0x1fffff]; assert(equal(decode(integers), expected)); } // Decode - four bytes { - immutable ubyte[] integers = [ 0x81, 0x80, 0x80, 0x0 ]; - immutable uint[] expected = [ 0x200000 ]; + immutable ubyte[] integers = [0x81, 0x80, 0x80, 0x0]; + immutable uint[] expected = [0x200000]; assert(equal(decode(integers), expected)); } // Decode - maximum 32-bit integer { - immutable ubyte[] integers = [ 0x8f, 0xff, 0xff, 0xff, 0x7f ]; - immutable uint[] expected = [ 0xffffffff ]; + immutable ubyte[] integers = [0x8f, 0xff, 0xff, 0xff, 0x7f]; + immutable uint[] expected = [0xffffffff]; assert(equal(decode(integers), expected)); } // Decode - incomplete sequence causes error { - immutable ubyte[] integers = [ 0xff ]; + immutable ubyte[] integers = [0xff]; assertThrown(decode(integers)); } // Decode - incomplete sequence causes error, even if value is zero { - immutable ubyte[] integers = [ 0x80 ]; + immutable ubyte[] integers = [0x80]; assertThrown(decode(integers)); } // Decode - multiple values { - immutable ubyte[] integers = [ 0xc0, 0x0, 0xc8, 0xe8, 0x56, 0xff, 0xff, 0xff, 0x7f, 0x0, 0xff, 0x7f, 0x81, 0x80, 0x0 ]; - immutable uint[] expected = [ 0x2000, 0x123456, 0xfffffff, 0x0, 0x3fff, 0x4000 ]; + immutable ubyte[] integers = [0xc0, 0x0, 0xc8, 0xe8, 0x56, 0xff, 0xff, 0xff, 0x7f, 0x0, 0xff, 0x7f, 0x81, 0x80, 0x0]; + immutable uint[] expected = [0x2000, 0x123456, 0xfffffff, 0x0, 0x3fff, 0x4000]; assert(equal(decode(integers), expected)); } } diff --git a/exercises/practice/yacht/.meta/test_generator.py b/exercises/practice/yacht/.meta/test_generator.py new file mode 100644 index 00000000..cf0a9a2d --- /dev/null +++ b/exercises/practice/yacht/.meta/test_generator.py @@ -0,0 +1,15 @@ +from lib import assert_eq, d_inline_array, d_int + + +def camel(words): + """Convert words such as "full house" to an identifier such as fullHouse.""" + first, *rest = words.split() + return first + "".join(word.capitalize() for word in rest) + + +def gen_case(case): + prop = case["property"] + dice = d_inline_array(case["input"]["dice"]) + category = camel(case["input"]["category"]) + expected = d_int(case["expected"]) + return assert_eq(f"{prop}({dice}, Category.{category})", expected) diff --git a/exercises/practice/yacht/example/yacht.d b/exercises/practice/yacht/example/yacht.d index 634fbaf8..c24571c6 100644 --- a/exercises/practice/yacht/example/yacht.d +++ b/exercises/practice/yacht/example/yacht.d @@ -66,4 +66,3 @@ int score(immutable int[] dice, Category category) return 0; } } - diff --git a/exercises/practice/yacht/source/yacht.d b/exercises/practice/yacht/source/yacht.d index 07261b1a..0f04d68f 100644 --- a/exercises/practice/yacht/source/yacht.d +++ b/exercises/practice/yacht/source/yacht.d @@ -114,4 +114,4 @@ unittest // Yacht as choice assert(score([2, 2, 2, 2, 2], Category.choice) == 10); } -} \ No newline at end of file +} diff --git a/generators/generate b/generators/generate index 72bd8497..765bd1ce 100755 --- a/generators/generate +++ b/generators/generate @@ -18,7 +18,11 @@ ROOT = pathlib.Path(__file__).resolve().parent.parent EXERCISES = ROOT / "exercises" / "practice" CACHE_PREFIX = "Using cached 'problem-specifications' dir: " ADDITIONAL_CASES = "additional-test-cases.json" -ASSERT_THROWN_IMPORT = "import std.exception : assertThrown;" +IMPORTS = { + "equal(": "import std.algorithm.comparison : equal;", + "assertThrown(": "import std.exception : assertThrown;", + "isClose(": "import std.math : isClose;", +} Case = dict[str, Any] @@ -116,10 +120,11 @@ def describe(case: Case) -> str: def render_case(module: ModuleType, case: Case) -> str: """Render one case as a comment followed by its statements.""" - body = module.gen_case(case).strip("\n") - if "\n" in body: - body = "{\n" + lib.indent(body) + "\n}" - return f"// {describe(case)}\n{body}" + description = getattr(module, "describe", describe)(case) + body = module.gen_case(case) + if not isinstance(body, str): + body = "{\n" + lib.indent("\n".join(body)) + "\n}" + return f"// {description}\n{body}" def render_unittest(module: ModuleType, cases: list[Case]) -> str: @@ -127,9 +132,13 @@ def render_unittest(module: ModuleType, cases: list[Case]) -> str: rendered = [render_case(module, case) for case in cases] sections = [] - if any("assertThrown(" in text for text in rendered): - sections.append(ASSERT_THROWN_IMPORT) - sections.append("immutable int allTestsEnabled = 0;") + imports = [ + line for call, line in IMPORTS.items() if any(call in text for text in rendered) + ] + if imports: + sections.append("\n".join(imports)) + if len(rendered) > 1: + sections.append("immutable int allTestsEnabled = 0;") sections.append(rendered[0]) if len(rendered) > 1: gated = lib.indent("\n\n".join(rendered[1:])) diff --git a/generators/lib.py b/generators/lib.py index 9d67bc6c..0a8463d4 100644 --- a/generators/lib.py +++ b/generators/lib.py @@ -29,11 +29,23 @@ def d_string(value: str) -> str: return '"' + "".join(chars) + '"' +def d_lines(lines: Iterable[str]) -> str: + """Render lines of text as a string, with one line of text per line.""" + text = "\n".join(lines) + literals = [d_string(line) for line in text.splitlines(keepends=True)] + return " ~\n".join(INDENT + literal for literal in literals) + + def d_int(value: int) -> str: """Render an integer as a D integer literal.""" return str(value) +def d_grouped_int(value: int) -> str: + """Render an integer, separating groups of digits when it has five or more.""" + return f"{value:_}" if abs(value) >= 10_000 else str(value) + + def d_bool(value: bool) -> str: """Render a boolean as a D boolean literal.""" return "true" if value else "false" @@ -77,6 +89,13 @@ def assert_eq(actual: str, expected: str) -> str: return f"assert({actual} == {expected});" +def assert_equal(first: str, second: str, wrap: bool = False) -> str: + """Assert that two ranges are equal, optionally one argument per line.""" + prefix = "assert(equal(" + separator = ",\n" + " " * len(prefix) if wrap else ", " + return f"{prefix}{first}{separator}{second}));" + + def assert_throws(expression: str) -> str: """Assert that evaluating an expression throws.""" return f"assertThrown({expression});"