Skip to content

Commit

Permalink
Add analyzer for community-garden (#411)
Browse files Browse the repository at this point in the history
* Add analyzer for community-garden

* Update lib/elixir_analyzer/test_suite/community_garden.ex

Co-authored-by: Jie <[email protected]>

---------

Co-authored-by: Jie <[email protected]>
  • Loading branch information
angelikatyborska and jiegillet authored Nov 21, 2023
1 parent 9170069 commit f1c76d0
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 0 deletions.
3 changes: 3 additions & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ config :elixir_analyzer,
"chessboard" => %{
analyzer_module: ElixirAnalyzer.TestSuite.Chessboard
},
"community-garden" => %{
analyzer_module: ElixirAnalyzer.TestSuite.CommunityGarden
},
"dancing-dots" => %{
analyzer_module: ElixirAnalyzer.TestSuite.DancingDots
},
Expand Down
3 changes: 3 additions & 0 deletions lib/elixir_analyzer/constants.ex
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ defmodule ElixirAnalyzer.Constants do
captains_log_use_rand_uniform: "elixir.captains-log.use_rand_uniform",
captains_log_use_io_lib: "elixir.captains-log.use_io_lib",

# Community Garden Comments
community_garden_use_get_and_update: "elixir.community-garden.use_get_and_update",

# Dancing Dots Comments
dancing_dots_annotate_impl_animation: "elixir.dancing-dots.annotate_impl_animation",
dancing_dots_do_not_reimplement_init: "elixir.dancing-dots.do_not_reimplement_init",
Expand Down
14 changes: 14 additions & 0 deletions lib/elixir_analyzer/test_suite/community_garden.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
defmodule ElixirAnalyzer.TestSuite.CommunityGarden do
@moduledoc """
This is an exercise analyzer extension module for the concept exercise Community Garden
"""
use ElixirAnalyzer.ExerciseTest
alias ElixirAnalyzer.Constants

assert_call "register uses Agent.get_and_update" do
type :essential
calling_fn module: CommunityGarden, name: :register
called_fn module: Agent, name: :get_and_update
comment Constants.community_garden_use_get_and_update()
end
end
143 changes: 143 additions & 0 deletions test/elixir_analyzer/test_suite/community_garden_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
defmodule ElixirAnalyzer.ExerciseTest.CommunityGardenTest do
use ElixirAnalyzer.ExerciseTestCase,
exercise_test_module: ElixirAnalyzer.TestSuite.CommunityGarden

alias ElixirAnalyzer.Constants

test_exercise_analysis "example solution",
comments: [Constants.solution_same_as_exemplar()] do
~S"""
defmodule Plot do
@enforce_keys [:plot_id, :registered_to]
defstruct [:plot_id, :registered_to]
end
defmodule CommunityGarden do
def start(opts \\ []) do
Agent.start(fn -> %{registry: %{}, next_id: 1} end, opts)
end
def list_registrations(pid) do
Agent.get(pid, fn state ->
Map.values(state.registry)
end)
end
def register(pid, register_to) do
Agent.get_and_update(pid, fn %{registry: registry, next_id: next_id} = state ->
new_plot = %Plot{plot_id: next_id, registered_to: register_to}
updated = Map.put(registry, next_id, new_plot)
{new_plot, %{state | registry: updated, next_id: next_id + 1}}
end)
end
def release(pid, plot_id) do
Agent.update(pid, fn %{registry: registry} = state ->
updated = Map.delete(registry, plot_id)
%{state | registry: updated}
end)
end
def get_registration(pid, plot_id) do
registration =
Agent.get(pid, fn state ->
state.registry[plot_id]
end)
case registration do
nil -> {:not_found, "plot is unregistered"}
_ -> registration
end
end
end
"""
end

test_exercise_analysis "other reasonable solutions",
comments: [] do
[
defmodule CommunityGarden do
def start() do
Agent.start(fn -> %{plots: [], id: 0} end)
end

def list_registrations(pid) do
Agent.get(pid, fn %{plots: plots} -> plots end)
end

def register(pid, register_to) do
Agent.get_and_update(pid, fn %{plots: plots, id: id} ->
id = id + 1

{%Plot{plot_id: id, registered_to: register_to},
%{plots: [%Plot{plot_id: id, registered_to: register_to} | plots], id: id}}
end)
end

def release(pid, plot_id) do
Agent.cast(pid, fn %{plots: plots} = n ->
plots = Enum.filter(plots, fn %{plot_id: x} -> x != plot_id end)
%{n | plots: plots}
end)
end

def get_registration(pid, plot_id) do
case Enum.find(list_registrations(pid), fn _ -> plot_id end) do
nil -> {:not_found, "plot is unregistered"}
n -> n
end
end
end,
defmodule CommunityGarden do
def start() do
Agent.start(fn -> %{plots: [], index: 0} end)
end

def list_registrations(pid) do
Agent.get(pid, fn %{plots: plots} -> plots end)
end

def register(pid, register_to) do
Agent.get_and_update(pid, fn %{plots: plots, index: index} ->
index = index + 1
plot = %Plot{plot_id: index, registered_to: register_to}
{plot, %{plots: [plot | plots], index: index}}
end)
end

def release(pid, plot_id) do
Agent.cast(pid, fn %{plots: plots} = status ->
plots = Enum.filter(plots, fn %{plot_id: p} -> p !== plot_id end)
%{status | plots: plots}
end)
end

def get_registration(pid, plot_id) do
Agent.get(pid, fn %{plots: plots} ->
plots
|> Enum.find(
{:not_found, "plot is unregistered"},
fn %{plot_id: p} -> p === plot_id end
)
end)
end
end
]
end

test_exercise_analysis "expects register to use Agent.get_and_update",
comments_include: [Constants.community_garden_use_get_and_update()] do
defmodule CommunityGarden do
def register(pid, register_to) do
state = Agent.get(pid, fn state -> state end)
%{registry: registry, next_id: next_id} = state
new_plot = %Plot{plot_id: next_id, registered_to: register_to}
updated = Map.put(registry, next_id, new_plot)
state = %{state | registry: updated, next_id: next_id + 1}
Agent.update(pid, fn x -> state end)

new_plot
end
end
end
end

0 comments on commit f1c76d0

Please sign in to comment.