diff --git a/.gitignore b/.gitignore index ea0d1853..5b175045 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.swp .DS_Store tmp +*~ \ No newline at end of file diff --git a/README.md b/README.md index f18d638c..2c32c6c8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,11 @@ # xErlang -Exercism exercises in Erlang +Exercism exercises in Erlang. + +For each test there is a directory, which contains two files, e.g., in the `bob` dir +there is `bob_test.erl` and `example.erl`. The example file define a module with the +name `bob`, so that we can use it to check that the tests are running as they should. +The users of exercism will create their own `bob.erl` file and `bob_test` will test it. ## Contributing Guide diff --git a/_test/check-exercises.escript b/_test/check-exercises.escript new file mode 100755 index 00000000..60dddf6b --- /dev/null +++ b/_test/check-exercises.escript @@ -0,0 +1,34 @@ +#! /usr/bin/env escript + +main( [] ) -> + Examples = filelib:wildcard( "*/example.erl" ), + Modules = [{X, compile(X)} || X <- Examples], + [compile_tests(X) || X <- Modules], + Results = [run_tests(X) || X <- Modules], + erlang:halt( erlang:length([X || X <- Results, X =:= ok]) ); +main( _ ) -> usage(). + + + +compile( File ) -> + Compile = compile:file( File, [binary, return_errors] ), + {compile, File, {ok, Module, Binary}} = {compile, File, Compile}, + Load = code:load_binary( Module, File, Binary ), + {load, Module, Load} = {load, Module, Load}, + {Module, Binary}. + + +compile_tests( {Example, {Example_module, _Binary}} ) -> + Filename = erlang:atom_to_list(Example_module) ++ "_tests.erl", + Filepath = filename:join( [filename:dirname(Example), Filename] ), + compile( Filepath ). + + +run_tests( {_Example, {Module, _Binary}} ) -> + io:fwrite( "~p: ", [Module] ), + eunit:test( Module ). + + +usage() -> + io:fwrite( "Usage: ~s~n", [escript:script_name()] ), + io:fwrite( "~s will compile and run Erlang examples and test cases in sub directories of where it is started.~n", [escript:script_name()] ). diff --git a/accumulate/accumulate_tests.erl b/accumulate/accumulate_tests.erl new file mode 100644 index 00000000..96564135 --- /dev/null +++ b/accumulate/accumulate_tests.erl @@ -0,0 +1,25 @@ +-module( accumulate_tests ). + +-include_lib("eunit/include/eunit.hrl"). + +accumulate_squares_test() -> + Fn = fun(Number) -> Number * Number end, + Ls = [1, 2, 3], + ?assertEqual([1, 4, 9], accumulate:accumulate(Fn, Ls)). + +accumulate_upcases_test() -> + Fn = fun(Word) -> string:to_upper(Word) end, + Ls = string:tokens("hello world", " "), + ?assertEqual(["HELLO", "WORLD"], accumulate:accumulate(Fn, Ls)). + +accumulate_reversed_strings_test() -> + Fn = fun(Word) -> lists:reverse(Word) end, + Ls = string:tokens("the quick brown fox etc", " "), + ?assertEqual(["eht", "kciuq", "nworb", "xof", "cte"], accumulate:accumulate(Fn, Ls)). + +accumulate_recursively_test() -> + Chars = string:tokens("a b c", " "), + Nums = string:tokens("1 2 3", " "), + Fn = fun(Char) -> [Char ++ Num || Num <- Nums] end, + ?assertEqual([["a1", "a2", "a3"], ["b1", "b2", "b3"], ["c1", "c2", "c3"]], accumulate:accumulate(Fn, Chars)). + diff --git a/allergies/allergies_test.erl b/allergies/allergies_test.erl new file mode 100644 index 00000000..23b7d579 --- /dev/null +++ b/allergies/allergies_test.erl @@ -0,0 +1,49 @@ +% To run tests: +% elc *.erl +% erl -noshell -eval "eunit:test(allergies, [verbose])" -s init stop +% + +-module(allergies_test). + +-include_lib("eunit/include/eunit.hrl"). + +no_allergies_at_all_test() -> + ?assertEqual(allergies:allergies(0), []). + +allergic_to_just_eggs_test() -> + ?assertEqual(allergies:allergies(1), ['eggs']). + +allergic_to_just_peanuts_test() -> + ?assertEqual(allergies:allergies(2), ['peanuts']). + +allergic_to_just_strawberries_test() -> + ?assertEqual(allergies:allergies(8), ['strawberries']). + +allergic_to_eggs_and_peanuts_test() -> + ?assertEqual(allergies:allergies(3), ['eggs', 'peanuts']). + +allergic_to_more_than_eggs_but_not_peanuts_test() -> + ?assertEqual(allergies:allergies(5), ['eggs', 'shellfish']). + +allergic_to_lots_of_stuff_test() -> + ?assertEqual(allergies:allergies(248), ['strawberries', 'tomatoes', 'chocolate', + 'pollen', 'cats']). + +allergic_to_everything_test() -> + ?assertEqual(allergies:allergies(255),['eggs', 'peanuts', 'shellfish', 'strawberries', + 'tomatoes', 'chocolate', 'pollen', 'cats']). + +no_allergies_means_not_allergic_test() -> + ?assertNot(allergies:isAllergicTo('peanuts', 0)), + ?assertNot(allergies:isAllergicTo('cats', 0)), + ?assertNot(allergies:isAllergicTo('strawberries', 0)). + +is_allergic_to_eggs_test() -> + ?assert(allergies:isAllergicTo('eggs', 1)). + +allergic_to_eggs_and_other_stuff_test() -> + ?assert(allergies:isAllergicTo('eggs', 5)). + +ignore_non_allergen_score_parts_test() -> + ?assertEqual(allergies:allergies(509), ['eggs', 'shellfish', 'strawberries', + 'tomatoes', 'chocolate', 'pollen', 'cats']). diff --git a/allergies/allergies_tests.erl b/allergies/allergies_tests.erl index 1ddcaeb9..1af49fb9 100644 --- a/allergies/allergies_tests.erl +++ b/allergies/allergies_tests.erl @@ -3,7 +3,7 @@ % erl -noshell -eval "eunit:test(allergies, [verbose])" -s init stop % --module(allergies_tests). +-module( allergies_tests ). -include_lib("eunit/include/eunit.hrl"). diff --git a/anagram/anagram_tests.erl b/anagram/anagram_tests.erl new file mode 100644 index 00000000..8d0def08 --- /dev/null +++ b/anagram/anagram_tests.erl @@ -0,0 +1,48 @@ +-module( anagram_tests ). +-include_lib("eunit/include/eunit.hrl"). + +no_matches_test() -> + ?assertEqual( + anagram:find("diaper", ["hello", "world", "zombies", "pants"]), + []). + +detect_simple_anagram_test() -> + ?assertEqual( + anagram:find("ant", ["tan", "stand", "at"]), + ["tan"]). + +does_not_confuse_different_duplicates_test() -> + ?assertEqual( + anagram:find("galea", ["eagle"]), + []). + +eliminate_anagram_subsets_test() -> + ?assertEqual( + anagram:find("good", ["dog", "goody"]), + []). + +detect_anagram_test() -> + ?assertEqual( + anagram:find("listen", ["enlists", "google", "inlets", "banana"]), + ["inlets"]). + +multiple_anagrams_test() -> + ?assertEqual( + anagram:find("allergy", ["gallery", "ballerina", "regally", "clergy", + "largely", "leading"]), + ["gallery", "regally", "largely"]). + +case_insensitive_subject_test() -> + ?assertEqual( + anagram:find("Orchestra", ["cashregister", "carthorse", "radishes"]), + ["carthorse"]). + +case_insensitive_candidate_test() -> + ?assertEqual( + anagram:find("orchestra", ["cashregister", "Carthorse", "radishes"]), + ["Carthorse"]). + +does_not_detect_a_word_as_its_own_anagram_test() -> + ?assertEqual( + anagram:find("corn", ["corn", "dark", "Corn", "rank", "CORN", "cron", "park"]), + ["cron"]). diff --git a/bank-account/bank_account_tests.erl b/bank-account/bank_account_tests.erl new file mode 100644 index 00000000..ed84ce0f --- /dev/null +++ b/bank-account/bank_account_tests.erl @@ -0,0 +1,95 @@ +-module(bank_account_tests). +-include_lib("eunit/include/eunit.hrl"). + + +create_test() -> + Bank_account = bank_account:create(), + ?assert(bank_account:balance( Bank_account ) =:= 0). + +close_account_test() -> + Bank_account = bank_account:create(), + bank_account:deposit( Bank_account, 1 ), + Amount = bank_account:close( Bank_account ), + ?assert(Amount =:= 1), + ?assertError(function_clause, bank_account:balance( Bank_account )). + +deposit_test() -> + Bank_account = bank_account:create(), + bank_account:deposit( Bank_account, 1 ), + ?assert(bank_account:balance( Bank_account ) =:= 1). + +deposit_fail_test() -> + Bank_account = bank_account:create(), + bank_account:deposit( Bank_account, -1 ), + ?assert(bank_account:balance( Bank_account ) =:= 0). + +deposit_many_test() -> + Bank_account = bank_account:create(), + [erlang:spawn( fun () -> bank_account:deposit(Bank_account, X) end ) || X <- lists:seq(1, 10)], + First = bank_account:balance( Bank_account ), + timer:sleep( 100 ), + Last = bank_account:balance( Bank_account ), + ?assert(First < 55), + ?assert(Last =:= 55). + +withdraw_test() -> + Bank_account = bank_account:create(), + bank_account:deposit( Bank_account, 10 ), + Amount = bank_account:withdraw( Bank_account, 1 ), + ?assert(Amount =:= 1), + ?assert(bank_account:balance( Bank_account ) =:= 9). + +withdraw_fail_test() -> + Bank_account = bank_account:create(), + bank_account:deposit( Bank_account, 10 ), + Amount = bank_account:withdraw( Bank_account, -1 ), + ?assert(Amount =:= 0), + ?assert(bank_account:balance( Bank_account ) =:= 10). + +withdraw_excessive_test() -> + Bank_account = bank_account:create(), + bank_account:deposit( Bank_account, 10 ), + Amount = bank_account:withdraw( Bank_account, 20 ), + ?assert(Amount =:= 10), + ?assert(bank_account:balance( Bank_account ) =:= 0). + +withdraw_many_test() -> + Bank_account = bank_account:create(), + bank_account:deposit(Bank_account, 55 ), + [erlang:spawn( fun () -> bank_account:withdraw(Bank_account, X) end ) || X <- lists:seq(1, 10)], + First = bank_account:balance( Bank_account ), + timer:sleep( 100 ), + Last = bank_account:balance( Bank_account ), + ?assert(First > 0), + ?assert(Last =:= 0). + +charge_test() -> + Bank_account = bank_account:create(), + bank_account:deposit( Bank_account, 10 ), + Amount = bank_account:charge( Bank_account, 2 ), + ?assert(Amount =:= 2), + ?assert(bank_account:balance( Bank_account ) =:= 8). + +charge_fail_test() -> + Bank_account = bank_account:create(), + bank_account:deposit( Bank_account, 10 ), + Amount = bank_account:charge( Bank_account, -2 ), + ?assert(Amount =:= 0), + ?assert(bank_account:balance( Bank_account ) =:= 10). + +charge_excessive_test() -> + Bank_account = bank_account:create(), + bank_account:deposit( Bank_account, 10 ), + Amount = bank_account:charge( Bank_account, 20 ), + ?assert(Amount =:= 0), + ?assert(bank_account:balance( Bank_account ) =:= 10). + +charge_many_test() -> + Bank_account = bank_account:create(), + bank_account:deposit(Bank_account, 55 ), + [erlang:spawn( fun () -> bank_account:charge(Bank_account, 10) end ) || _X <- lists:seq(1, 10)], + First = bank_account:balance( Bank_account ), + timer:sleep( 100 ), + Last = bank_account:balance( Bank_account ), + ?assert(First > 0), + ?assert(Last =:= 5). diff --git a/bank-account/example.erl b/bank-account/example.erl new file mode 100644 index 00000000..97b7e9fb --- /dev/null +++ b/bank-account/example.erl @@ -0,0 +1,48 @@ +-module(bank_account). + +-export( [balance/1, charge/2, close/1, create/0, deposit/2, withdraw/2] ). + +balance( Pid ) -> call( erlang:is_process_alive(Pid), Pid, balance, 0 ). + +charge( Pid, Amount ) when Amount > 0 -> call( erlang:is_process_alive(Pid), Pid, charge, Amount ); +charge( _Pid, _Amount ) -> 0. + +close( Pid ) -> call( erlang:is_process_alive(Pid), Pid, close, 0 ). + +create() -> erlang:spawn( fun () -> loop(0) end ). + +deposit( Pid, Amount ) when Amount > 0 -> Pid ! {deposit, Amount}; +deposit( _Pid, _Amount ) -> ok. + +withdraw( Pid, Amount ) when Amount > 0 -> call( erlang:is_process_alive(Pid), Pid, withdraw, Amount ); +withdraw( _Pid, _Amount ) -> 0. + + + +call( true, Pid, Request, Argument ) -> + Pid ! {Request, Argument, erlang:self()}, + receive + {Request, Answer} -> Answer + end. + +loop( Balance ) -> + receive + {balance, _Argument, Pid} -> + Pid ! {balance, Balance}, + loop( Balance ); + {charge, Amount, Pid} -> + Charge = loop_charge( Balance, Amount ), + Pid ! {charge, Charge}, + loop( Balance - Charge ); + {close, _Argument, Pid} -> + Pid ! {close, Balance}; + {deposit, Amount} -> + loop( Balance + Amount ); + {withdraw, Amount, Pid} -> + Withdraw = erlang:min( Balance, Amount ), + Pid ! {withdraw, Withdraw}, + loop( Balance - Withdraw ) + end. + +loop_charge( Balance, Amount ) when Balance >= Amount -> Amount; +loop_charge( _Balance, _Amount ) -> 0. diff --git a/beer-song/beer_song_tests.erl b/beer-song/beer_song_tests.erl new file mode 100644 index 00000000..3ad89214 --- /dev/null +++ b/beer-song/beer_song_tests.erl @@ -0,0 +1,50 @@ +-module( beer_song_tests ). +-include_lib("eunit/include/eunit.hrl"). + +verse_test() -> + compareNestedLists(beer_song:verse(8), + "8 bottles of beer on the wall, 8 bottles of beer.\n" + "Take it down and pass it around, 7 bottles of beer on the wall.\n"). + +verse_0_test() -> + compareNestedLists(beer_song:verse(0), + "No more bottles of beer on the wall, no more bottles of beer.\n" + "Go to the store and buy some more, 99 bottles of beer on the wall.\n"). + +verse_1_test() -> + compareNestedLists(beer_song:verse(1), + "1 bottle of beer on the wall, 1 bottle of beer.\n" + "Take it down and pass it around, no more bottles of beer on the wall.\n"). + +verse_2_test() -> + compareNestedLists(beer_song:verse(2), + "2 bottles of beer on the wall, 2 bottles of beer.\n" + "Take it down and pass it around, 1 bottle of beer on the wall.\n"). + +singing_several_verses_test() -> + compareNestedLists(beer_song:sing(8, 6), + "8 bottles of beer on the wall, 8 bottles of beer.\n" + "Take it down and pass it around, 7 bottles of beer on the wall.\n\n" + + "7 bottles of beer on the wall, 7 bottles of beer.\n" + "Take it down and pass it around, 6 bottles of beer on the wall.\n\n" + + "6 bottles of beer on the wall, 6 bottles of beer.\n" + "Take it down and pass it around, 5 bottles of beer on the wall.\n\n"). + +sing_all_the_rest_of_the_verses_test() -> + compareNestedLists(beer_song:sing(3), + "3 bottles of beer on the wall, 3 bottles of beer.\n" + "Take it down and pass it around, 2 bottles of beer on the wall.\n\n" + + "2 bottles of beer on the wall, 2 bottles of beer.\n" + "Take it down and pass it around, 1 bottle of beer on the wall.\n\n" + + "1 bottle of beer on the wall, 1 bottle of beer.\n" + "Take it down and pass it around, no more bottles of beer on the wall.\n\n" + + "No more bottles of beer on the wall, no more bottles of beer.\n" + "Go to the store and buy some more, 99 bottles of beer on the wall.\n\n"). + +compareNestedLists(Response, Expected) -> + ?assertEqual(lists:flatten(Response), lists:flatten(Expected)). diff --git a/bin/configlet-darwin-386 b/bin/configlet-darwin-386 new file mode 100755 index 00000000..514ec094 Binary files /dev/null and b/bin/configlet-darwin-386 differ diff --git a/bin/configlet-darwin-amd64 b/bin/configlet-darwin-amd64 new file mode 100755 index 00000000..1142a8c7 Binary files /dev/null and b/bin/configlet-darwin-amd64 differ diff --git a/bin/configlet-linux-386 b/bin/configlet-linux-386 new file mode 100755 index 00000000..2ff44037 Binary files /dev/null and b/bin/configlet-linux-386 differ diff --git a/bin/configlet-linux-amd64 b/bin/configlet-linux-amd64 new file mode 100755 index 00000000..45ec32d5 Binary files /dev/null and b/bin/configlet-linux-amd64 differ diff --git a/bin/configlet-windows-386.exe b/bin/configlet-windows-386.exe new file mode 100755 index 00000000..64f20caf Binary files /dev/null and b/bin/configlet-windows-386.exe differ diff --git a/bin/configlet-windows-amd64.exe b/bin/configlet-windows-amd64.exe new file mode 100755 index 00000000..39fc7872 Binary files /dev/null and b/bin/configlet-windows-amd64.exe differ diff --git a/binary/binary_string_tests.erl b/binary/binary_string_tests.erl new file mode 100644 index 00000000..8648a3ac --- /dev/null +++ b/binary/binary_string_tests.erl @@ -0,0 +1,22 @@ +-module( binary_string_tests ). +-include_lib( "eunit/include/eunit.hrl" ). + + +one_test() -> check( "1" ). + +two_test() -> check( "10" ). + +three_test() -> check( "11" ). + +four_test() -> check( "100" ). + +nine_test() -> check( "1001" ). + +twenty_six_test() -> check( "11010" ). + +large_test() -> check( "10001101000" ). + +carrot_test() -> ?assert(0 =:= binary_string:to_decimal( "carrot" )). + +check( String ) -> + ?assert(binary_string:to_decimal( String ) =:= erlang:list_to_integer( String, 2 )). diff --git a/binary/example.erl b/binary/example.erl new file mode 100644 index 00000000..0c3225ec --- /dev/null +++ b/binary/example.erl @@ -0,0 +1,17 @@ +-module( binary_string ). % binary is a "sticky module" so we have to use another name. +-export( [to_decimal/1] ). + +to_decimal( String ) -> + try + {_N, Result} = lists:foldr( fun to_decimal/2, {0, 0}, String ), + Result + + catch + _:_ -> 0 + + end. + + + +to_decimal( $0, {N, Acc} ) -> {N + 1, Acc}; +to_decimal( $1, {N, Acc} ) -> {N + 1, Acc + erlang:trunc(math:pow(2, N))}. diff --git a/bob/bob_tests.erl b/bob/bob_tests.erl new file mode 100644 index 00000000..6dbb9389 --- /dev/null +++ b/bob/bob_tests.erl @@ -0,0 +1,70 @@ +-module( bob_tests ). + +-include_lib("eunit/include/eunit.hrl"). + +responds_to_something_test() -> + bob_responds("Tom-ay-to, tom-aaaah-to.", "Whatever."). + +responds_to_shouts_test() -> + bob_responds("WATCH OUT!", "Woah, chill out!"). + +responds_to_questions_test() -> + bob_responds("Does this cryogenic chamber make me look fat?", "Sure."). + +responds_to_forceful_talking_test() -> + bob_responds("Let's go make out behind the gym!", "Whatever."). + +responds_to_acronyms_test() -> + bob_responds("It's OK if you don't want to go to the DMV.", "Whatever."). + +responds_to_forceful_questions_test() -> + bob_responds("WHAT THE HELL WERE YOU THINKING?", "Woah, chill out!"). + +responds_to_shouting_with_special_characters_test() -> + bob_responds("ZOMG THE %^*@#$(*^ ZOMBIES ARE COMING!!11!!1!", + "Woah, chill out!"). + +responds_to_shouting_numbers_test() -> + bob_responds("1, 2, 3, GO!", "Woah, chill out!"). + +responds_to_shouting_with_no_exclamation_mark_test() -> + bob_responds("I HATE YOU", "Woah, chill out!"). + +responds_to_statement_containing_question_mark_test() -> + bob_responds("Ending with ? means a question", "Whatever."). + +responds_to_silence_test() -> + bob_responds("", "Fine. Be that way!"). + +responds_to_prolonged_silence_test() -> + bob_responds(" ", "Fine. Be that way!"). + + +responds_to_non_letters_with_question_test() -> + bob_responds(":) ?", "Sure."). + +responds_to_multiple_line_questions_test() -> + bob_responds("\nDoes this cryogenic chamber make me look fat? \nno", + "Whatever."). + +%% This one is especially challenging in Erlang, hint: use the re module. + +%%responds_to_other_whitespace_test() -> +%% bob_responds("\n\r \t\v\xA0\x{2002}", +%% "Fine. Be that way!"). + +responds_to_only_numbers_test() -> + bob_responds("1, 2, 3", "Whatever."). + +responds_to_question_with_only_numbers_test() -> + bob_responds("4?", "Sure."). + +responds_to_unicode_shout_test() -> + bob_responds("\xdcML\xc4\xdcTS!", "Woah, chill out!"). + +responds_to_unicode_non_shout_test() -> + bob_responds("\xdcML\xe4\xdcTS!", "Whatever."). + +bob_responds(Question, Answer) -> + ?assertEqual(bob:response_for(Question), + Answer). diff --git a/config.json b/config.json index b2dd685d..affa251f 100644 --- a/config.json +++ b/config.json @@ -4,7 +4,19 @@ "repository": "https://github.com/exercism/xerlang", "active": false, "problems": [ - + "bob", + "word-count", + "accumulate", + "anagram", + "beer-song", + "nucleotide-count", + "rna-transcription", + "point-mutations", + "phone-number", + "etl", + "allergies", + "trinary", + "luhn" ], "deprecated": [ diff --git a/crypto-square/crypto_square_tests.erl b/crypto-square/crypto_square_tests.erl new file mode 100644 index 00000000..542c69d4 --- /dev/null +++ b/crypto-square/crypto_square_tests.erl @@ -0,0 +1,19 @@ +-module( crypto_square_tests ). +-include_lib( "eunit/include/eunit.hrl" ). + +encode1_test() -> ?assert( ["i"] =:= crypto_square:encode("I") ). + +encode2_test() -> ?assert( ["ima"] =:= crypto_square:encode("I am") ). + +encode_example1_test() -> + Plain_text = "If man was meant to stay on the ground, God would have given us roots.", + Cypher = ["imtgd","vsfea","rwerm","ayoog","oanou","uiont","nnlvt", "wttdd","esaoh","ghnss","eoau"], + ?assert( Cypher =:= crypto_square:encode(Plain_text) ). + +encode_example2_test() -> + Plain_text = "Have a nice day. Feed the dog & chill out!", + Cypher1 = "hifei", + Cypher2 = "acedl", + Cypher = crypto_square:encode( Plain_text ), + ?assert( Cypher1 =:= lists:nth(1, Cypher) ), + ?assert( Cypher2 =:= lists:nth(2, Cypher) ). diff --git a/crypto-square/example.erl b/crypto-square/example.erl new file mode 100644 index 00000000..2cc17a0b --- /dev/null +++ b/crypto-square/example.erl @@ -0,0 +1,33 @@ +-module( crypto_square ). + +-export( [encode/1] ). + +encode( String ) -> + Normalised = [X || X <- string:to_lower(String), is_letter(X)], + Length = erlang:length( Normalised ), + Square_root = math:sqrt( Length ), + Width = width( Square_root, erlang:trunc(Square_root) ), + Rows = rows( Length, Width, Normalised ), + Queue = queue:from_list( Rows ), + Transposed = first_in_each_row( queue:out(Queue) ), + rows( Length, 5, Transposed ). + + +first_in_each_row( {empty, _Q} ) -> []; +first_in_each_row( {{value, [Character | Row]}, Q} ) -> + New_q = first_in_each_row_q( Row, Q ), + [Character | first_in_each_row( queue:out(New_q) )]. + +first_in_each_row_q( [], Q ) -> Q; +first_in_each_row_q( Row, Q ) -> queue:in( Row, Q ). + +is_letter( C ) when C >= $a, C =< $z -> true; +is_letter( _C ) -> false. + +rows( Length, Width, String ) when Length > Width -> + {Row, Rest} = lists:split( Width, String ), + [Row | rows( Length - Width, Width, Rest )]; +rows( _Length, _Width, String ) -> [String]. + +width( Square_root, Trunc ) when Square_root > Trunc -> Trunc + 1; +width( _Square_root, Trunc ) -> Trunc. diff --git a/etl/etl_test.erl b/etl/etl_test.erl index d69c894f..40c9eb23 100644 --- a/etl/etl_test.erl +++ b/etl/etl_test.erl @@ -51,6 +51,6 @@ transform_full_dataset_test() -> erl_transform(Old, Expected). erl_transform(Old,New) -> - ?assertEqual(example:transform(Old), New). + ?assertEqual(etl:transform(Old), New). diff --git a/etl/etl_tests.erl b/etl/etl_tests.erl new file mode 100644 index 00000000..f838b22a --- /dev/null +++ b/etl/etl_tests.erl @@ -0,0 +1,56 @@ +-module( etl_tests ). + +-include_lib("eunit/include/eunit.hrl"). + +transform_one_value_test() -> + erl_transform([{"a", [1]}], [{1, "a"}]). + +transform_one_word_test() -> + erl_transform([{"hello", ["WORLD"]}], [{"world", "hello"}]). + +transform_more_values_test() -> + erl_transform([{"hello", ["WORLD","GSCHOOLERS"]}], [{"gschoolers", "hello"}, {"world", "hello"}]). + +transform_multiple_keys_from_one_value_test() -> + erl_transform([{"a", [1]}, {"b", [1]}], [{1, "ab"}]). + +transform_multiple_keys_from_multiple_values_test() -> + erl_transform([{"a", [1]}, {"b", [4]}], [{1, "a"}, {4, "b"}]). + +transform_more_keys_test() -> + Old = [ + {"a", ["APPLE", "ARTICHOKE"]} + ,{"b", ["BOAT", "BALLERINA"]} + ], + Expected = [ + {"apple", "a"}, + {"artichoke", "a"}, + {"ballerina", "b"}, + {"boat", "b"} + ], + erl_transform(Old, Expected). + +transform_full_dataset_test() -> + Old = [ + {1, ["A","E","I","O","U","L","N","R","S","T"]} + , {2, ["D","G"]} + , {3, ["B","C","M","P"]} + , {4, ["F","H","V","W","Y"]} + , {5, ["K"]} + , {8, ["J","X"]} + , {10, ["Q","Z"]} + ], + Expected = [ + {"a", 1}, {"b", 3}, {"c", 3}, {"d", 2}, {"e", 1} + , {"f", 4}, {"g", 2}, {"h", 4}, {"i", 1}, {"j", 8} + , {"k", 5}, {"l", 1}, {"m", 3}, {"n", 1}, {"o", 1} + , {"p", 3}, {"q", 10}, {"r", 1}, {"s", 1}, {"t", 1} + , {"u", 1}, {"v", 4}, {"w", 4}, {"x", 8}, {"y", 4} + , {"z", 10} + ], + erl_transform(Old, Expected). + +erl_transform(Old,New) -> + ?assertEqual(etl:transform(Old), New). + + diff --git a/etl/example.erl b/etl/example.erl index 9726652c..b8460288 100644 --- a/etl/example.erl +++ b/etl/example.erl @@ -1,4 +1,4 @@ --module(example). +-module(etl). -export([transform/1]). diff --git a/luhn/luhn_tests.erl b/luhn/luhn_tests.erl new file mode 100644 index 00000000..9520b715 --- /dev/null +++ b/luhn/luhn_tests.erl @@ -0,0 +1,14 @@ +-module( luhn_tests ). +-include_lib("eunit/include/eunit.hrl"). + +invalid_test() -> + ?assertNot(luhn:valid("1111")), + ?assertNot(luhn:valid("738")). + +valid_test() -> + ?assert(luhn:valid("8739567")), + ?assert(luhn:valid("8763")), + ?assert(luhn:valid("2323 2005 7766 3554")). + +create_test() -> + ?assertEqual("2323 2005 7766 3554", luhn:create("2323 2005 7766 355")). diff --git a/nucleotide-count/dna_test.erl b/nucleotide-count/dna_test.erl new file mode 100644 index 00000000..c4f39370 --- /dev/null +++ b/nucleotide-count/dna_test.erl @@ -0,0 +1,30 @@ +-module(dna_test). + +-include_lib("eunit/include/eunit.hrl"). + +empty_dna_string_has_no_adenosine_test() -> + ?assertEqual(dna:count("", "A"), 0). + +repetitive_cytidine_gets_counted_test() -> + ?assertEqual(dna:count("CCCCC", "C"), 5). + +counts_only_thymidine_test() -> + ?assertEqual(dna:count("GGGGGTAACCCGG", "T"), 1). + +dna_has_no_uracil_test() -> + ?assertEqual(dna:count("GATTACA", "U"), 0). + +validates_nucleotides_test() -> + ?assertException(error, "Invalid nucleotide", dna:count("GACT", "X")). + +empty_dna_string_has_no_nucleotides_test() -> + ?assertEqual(dna:nucleotide_counts(""), + [{"A", 0}, {"T", 0}, {"C", 0}, {"G", 0}]). + +repetitive_sequence_has_only_guanosine_test() -> + ?assertEqual(dna:nucleotide_counts("GGGGGGGG"), + [{"A", 0}, {"T", 0}, {"C", 0}, {"G", 8}]). + +counts_all_nucleotides_test() -> + ?assertEqual(dna:nucleotide_counts("AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC"), + [{"A", 20}, {"T", 21}, {"C", 12}, {"G", 17}]). diff --git a/nucleotide-count/dna_tests.erl b/nucleotide-count/dna_tests.erl index e6273ba9..90e03aaa 100644 --- a/nucleotide-count/dna_tests.erl +++ b/nucleotide-count/dna_tests.erl @@ -1,4 +1,4 @@ --module(dna_tests). +-module( dna_tests ). -include_lib("eunit/include/eunit.hrl"). diff --git a/phone-number/phone_test.erl b/phone-number/phone_test.erl new file mode 100644 index 00000000..4dbb49aa --- /dev/null +++ b/phone-number/phone_test.erl @@ -0,0 +1,29 @@ +% To run tests: +% elc *.erl +% erl -noshell -eval "eunit:test(phone, [verbose])" -s init stop +% +-module(phone_test). + +-include_lib("eunit/include/eunit.hrl"). + +cleans_number_test() -> + ?assertEqual(phone:number("(123) 456-7890"), "1234567890"). + +cleans_number_with_dots_test() -> + ?assertEqual(phone:number("123.456.7890"), "1234567890"). + +valid_when_eleven_digits_test() -> + ?assertEqual(phone:number("11234567890"), "1234567890"). + +invalid_when_eleven_digits_test() -> + ?assertEqual(phone:number("21234567890"), "0000000000"). + +invalid_when_nine_digits_test() -> + ?assertEqual(phone:number("123456789"), "0000000000"). + +area_code_test() -> + ?assertEqual(phone:areacode("1234567890"), "123"). + +pretty_print_test() -> + ?assertEqual(phone:pretty_print("1234567890"), "(123) 456-7890"), + ?assertEqual(phone:pretty_print("11234567890"), "(123) 456-7890"). diff --git a/phone-number/phone_tests.erl b/phone-number/phone_tests.erl index 3e7d9212..31d51fcf 100644 --- a/phone-number/phone_tests.erl +++ b/phone-number/phone_tests.erl @@ -2,7 +2,7 @@ % elc *.erl % erl -noshell -eval "eunit:test(phone, [verbose])" -s init stop % --module(phone_tests). +-module( phone_tests ). -include_lib("eunit/include/eunit.hrl"). diff --git a/point-mutations/dna.erl b/point-mutations/dna.erl deleted file mode 100644 index 57c5efe7..00000000 --- a/point-mutations/dna.erl +++ /dev/null @@ -1,6 +0,0 @@ --module(dna). - --export([hammingDistance/2]). - -hammingDistance(_, _) -> - 0. diff --git a/point-mutations/dna_test.erl b/point-mutations/dna_test.erl new file mode 100644 index 00000000..7d9d8362 --- /dev/null +++ b/point-mutations/dna_test.erl @@ -0,0 +1,26 @@ +-module(dna_test). + +-include_lib("eunit/include/eunit.hrl"). + + +no_difference_between_empty_strands_test() -> + ?assertEqual(0, dna:hamming_distance("", "")). + +no_difference_between_identical_strands_test() -> + ?assertEqual(0, dna:hamming_distance("GGACTGA", "GGACTGA")). + +hamming_distance_in_off_by_one_strand_test() -> + ?assertEqual(19, dna:hamming_distance("GGACGGATTCTGACCTGGACTAATTTTGGGG", + "AGGACGGATTCTGACCTGGACTAATTTTGGGG")). + +small_hamming_distance_in_middle_somewhere_test() -> + ?assertEqual(1, dna:hamming_distance("GGACG", "GGTCG")). + +langer_distance_test() -> + ?assertEqual(2 , dna:hamming_distance("ACCAGGG", "ACTATGG")). + +ignores_extra_length_on_other_strand_when_longer_test()-> + ?assertEqual(3, dna:hamming_distance("AAACTAGGGG", "AGGCTAGCGGTAGGAC")). + +ignores_extra_length_on_original_strand_when_longer_test() -> + ?assertEqual(5, dna:hamming_distance("GACTACGGACAGGGTAGGGAAT", "GACATCGCACACC")). diff --git a/point-mutations/dna_tests.erl b/point-mutations/dna_tests.erl index c8133d33..5eb8dccf 100644 --- a/point-mutations/dna_tests.erl +++ b/point-mutations/dna_tests.erl @@ -1,3 +1,26 @@ --module(dna_tests). +-module( dna_tests ). -include_lib("eunit/include/eunit.hrl"). + + +no_difference_between_empty_strands_test() -> + ?assertEqual(0, dna:hamming_distance("", "")). + +no_difference_between_identical_strands_test() -> + ?assertEqual(0, dna:hamming_distance("GGACTGA", "GGACTGA")). + +hamming_distance_in_off_by_one_strand_test() -> + ?assertEqual(19, dna:hamming_distance("GGACGGATTCTGACCTGGACTAATTTTGGGG", + "AGGACGGATTCTGACCTGGACTAATTTTGGGG")). + +small_hamming_distance_in_middle_somewhere_test() -> + ?assertEqual(1, dna:hamming_distance("GGACG", "GGTCG")). + +langer_distance_test() -> + ?assertEqual(2 , dna:hamming_distance("ACCAGGG", "ACTATGG")). + +ignores_extra_length_on_other_strand_when_longer_test()-> + ?assertEqual(3, dna:hamming_distance("AAACTAGGGG", "AGGCTAGCGGTAGGAC")). + +ignores_extra_length_on_original_strand_when_longer_test() -> + ?assertEqual(5, dna:hamming_distance("GACTACGGACAGGGTAGGGAAT", "GACATCGCACACC")). diff --git a/point-mutations/example.erl b/point-mutations/example.erl new file mode 100644 index 00000000..40bbf618 --- /dev/null +++ b/point-mutations/example.erl @@ -0,0 +1,12 @@ +-module(dna). + +-export([hamming_distance/2]). + +hamming_distance([], _) -> + 0; +hamming_distance(_, []) -> + 0; +hamming_distance([A|As], [A|Bs]) -> + hamming_distance(As, Bs); +hamming_distance([_|As], [_|Bs]) -> + 1 + hamming_distance(As, Bs). diff --git a/rna-transcription/dna_tests.erl b/rna-transcription/dna_tests.erl new file mode 100644 index 00000000..18e2105e --- /dev/null +++ b/rna-transcription/dna_tests.erl @@ -0,0 +1,20 @@ +-module( dna_tests ). +-include_lib("eunit/include/eunit.hrl"). + +transcribes_cytidine_unchanged_test() -> + ?assertEqual("C", dna:to_rna("C")). + +transcribes_guanosine_unchanged_test() -> + ?assertEqual("G", dna:to_rna("G")). + +transcribes_adenosine_unchanged_test() -> + ?assertEqual("A", dna:to_rna("A")). + +transcribes_thymidine_to_uracil_test() -> + ?assertEqual("U", dna:to_rna("T")). + +transcribes_all_occurences_test() -> + ?assertEqual( + "ACGUGGUCUUAA", + dna:to_rna("ACGTGGTCTTAA") + ). diff --git a/trinary/example_tests.erl b/trinary/example_tests.erl new file mode 100644 index 00000000..3337a398 --- /dev/null +++ b/trinary/example_tests.erl @@ -0,0 +1,34 @@ +-module( example_tests ). + +-include_lib("eunit/include/eunit.hrl"). + +trinary_1_is_decimal_1_test() -> + ?assertEqual(1, example:to_decimal("1")). + +trinary_2_is_decimal_2_test() -> + ?assertEqual(2, example:to_decimal("2")). + +trinary_10_is_decimal_3_test() -> + ?assertEqual(3, example:to_decimal("10")). + +trinary_11_is_decimal_4_test() -> + ?assertEqual(4, example:to_decimal("11")). + +trinary_100_is_decimal_9_test() -> + ?assertEqual(9, example:to_decimal("100")). + +trinary_112_is_decimal_14_test() -> + ?assertEqual(14, example:to_decimal("112")). + +trinary_222_is_decimal_26_test() -> + ?assertEqual(26, example:to_decimal("222")). + +trinary_1120_is_decimal_42_test() -> + ?assertEqual(42, example:to_decimal("1120")). + +trinary_1122000120_is_decimal_32091_test() -> + ?assertEqual(32091, example:to_decimal("1122000120")). + +invalid_trinary_is_decimal_0_test() -> + ?assertEqual(0, example:to_decimal("carrot")). + diff --git a/trinary/trinary_test.erl b/trinary/trinary_test.erl new file mode 100644 index 00000000..9a1c6c81 --- /dev/null +++ b/trinary/trinary_test.erl @@ -0,0 +1,34 @@ +-module(trinary_test). +-import(example, [to_decimal/1]). +-include_lib("eunit/include/eunit.hrl"). + +trinary_1_is_decimal_1_test() -> + ?assertEqual(1, example:to_decimal("1")). + +trinary_2_is_decimal_2_test() -> + ?assertEqual(2, example:to_decimal("2")). + +trinary_10_is_decimal_3_test() -> + ?assertEqual(3, example:to_decimal("10")). + +trinary_11_is_decimal_4_test() -> + ?assertEqual(4, example:to_decimal("11")). + +trinary_100_is_decimal_9_test() -> + ?assertEqual(9, example:to_decimal("100")). + +trinary_112_is_decimal_14_test() -> + ?assertEqual(14, example:to_decimal("112")). + +trinary_222_is_decimal_26_test() -> + ?assertEqual(26, example:to_decimal("222")). + +trinary_1120_is_decimal_42_test() -> + ?assertEqual(42, example:to_decimal("1120")). + +trinary_1122000120_is_decimal_32091_test() -> + ?assertEqual(32091, example:to_decimal("1122000120")). + +invalid_trinary_is_decimal_0_test() -> + ?assertEqual(0, example:to_decimal("carrot")). + diff --git a/trinary/trinary_tests.erl b/trinary/trinary_tests.erl deleted file mode 100644 index ba27ab42..00000000 --- a/trinary/trinary_tests.erl +++ /dev/null @@ -1,34 +0,0 @@ --module(trinary_tests). --import(example, [to_decimal/1]). --include_lib("eunit/include/eunit.hrl"). - -trinary_1_is_decimal_1_test() -> - ?assertEqual(1, example:to_decimal("1")). - -%% trinary_2_is_decimal_2_test() -> -%% ?assertEqual(2, example:to_decimal("2")). - -%% trinary_10_is_decimal_3_test() -> -%% ?assertEqual(3, example:to_decimal("10")). - -%% trinary_11_is_decimal_4_test() -> -%% ?assertEqual(4, example:to_decimal("11")). - -%% trinary_100_is_decimal_9_test() -> -%% ?assertEqual(9, example:to_decimal("100")). - -%% trinary_112_is_decimal_14_test() -> -%% ?assertEqual(14, example:to_decimal("112")). - -%% trinary_222_is_decimal_26_test() -> -%% ?assertEqual(26, example:to_decimal("222")). - -%% trinary_1120_is_decimal_42_test() -> -%% ?assertEqual(42, example:to_decimal("1120")). - -%% trinary_1122000120_is_decimal_32091_test() -> -%% ?assertEqual(32091, example:to_decimal("1122000120")). - -%% invalid_trinary_is_decimal_0_test() -> -%% ?assertEqual(0, example:to_decimal("carrot")). - diff --git a/word-count/word_count_tests.erl b/word-count/word_count_tests.erl new file mode 100644 index 00000000..73fd98c3 --- /dev/null +++ b/word-count/word_count_tests.erl @@ -0,0 +1,66 @@ +-module( word_count_tests ). +-include_lib("eunit/include/eunit.hrl"). + +%% dict should be used to implement wound_count:count/1. + +count_one_word_test() -> + assert_count( + "word", + [{"word", 1}]). + +count_one_of_each_test() -> + assert_count( + "one of each", + [{"one", 1}, + {"of", 1}, + {"each", 1}]). + +count_multiple_occurrences_test() -> + assert_count( + "one fish two fish red fish blue fish", + [{"one", 1}, + {"two", 1}, + {"fish", 4}, + {"red", 1}, + {"blue", 1}]). + +ignore_punctuation_test() -> + assert_count( + "car : carpet as java : javascript!!&@$%^&", + [{"car", 1}, + {"carpet", 1}, + {"as", 1}, + {"java", 1}, + {"javascript", 1}]). + +include_numbers_test() -> + assert_count( + "testing, 1, 2 testing", + [{"testing", 2}, + {"1", 1}, + {"2", 1}]). + +normalize_case_test() -> + assert_count( + "go Go GO", + [{"go", 3}]). + +prefix_punctuation_test() -> + assert_count( + "!%%#testing, 1, 2 testing", + [{"testing", 2}, + {"1", 1}, + {"2", 1}]). + +symbols_are_separators_test() -> + assert_count( + "hey,my_spacebar_is_broken.", + [{"hey", 1}, + {"my", 1}, + {"spacebar", 1}, + {"is", 1}, + {"broken", 1}]). + +assert_count(S, Expect) -> + ?assertEqual(orddict:from_list(dict:to_list(word_count:count(S))), + orddict:from_list(Expect)).