Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5181a63
create Node bindings
TheRealOwenRees Mar 16, 2026
08c45a2
convert getCases to ReScript
TheRealOwenRees Mar 16, 2026
97fc94a
build test generator on project build
TheRealOwenRees Mar 16, 2026
1b94202
change type of cases
TheRealOwenRees Mar 16, 2026
94ed34a
include resolve4
TheRealOwenRees Mar 16, 2026
57b693c
only export generateTests
TheRealOwenRees Mar 16, 2026
46c3496
remove commented code
TheRealOwenRees Mar 16, 2026
08f4c5c
convert generateTests to rescript
TheRealOwenRees Mar 16, 2026
55c894d
change test case formatting
TheRealOwenRees Mar 16, 2026
0378ab7
change test generator import
TheRealOwenRees Mar 16, 2026
3257290
generate hello world tests
TheRealOwenRees Mar 16, 2026
25b496b
find input from JSON
TheRealOwenRees Mar 16, 2026
6b5290e
update test
TheRealOwenRees Mar 16, 2026
a8d54d1
acronym test gen
TheRealOwenRees Mar 16, 2026
9713b0c
test template and copy
TheRealOwenRees Mar 16, 2026
767c7da
rework Bob tests
TheRealOwenRees Mar 16, 2026
d199458
update All Your Base
TheRealOwenRees Mar 16, 2026
a543d27
update JSON stringification of input
TheRealOwenRees Mar 16, 2026
2370a38
inject assertions into test files
TheRealOwenRees Mar 16, 2026
f152f9e
rework assertions as template strings to allow injection into test files
TheRealOwenRees Mar 16, 2026
5d45115
remove unused code
TheRealOwenRees Mar 16, 2026
2cc9545
update test template to retrieve slug from filename
TheRealOwenRees Mar 16, 2026
88fe269
get slug from filename
TheRealOwenRees Mar 16, 2026
cd04551
added comments for assertions
TheRealOwenRees Mar 16, 2026
fa50680
convert anagram tests
TheRealOwenRees Mar 16, 2026
aba0c83
convert Binary Search tests
TheRealOwenRees Mar 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 18 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ check-exercise-files:
@echo "All exercises contain all required files and are in sync."

add-test-template:
@cp templates/testTemplate.js exercises/practice/$(EXERCISE)/.meta/testTemplate.js
# @cp templates/testTemplate.js exercises/practice/$(EXERCISE)/.meta/testTemplate.js
@$(eval PASCAL_EXERCISE=$(shell echo $(EXERCISE) | sed -r 's/(^|-)([a-z])/\U\2/g'))
@cp templates/Test_template.res test_templates/$(PASCAL_EXERCISE)_template.res
@echo "Copied $(PASCAL_EXERCISE)Template.res to $(EXERCISE)"

# copy all relevant files for a single exercise - test template, config etc.
copy-exercise-files:
Expand Down Expand Up @@ -85,14 +88,19 @@ format:

