diff --git a/lib/elixir_analyzer/constants.ex b/lib/elixir_analyzer/constants.ex index 19247b35..5496a545 100644 --- a/lib/elixir_analyzer/constants.ex +++ b/lib/elixir_analyzer/constants.ex @@ -76,7 +76,7 @@ defmodule ElixirAnalyzer.Constants do captains_log_do_not_use_enum_random: "elixir.captains-log.do_not_use_enum_random", captains_log_do_not_use_rand_uniform_real: "elixir.captains-log.do_not_use_rand_uniform_real", captains_log_use_rand_uniform: "elixir.captains-log.use_rand_uniform", - captains_log_use_io_lib: "elixir.captains-log.use_io_lib", + captains_log_use_erlang: "elixir.captains-log.use_erlang", # Community Garden Comments community_garden_use_get_and_update: "elixir.community-garden.use_get_and_update", diff --git a/lib/elixir_analyzer/test_suite/captains_log.ex b/lib/elixir_analyzer/test_suite/captains_log.ex index 05a1256e..e21b6d91 100644 --- a/lib/elixir_analyzer/test_suite/captains_log.ex +++ b/lib/elixir_analyzer/test_suite/captains_log.ex @@ -4,6 +4,7 @@ defmodule ElixirAnalyzer.TestSuite.CaptainsLog do """ use ElixirAnalyzer.ExerciseTest alias ElixirAnalyzer.Constants + alias ElixirAnalyzer.Source assert_call "random_planet_class uses Enum.random" do type :essential @@ -43,10 +44,30 @@ defmodule ElixirAnalyzer.TestSuite.CaptainsLog do suppress_if "random_stardate does not use Enum.random", :fail end - assert_call "format_stardate uses :io_lib" do + + check_source "format_stardate uses erlang" do type :essential - calling_fn module: CaptainsLog, name: :format_stardate - called_fn module: :io_lib, name: :_ - comment Constants.captains_log_use_io_lib() + comment Constants.captains_log_use_erlang() + + check(%Source{code_ast: code_ast}) do + {_, erlang?} = + Macro.prewalk(code_ast, false, fn node, acc -> + case node do + # usage :io_lib.format/2 + {{:., _, [:io_lib, :format]}, _, _} -> + {node, true} + + # usage :erlang.function_name/arity + # matches any function call from :erlang module + {{:., _, [:erlang, _]}, _, _} -> + {node, true} + + _ -> + {node, acc} + end + end) + + erlang? + end end end diff --git a/test/elixir_analyzer/test_suite/captains_log_test.exs b/test/elixir_analyzer/test_suite/captains_log_test.exs index b3b783fd..fb07b638 100644 --- a/test/elixir_analyzer/test_suite/captains_log_test.exs +++ b/test/elixir_analyzer/test_suite/captains_log_test.exs @@ -98,7 +98,7 @@ defmodule ElixirAnalyzer.ExerciseTest.CaptainsLogTest do end test_exercise_analysis "format_stardate uses Float.round", - comments_include: [Constants.captains_log_use_io_lib()] do + comments_include: [Constants.captains_log_use_erlang()] do defmodule CaptainsLog do def format_stardate(stardate) do if is_float(stardate) do diff --git a/test_data/captains-log/no_erlang_solution/.meta/config.json b/test_data/captains-log/no_erlang_solution/.meta/config.json new file mode 100644 index 00000000..d279010d --- /dev/null +++ b/test_data/captains-log/no_erlang_solution/.meta/config.json @@ -0,0 +1,20 @@ +{ + "authors": [ + "angelikatyborska" + ], + "contributors": [ + "neenjaw" + ], + "files": { + "solution": [ + "lib/captains_log.ex" + ], + "test": [ + "test/captains_log_test.exs" + ], + "exemplar": [ + ".meta/exemplar.ex" + ] + }, + "blurb": "Learn about randomness and using Erlang libraries from Elixir by helping Mary generate stardates and starship registry numbers for her Star Trek themed pen-and-paper role playing sessions." +} \ No newline at end of file diff --git a/test_data/captains-log/no_erlang_solution/.meta/exemplar.ex b/test_data/captains-log/no_erlang_solution/.meta/exemplar.ex new file mode 100644 index 00000000..faaff587 --- /dev/null +++ b/test_data/captains-log/no_erlang_solution/.meta/exemplar.ex @@ -0,0 +1,20 @@ +defmodule CaptainsLog do + @planetary_classes ["D", "H", "J", "K", "L", "M", "N", "R", "T", "Y"] + + def random_planet_class() do + Enum.random(@planetary_classes) + end + + def random_ship_registry_number() do + number = Enum.random(1000..9999) + "NCC-#{number}" + end + + def random_stardate() do + :rand.uniform() * 1000 + 41_000 + end + + def format_stardate(stardate) do + to_string(:io_lib.format("~.1f", [stardate])) + end +end diff --git a/test_data/captains-log/no_erlang_solution/expected_analysis.json b/test_data/captains-log/no_erlang_solution/expected_analysis.json new file mode 100644 index 00000000..b8b95c54 --- /dev/null +++ b/test_data/captains-log/no_erlang_solution/expected_analysis.json @@ -0,0 +1 @@ +{"summary":"Check the comments for things to fix. 🛠","comments":[{"type":"essential","comment":"elixir.captains-log.use_erlang"},{"type":"informative","params":{"mentoring_request_url":"https://exercism.org/tracks/elixir/exercises/captains-log/mentor_discussions"},"comment":"elixir.general.feedback_request"}]} \ No newline at end of file diff --git a/test_data/captains-log/no_erlang_solution/lib/captains_log.ex b/test_data/captains-log/no_erlang_solution/lib/captains_log.ex new file mode 100644 index 00000000..4666af3a --- /dev/null +++ b/test_data/captains-log/no_erlang_solution/lib/captains_log.ex @@ -0,0 +1,20 @@ +defmodule CaptainsLog do + @planetary_classes ["D", "H", "J", "K", "L", "M", "N", "R", "T", "Y"] + + def random_planet_class() do + Enum.random(@planetary_classes) + end + + def random_ship_registry_number() do + number = Enum.random(1000..9999) + "NCC-#{number}" + end + + def random_stardate() do + :rand.uniform() * 1000 + 41_000 + end + + def format_stardate(stardate) do + Float.round(stardate, 1) |> to_string() + end +end diff --git a/test_data/captains-log/perfect_solution/.meta/config.json b/test_data/captains-log/perfect_solution/.meta/config.json new file mode 100644 index 00000000..d279010d --- /dev/null +++ b/test_data/captains-log/perfect_solution/.meta/config.json @@ -0,0 +1,20 @@ +{ + "authors": [ + "angelikatyborska" + ], + "contributors": [ + "neenjaw" + ], + "files": { + "solution": [ + "lib/captains_log.ex" + ], + "test": [ + "test/captains_log_test.exs" + ], + "exemplar": [ + ".meta/exemplar.ex" + ] + }, + "blurb": "Learn about randomness and using Erlang libraries from Elixir by helping Mary generate stardates and starship registry numbers for her Star Trek themed pen-and-paper role playing sessions." +} \ No newline at end of file diff --git a/test_data/captains-log/perfect_solution/.meta/exemplar.ex b/test_data/captains-log/perfect_solution/.meta/exemplar.ex new file mode 100644 index 00000000..faaff587 --- /dev/null +++ b/test_data/captains-log/perfect_solution/.meta/exemplar.ex @@ -0,0 +1,20 @@ +defmodule CaptainsLog do + @planetary_classes ["D", "H", "J", "K", "L", "M", "N", "R", "T", "Y"] + + def random_planet_class() do + Enum.random(@planetary_classes) + end + + def random_ship_registry_number() do + number = Enum.random(1000..9999) + "NCC-#{number}" + end + + def random_stardate() do + :rand.uniform() * 1000 + 41_000 + end + + def format_stardate(stardate) do + to_string(:io_lib.format("~.1f", [stardate])) + end +end diff --git a/test_data/captains-log/perfect_solution/expected_analysis.json b/test_data/captains-log/perfect_solution/expected_analysis.json new file mode 100644 index 00000000..9dfbf803 --- /dev/null +++ b/test_data/captains-log/perfect_solution/expected_analysis.json @@ -0,0 +1 @@ +{"comments":[],"summary":"Submission analyzed. No automated suggestions found."} diff --git a/test_data/captains-log/perfect_solution/lib/captains_log.ex b/test_data/captains-log/perfect_solution/lib/captains_log.ex new file mode 100644 index 00000000..86678ca8 --- /dev/null +++ b/test_data/captains-log/perfect_solution/lib/captains_log.ex @@ -0,0 +1,20 @@ +defmodule CaptainsLog do + @planetary_classes ["D", "H", "J", "K", "L", "M", "N", "R", "T", "Y"] + + def random_planet_class() do + Enum.random(@planetary_classes) + end + + def random_ship_registry_number() do + number = Enum.random(1000..9999) + "NCC-#{number}" + end + + def random_stardate() do + :rand.uniform() * 1000 + 41_000 + end + + def format_stardate(stardate) do + :io_lib.format("~.1f", [stardate]) |> to_string() + end +end