Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
45 changes: 44 additions & 1 deletion lib/cadet/assessments/library.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ defmodule Cadet.Assessments.Library do
@primary_key false
embedded_schema do
field(:chapter, :integer, default: 1)
field(:variant, :string, default: nil)
field(:exec_time_ms, :integer, default: 1000)
field(:globals, :map, default: %{})
embeds_one(:external, ExternalLibrary, on_replace: :update)
end

@required_fields ~w(chapter)a
@optional_fields ~w(globals)a
@optional_fields ~w(globals variant exec_time_ms)a
@required_embeds ~w(external)a

def changeset(library, params \\ %{}) do
Expand All @@ -24,6 +26,8 @@ defmodule Cadet.Assessments.Library do
|> put_default_external()
|> validate_required(@required_fields ++ @required_embeds)
|> validate_globals()
|> validate_chapter()
|> validate_chapter_variant()
end

defp validate_globals(changeset) do
Expand All @@ -40,6 +44,45 @@ defmodule Cadet.Assessments.Library do
end
end

defp validate_chapter(changeset) do
case changeset |> fetch_change(:chapter) do
{:ok, c} when c in 1..4 -> changeset
:error -> changeset
_ -> add_error(changeset, :chapter, "invalid chapter")
end
end

@valid_chapter_variants [
{1, "wasm"},
{1, "lazy"},
{2, "lazy"},
{3, "concurrent"},
{3, "non-det"},
{4, "gpu"}
]

defp validate_chapter_variant(changeset) do
chapter = changeset |> fetch_field(:chapter)
variant = changeset |> fetch_field(:variant)

case {chapter, variant} do
# no changes
{{:data, _}, {:data, _}} ->
changeset

# default variant
{{_, _c}, {_, v}} when is_nil(v) or v == "default" ->
changeset

{{_, chapter}, {_, variant}} ->
if {chapter, variant} in @valid_chapter_variants do
changeset
else
add_error(changeset, :variant, "invalid variant for given chapter")
end
end
end

def put_default_external(changeset) do
external = get_change(changeset, :external)

Expand Down
4 changes: 3 additions & 1 deletion lib/cadet/jobs/xml_parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,9 @@ defmodule Cadet.Updater.XMLParser do
library_entity
|> xpath(
~x"."e,
chapter: ~x"./@interpreter"i
chapter: ~x"./@interpreter"i,
exec_time_ms: ~x"./@exectime"oi,
variant: ~x"./@variant"os
)
|> Map.put(:globals, globals)
|> Map.put(:external, external)
Expand Down
2 changes: 2 additions & 0 deletions lib/cadet_web/views/assessments_helpers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ defmodule CadetWeb.AssessmentsHelpers do
defp build_library(%{library: library}) do
transform_map_for_view(library, %{
chapter: :chapter,
variant: :variant,
execTimeMs: :exec_time_ms,
globals: :globals,
external: &build_external_library(%{external_library: &1.external})
})
Expand Down
59 changes: 59 additions & 0 deletions test/cadet/assessments/library_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,65 @@ defmodule Cadet.Assessments.LibraryTest do
end
end

test "invalid changeset invalid chapter", %{valid_params: params} do
params
|> Map.put(:chapter, 100)
|> assert_changeset(:invalid)

params
|> Map.put(:chapter, 0)
|> assert_changeset(:invalid)
end

test "valid changeset valid chapter-variant", %{valid_params: params} do
variants = [
{1, "default"},
{1, "wasm"},
{1, "lazy"},
{2, "default"},
{2, "lazy"},
{3, "default"},
{3, "concurrent"},
{3, "non-det"},
{4, "default"},
{4, "gpu"}
]

for {c, v} <- variants do
params
|> Map.merge(%{chapter: c, variant: v})
|> assert_changeset(:valid)
end

# no variant
params
|> Map.merge(%{chapter: 1})
|> assert_changeset(:valid)
end

test "valid changeset invalid chapter-variant", %{valid_params: params} do
variants = [
{1, "hello"},
{1, "concurrent"},
{1, "non-det"},
{2, "undefault"},
{2, "eager"},
{3, "concurren"},
{4, "geforce rtx 3080"}
]

for {c, v} <- variants do
params
|> Map.merge(%{chapter: c, variant: v})
|> assert_changeset(:invalid)
end
end

test "invalid changeset empty" do
refute (%Library{chapter: nil}
|> Library.changeset(%{})).valid?
end

test "valid changeset without globals", %{valid_params: params} do
params
|> Map.delete(:globals)
Expand Down
24 changes: 18 additions & 6 deletions test/cadet_web/admin_controllers/admin_grading_controller_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,9 @@ defmodule CadetWeb.AdminGradingControllerTest do
"external" => %{
"name" => "#{&1.question.library.external.name}",
"symbols" => &1.question.library.external.symbols
}
},
"execTimeMs" => &1.question.library.exec_time_ms,
"variant" => &1.question.library.variant
},
"maxXp" => &1.question.max_xp,
"content" => &1.question.question.content,
Expand Down Expand Up @@ -305,7 +307,9 @@ defmodule CadetWeb.AdminGradingControllerTest do
"external" => %{
"name" => "#{&1.question.library.external.name}",
"symbols" => &1.question.library.external.symbols
}
},
"execTimeMs" => &1.question.library.exec_time_ms,
"variant" => &1.question.library.variant
},
"maxXp" => &1.question.max_xp,
"content" => &1.question.question.content,
Expand Down Expand Up @@ -352,7 +356,9 @@ defmodule CadetWeb.AdminGradingControllerTest do
"external" => %{
"name" => "#{&1.question.library.external.name}",
"symbols" => &1.question.library.external.symbols
}
},
"execTimeMs" => &1.question.library.exec_time_ms,
"variant" => &1.question.library.variant
},
"maxXp" => &1.question.max_xp,
"content" => &1.question.question.content,
Expand Down Expand Up @@ -902,7 +908,9 @@ defmodule CadetWeb.AdminGradingControllerTest do
"external" => %{
"name" => "#{&1.question.library.external.name}",
"symbols" => &1.question.library.external.symbols
}
},
"execTimeMs" => &1.question.library.exec_time_ms,
"variant" => &1.question.library.variant
},
"maxXp" => &1.question.max_xp,
"content" => &1.question.question.content,
Expand Down Expand Up @@ -939,7 +947,9 @@ defmodule CadetWeb.AdminGradingControllerTest do
"external" => %{
"name" => "#{&1.question.library.external.name}",
"symbols" => &1.question.library.external.symbols
}
},
"execTimeMs" => &1.question.library.exec_time_ms,
"variant" => &1.question.library.variant
},
"content" => &1.question.question.content,
"answer" => &1.answer.choice_id,
Expand Down Expand Up @@ -986,7 +996,9 @@ defmodule CadetWeb.AdminGradingControllerTest do
"external" => %{
"name" => "#{&1.question.library.external.name}",
"symbols" => &1.question.library.external.symbols
}
},
"execTimeMs" => &1.question.library.exec_time_ms,
"variant" => &1.question.library.variant
},
"maxXp" => &1.question.max_xp,
"content" => &1.question.question.content,
Expand Down
2 changes: 1 addition & 1 deletion test/factories/assessments/library_factory.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ defmodule Cadet.Assessments.LibraryFactory do

def library_factory do
%{
chapter: Enum.random(1..20),
chapter: Enum.random(1..4),
globals:
Enum.reduce(
0..5,
Expand Down