defmodule CMDCEval.Case do
@moduledoc """
单个评测用例 struct。
Suite 实现的 `cases/0` 返回 `[Case.t()]` 列表,Runner 按 case 并发跑。
## 字段
- `:id` —— case 唯一标识(在 Suite 内 unique)
- `:input` —— 用户 prompt 字符串
- `:expected` —— 期望结果 spec(map / 字符串 / 函数),由 Suite 的 `assert/2` 解释
- `:tools` —— 该 case 启用的工具模块列表(覆盖 Suite 默认)
- `:metadata` —— 附加 metadata(如 `:category`, `:difficulty`)
- `:timeout_ms` —— 单 case 超时(nil 表示用 Runner 默认)
"""
@derive Jason.Encoder
defstruct [
:id,
:input,
:expected,
:tools,
:timeout_ms,
metadata: %{}
]
@type t :: %__MODULE__{
id: String.t(),
input: String.t(),
expected: term(),
tools: [module()] | nil,
timeout_ms: pos_integer() | nil,
metadata: map()
}
@doc """
构造一个 Case struct(基础校验 + 默认值)。
## 示例
Case.new(id: "sum_basic", input: "1 + 1 = ?", expected: ~r/2/)
"""
@spec new(keyword()) :: t()
def new(opts) do
id = Keyword.fetch!(opts, :id)
input = Keyword.fetch!(opts, :input)
expected = Keyword.get(opts, :expected)
%__MODULE__{
id: to_string(id),
input: to_string(input),
expected: expected,
tools: Keyword.get(opts, :tools),
timeout_ms: Keyword.get(opts, :timeout_ms),
metadata: Keyword.get(opts, :metadata, %{})
}
end
end