# Generate tests for all exercises
generate-tests:
@echo "Generating tests for all exercises..."
@for exercise in $(EXERCISES); do \
if [ -f exercises/practice/$$exercise/.meta/testTemplate.js ]; then \
echo "-> Generating: $$exercise"; \
node exercises/practice/$$exercise/.meta/testTemplate.js || exit 1; \
else \
echo "-> Skipping: $$exercise (no generator found)"; \
fi \
# @echo "Generating tests for all exercises..."
# @for exercise in $(EXERCISES); do \
# if [ -f exercises/practice/$$exercise/.meta/testTemplate.js ]; then \
# echo "-> Generating: $$exercise"; \
# node exercises/practice/$$exercise/.meta/testTemplate.js || exit 1; \
# else \
# echo "-> Skipping: $$exercise (no generator found)"; \
# fi \
# done
@echo "Generating tests from test_templates directory..."
@for template in $(wildcard test_templates/*_template.res.js); do \
echo "-> Running template: $$template"; \
node $$template || exit 1; \
done
@echo "All tests generated successfully."

Expand All @@ -105,6 +113,6 @@ endif

test:
$(MAKE) -s clean
$(MAKE) -s check-exercise-files
# $(MAKE) -s check-exercise-files
$(MAKE) -s copy-all-exercises
npm run ci
17 changes: 0 additions & 17 deletions exercises/practice/acronym/.meta/testTemplate.js

This file was deleted.

38 changes: 10 additions & 28 deletions exercises/practice/acronym/tests/Acronym_test.res
Original file line number Diff line number Diff line change
@@ -1,40 +1,22 @@
open Test
open Acronym

let stringEqual = (~message=?, a: string, b: string) => assertion(~message?, ~operator="stringEqual", (a, b) => a == b, a, b)
let equal = (~message=?, a, b) => assertion(~message?, ~operator="equal", (a, b) => a == b, a, b)

test("basic", () => {
stringEqual(~message="basic", abbreviate("Portable Network Graphics"), "PNG")
})
test("basic", () => {equal(~message="basic", abbreviate("Portable Network Graphics"), "PNG")})

test("lowercase words", () => {
stringEqual(~message="lowercase words", abbreviate("Ruby on Rails"), "ROR")
})
test("lowercase words", () => {equal(~message="lowercase words", abbreviate("Ruby on Rails"), "ROR")})

test("punctuation", () => {
stringEqual(~message="punctuation", abbreviate("First In, First Out"), "FIFO")
})
test("punctuation", () => {equal(~message="punctuation", abbreviate("First In, First Out"), "FIFO")})

test("all caps word", () => {
stringEqual(~message="all caps word", abbreviate("GNU Image Manipulation Program"), "GIMP")
})
test("all caps word", () => {equal(~message="all caps word", abbreviate("GNU Image Manipulation Program"), "GIMP")})

test("punctuation without whitespace", () => {
stringEqual(~message="punctuation without whitespace", abbreviate("Complementary metal-oxide semiconductor"), "CMOS")
})
test("punctuation without whitespace", () => {equal(~message="punctuation without whitespace", abbreviate("Complementary metal-oxide semiconductor"), "CMOS")})

test("very long abbreviation", () => {
stringEqual(~message="very long abbreviation", abbreviate("Rolling On The Floor Laughing So Hard That My Dogs Came Over And Licked Me"), "ROTFLSHTMDCOALM")
})
test("very long abbreviation", () => {equal(~message="very long abbreviation", abbreviate("Rolling On The Floor Laughing So Hard That My Dogs Came Over And Licked Me"), "ROTFLSHTMDCOALM")})

test("consecutive delimiters", () => {
stringEqual(~message="consecutive delimiters", abbreviate("Something - I made up from thin air"), "SIMUFTA")
})
test("consecutive delimiters", () => {equal(~message="consecutive delimiters", abbreviate("Something - I made up from thin air"), "SIMUFTA")})

test("apostrophes", () => {
stringEqual(~message="apostrophes", abbreviate("Halley's Comet"), "HC")
})
test("apostrophes", () => {equal(~message="apostrophes", abbreviate("Halley's Comet"), "HC")})

test("underscore emphasis", () => {
stringEqual(~message="underscore emphasis", abbreviate("The Road _Not_ Taken"), "TRNT")
})
test("underscore emphasis", () => {equal(~message="underscore emphasis", abbreviate("The Road _Not_ Taken"), "TRNT")})
86 changes: 22 additions & 64 deletions exercises/practice/all-your-base/tests/AllYourBase_test.res
Original file line number Diff line number Diff line change
@@ -1,88 +1,46 @@
open Test
open AllYourBase

let assertEqual = (~message=?, a: 'a, b: 'a) => assertion(~message?, ~operator="assertEqual", (a, b) => a == b, a, b)
let equal = (~message=?, a, b) => assertion(~message?, ~operator="equal", (a, b) => a == b, a, b)

test("single bit one to decimal", () => {
assertEqual(~message="single bit one to decimal", rebase(2, [1], 10), Some([1]))
})
test("single bit one to decimal", () => {equal(~message="single bit one to decimal", rebase(2, [1], 10), Some([1]))})

test("binary to single decimal", () => {
assertEqual(~message="binary to single decimal", rebase(2, [1, 0, 1], 10), Some([5]))
})
test("binary to single decimal", () => {equal(~message="binary to single decimal", rebase(2, [1,0,1], 10), Some([5]))})

test("single decimal to binary", () => {
assertEqual(~message="single decimal to binary", rebase(10, [5], 2), Some([1, 0, 1]))
})
test("single decimal to binary", () => {equal(~message="single decimal to binary", rebase(10, [5], 2), Some([1,0,1]))})

test("binary to multiple decimal", () => {
assertEqual(~message="binary to multiple decimal", rebase(2, [1, 0, 1, 0, 1, 0], 10), Some([4, 2]))
})
test("binary to multiple decimal", () => {equal(~message="binary to multiple decimal", rebase(2, [1,0,1,0,1,0], 10), Some([4,2]))})

test("decimal to binary", () => {
assertEqual(~message="decimal to binary", rebase(10, [4, 2], 2), Some([1, 0, 1, 0, 1, 0]))
})
test("decimal to binary", () => {equal(~message="decimal to binary", rebase(10, [4,2], 2), Some([1,0,1,0,1,0]))})

test("trinary to hexadecimal", () => {
assertEqual(~message="trinary to hexadecimal", rebase(3, [1, 1, 2, 0], 16), Some([2, 10]))
})
test("trinary to hexadecimal", () => {equal(~message="trinary to hexadecimal", rebase(3, [1,1,2,0], 16), Some([2,10]))})

test("hexadecimal to trinary", () => {
assertEqual(~message="hexadecimal to trinary", rebase(16, [2, 10], 3), Some([1, 1, 2, 0]))
})
test("hexadecimal to trinary", () => {equal(~message="hexadecimal to trinary", rebase(16, [2,10], 3), Some([1,1,2,0]))})

test("15-bit integer", () => {
assertEqual(~message="15-bit integer", rebase(97, [3, 46, 60], 73), Some([6, 10, 45]))
})
test("15-bit integer", () => {equal(~message="15-bit integer", rebase(97, [3,46,60], 73), Some([6,10,45]))})

test("empty list", () => {
assertEqual(~message="empty list", rebase(2, [], 10), Some([0]))
})
test("empty list", () => {equal(~message="empty list", rebase(2, [], 10), Some([0]))})

test("single zero", () => {
assertEqual(~message="single zero", rebase(10, [0], 2), Some([0]))
})
test("single zero", () => {equal(~message="single zero", rebase(10, [0], 2), Some([0]))})

test("multiple zeros", () => {
assertEqual(~message="multiple zeros", rebase(10, [0, 0, 0], 2), Some([0]))
})
test("multiple zeros", () => {equal(~message="multiple zeros", rebase(10, [0,0,0], 2), Some([0]))})

test("leading zeros", () => {
assertEqual(~message="leading zeros", rebase(7, [0, 6, 0], 10), Some([4, 2]))
})
test("leading zeros", () => {equal(~message="leading zeros", rebase(7, [0,6,0], 10), Some([4,2]))})

test("input base is one", () => {
assertEqual(~message="input base is one", rebase(1, [0], 10), None)
})
test("input base is one", () => {equal(~message="input base is one", rebase(1, [0], 10), None)})

test("input base is zero", () => {
assertEqual(~message="input base is zero", rebase(0, [], 10), None)
})
test("input base is zero", () => {equal(~message="input base is zero", rebase(0, [], 10), None)})

test("input base is negative", () => {
assertEqual(~message="input base is negative", rebase(-2, [1], 10), None)
})
test("input base is negative", () => {equal(~message="input base is negative", rebase(-2, [1], 10), None)})

test("negative digit", () => {
assertEqual(~message="negative digit", rebase(2, [1, -1, 1, 0, 1, 0], 10), None)
})
test("negative digit", () => {equal(~message="negative digit", rebase(2, [1,-1,1,0,1,0], 10), None)})

test("invalid positive digit", () => {
assertEqual(~message="invalid positive digit", rebase(2, [1, 2, 1, 0, 1, 0], 10), None)
})
test("invalid positive digit", () => {equal(~message="invalid positive digit", rebase(2, [1,2,1,0,1,0], 10), None)})

test("output base is one", () => {
assertEqual(~message="output base is one", rebase(2, [1, 0, 1, 0, 1, 0], 1), None)
})
test("output base is one", () => {equal(~message="output base is one", rebase(2, [1,0,1,0,1,0], 1), None)})

test("output base is zero", () => {
assertEqual(~message="output base is zero", rebase(10, [7], 0), None)
})
test("output base is zero", () => {equal(~message="output base is zero", rebase(10, [7], 0), None)})

test("output base is negative", () => {
assertEqual(~message="output base is negative", rebase(2, [1], -7), None)
})
test("output base is negative", () => {equal(~message="output base is negative", rebase(2, [1], -7), None)})

test("both bases are negative", () => {
assertEqual(~message="both bases are negative", rebase(-2, [1], -7), None)
})
test("both bases are negative", () => {equal(~message="both bases are negative", rebase(-2, [1], -7), None)})
23 changes: 0 additions & 23 deletions exercises/practice/anagram/.meta/testTemplate.js

This file was deleted.

74 changes: 19 additions & 55 deletions exercises/practice/anagram/tests/Anagram_test.res
Original file line number Diff line number Diff line change
@@ -1,76 +1,40 @@
open Test
open Anagram

let assertEqual = (~message=?, a: 'a, b: 'a) => assertion(~message?, ~operator="assertEqual", (a, b) => a == b, a, b)
let equal = (~message=?, a, b) => assertion(~message?, ~operator="equal", (a, b) => a == b, a, b)

test("no matches", () => {
assertEqual(~message="no matches", findAnagrams("diaper", ["hello","world","zombies","pants"]), None)
})
test("no matches", () => {equal(~message="no matches", findAnagrams("diaper", ["hello","world","zombies","pants"]), None)})

test("detects two anagrams", () => {
assertEqual(~message="detects two anagrams", findAnagrams("solemn", ["lemons","cherry","melons"]), Some(["lemons","melons"]))
})
test("detects two anagrams", () => {equal(~message="detects two anagrams", findAnagrams("solemn", ["lemons","cherry","melons"]), Some(["lemons","melons"]))})

test("does not detect anagram subsets", () => {
assertEqual(~message="does not detect anagram subsets", findAnagrams("good", ["dog","goody"]), None)
})
test("does not detect anagram subsets", () => {equal(~message="does not detect anagram subsets", findAnagrams("good", ["dog","goody"]), None)})

test("detects anagram", () => {
assertEqual(~message="detects anagram", findAnagrams("listen", ["enlists","google","inlets","banana"]), Some(["inlets"]))
})
test("detects anagram", () => {equal(~message="detects anagram", findAnagrams("listen", ["enlists","google","inlets","banana"]), Some(["inlets"]))})

test("detects three anagrams", () => {
assertEqual(~message="detects three anagrams", findAnagrams("allergy", ["gallery","ballerina","regally","clergy","largely","leading"]), Some(["gallery","regally","largely"]))
})
test("detects three anagrams", () => {equal(~message="detects three anagrams", findAnagrams("allergy", ["gallery","ballerina","regally","clergy","largely","leading"]), Some(["gallery","regally","largely"]))})

test("detects multiple anagrams with different case", () => {
assertEqual(~message="detects multiple anagrams with different case", findAnagrams("nose", ["Eons","ONES"]), Some(["Eons","ONES"]))
})
test("detects multiple anagrams with different case", () => {equal(~message="detects multiple anagrams with different case", findAnagrams("nose", ["Eons","ONES"]), Some(["Eons","ONES"]))})

test("does not detect non-anagrams with identical checksum", () => {
assertEqual(~message="does not detect non-anagrams with identical checksum", findAnagrams("mass", ["last"]), None)
})
test("does not detect non-anagrams with identical checksum", () => {equal(~message="does not detect non-anagrams with identical checksum", findAnagrams("mass", ["last"]), None)})

test("detects anagrams case-insensitively", () => {
assertEqual(~message="detects anagrams case-insensitively", findAnagrams("Orchestra", ["cashregister","Carthorse","radishes"]), Some(["Carthorse"]))
})
test("detects anagrams case-insensitively", () => {equal(~message="detects anagrams case-insensitively", findAnagrams("Orchestra", ["cashregister","Carthorse","radishes"]), Some(["Carthorse"]))})

test("detects anagrams using case-insensitive subject", () => {
assertEqual(~message="detects anagrams using case-insensitive subject", findAnagrams("Orchestra", ["cashregister","carthorse","radishes"]), Some(["carthorse"]))
})
test("detects anagrams using case-insensitive subject", () => {equal(~message="detects anagrams using case-insensitive subject", findAnagrams("Orchestra", ["cashregister","carthorse","radishes"]), Some(["carthorse"]))})

test("detects anagrams using case-insensitive possible matches", () => {
assertEqual(~message="detects anagrams using case-insensitive possible matches", findAnagrams("orchestra", ["cashregister","Carthorse","radishes"]), Some(["Carthorse"]))
})
test("detects anagrams using case-insensitive possible matches", () => {equal(~message="detects anagrams using case-insensitive possible matches", findAnagrams("orchestra", ["cashregister","Carthorse","radishes"]), Some(["Carthorse"]))})

test("does not detect an anagram if the original word is repeated", () => {
assertEqual(~message="does not detect an anagram if the original word is repeated", findAnagrams("go", ["goGoGO"]), None)
})
test("does not detect an anagram if the original word is repeated", () => {equal(~message="does not detect an anagram if the original word is repeated", findAnagrams("go", ["goGoGO"]), None)})

test("anagrams must use all letters exactly once", () => {
assertEqual(~message="anagrams must use all letters exactly once", findAnagrams("tapper", ["patter"]), None)
})
test("anagrams must use all letters exactly once", () => {equal(~message="anagrams must use all letters exactly once", findAnagrams("tapper", ["patter"]), None)})

test("words are not anagrams of themselves", () => {
assertEqual(~message="words are not anagrams of themselves", findAnagrams("BANANA", ["BANANA"]), None)
})
test("words are not anagrams of themselves", () => {equal(~message="words are not anagrams of themselves", findAnagrams("BANANA", ["BANANA"]), None)})

test("words are not anagrams of themselves even if letter case is partially different", () => {
assertEqual(~message="words are not anagrams of themselves even if letter case is partially different", findAnagrams("BANANA", ["Banana"]), None)
})
test("words are not anagrams of themselves even if letter case is partially different", () => {equal(~message="words are not anagrams of themselves even if letter case is partially different", findAnagrams("BANANA", ["Banana"]), None)})

test("words are not anagrams of themselves even if letter case is completely different", () => {
assertEqual(~message="words are not anagrams of themselves even if letter case is completely different", findAnagrams("BANANA", ["banana"]), None)
})
test("words are not anagrams of themselves even if letter case is completely different", () => {equal(~message="words are not anagrams of themselves even if letter case is completely different", findAnagrams("BANANA", ["banana"]), None)})

test("words other than themselves can be anagrams", () => {
assertEqual(~message="words other than themselves can be anagrams", findAnagrams("LISTEN", ["LISTEN","Silent"]), Some(["Silent"]))
})
test("words other than themselves can be anagrams", () => {equal(~message="words other than themselves can be anagrams", findAnagrams("LISTEN", ["LISTEN","Silent"]), Some(["Silent"]))})

test("handles case of greek letters", () => {
assertEqual(~message="handles case of greek letters", findAnagrams("ΑΒΓ", ["ΒΓΑ","ΒΓΔ","γβα","αβγ"]), Some(["ΒΓΑ","γβα"]))
})
test("handles case of greek letters", () => {equal(~message="handles case of greek letters", findAnagrams("ΑΒΓ", ["ΒΓΑ","ΒΓΔ","γβα","αβγ"]), Some(["ΒΓΑ","γβα"]))})

test("different characters may have the same bytes", () => {
assertEqual(~message="different characters may have the same bytes", findAnagrams("a⬂", ["€a"]), None)
})
test("different characters may have the same bytes", () => {equal(~message="different characters may have the same bytes", findAnagrams("a⬂", ["€a"]), None)})
Loading
Loading