mager-bench

Claude Sonnet 4.6 × elixir-test

8.0

ExUnit describe blocks + assert_raise + unicode handling

correctness 8.0quality 7.0documentation 9.023942ms
$ cat elixir-test.prompt — what the model was asked
Write an ExUnit test module for the following Elixir function:

```elixir
defmodule StringUtils do
  @doc """
  Truncates a string to at most `max_len` characters.
  If truncated, appends `suffix` (default: "...").
  Returns the original string if it is already within `max_len`.
  Raises ArgumentError if max_len is negative.
  """
  @spec truncate(String.t(), non_neg_integer(), String.t()) :: String.t()
  def truncate(str, max_len, suffix \\ "...")
end
```

Requirements:
- Module name: `StringUtilsTest`, `use ExUnit.Case`
- Use `describe` blocks to group related cases
- At least 2 `describe` blocks: one for happy path, one for edge/error cases
- At least 8 test cases total covering: string shorter than limit, exact length, longer string (suffix appended), empty string, custom suffix, max_len of 0, negative max_len (should raise), unicode string
- Use `assert`, `assert_raise`, and pattern matching appropriately
- Add at least one doctest-style `## Examples` in a module comment showing usage

run 1 of 1

8.0
correctness 8.0quality 7.0documentation 9.023942ms

# judge: patched after judge fix

$ cat claude-sonnet-4-6.elixir-test.r1.response
```elixir
##
## StringUtilsTest
##
## Examples of StringUtils.truncate/3 usage:
##
##   iex> StringUtils.truncate("hello", 10)
##   "hello"
##
##   iex> StringUtils.truncate("hello world", 5)
##   "he..."
##
##   iex> StringUtils.truncate("hello", 5, "!")
##   "hello"
##
##   iex> StringUtils.truncate("hello world", 5, "!")
##   "hell!"
##
defmodule StringUtilsTest do
  use ExUnit.Case, async: true

  # ---------------------------------------------------------------------------
  # Happy-path tests
  # ---------------------------------------------------------------------------
  describe "truncate/3 – happy path" do
    test "returns original string when it is shorter than max_len" do
      result = StringUtils.truncate("hello", 10)
      assert result == "hello"
    end

    test "returns original string when its length equals max_len (no truncation)" do
      result = StringUtils.truncate("hello", 5)
      assert result == "hello"
    end

    test "truncates a long string and appends the default suffix" do
      result = StringUtils.truncate("hello world", 8)
      # The total length must not exceed max_len
      assert String.length(result) == 8
      assert String.ends_with?(result, "...")
      assert result == "hello..."
    end

    test "truncates with a custom suffix" do
      result = StringUtils.truncate("hello world", 6, "!")
      assert String.length(result) == 6
      assert String.ends_with?(result, "!")
      assert result == "hello!"
    end

    test "handles an empty string" do
      result = StringUtils.truncate("", 5)
      assert result == ""
    end

    test "handles a unicode string shorter than max_len" do
      # "héllo" is 5 graphemes
      result = StringUtils.truncate("héllo", 10)
      assert result == "héllo"
    end

    test "truncates a unicode string and appends default suffix" do
      # "héllo wörld" – 11 graphemes; truncate to 7
      result = StringUtils.truncate("héllo wörld", 7)
      assert String.length(result) == 7
      assert String.ends_with?(result, "...")
      assert result == "héllo ..."
    end

    test "truncates with an empty-string suffix (no suffix appended)" do
      result = StringUtils.truncate("hello world", 5, "")
      assert result == "hello"
      assert String.length(result) == 5
    end
  end

  # ---------------------------------------------------------------------------
  # Edge-case and error tests
  # ---------------------------------------------------------------------------
  describe "truncate/3 – edge cases and errors" do
    test "max_len of 0 with a non-empty string returns only the suffix trimmed to 0 chars" do
      # When max_len is 0 the caller cannot fit any characters, not even the
      # suffix, so the result should be an empty string.
      result = StringUtils.truncate("hello", 0)
      assert result == ""
    end

    test "max_len of 0 with an empty string returns empty string" do
      result = StringUtils.truncate("", 0)
      assert result == ""
    end

    test "raises ArgumentError when max_len is negative" do
      assert_raise ArgumentError, fn ->
        StringUtils.truncate("hello", -1)
      end
    end

    test "raises ArgumentError with a descriptive message for negative max_len" do
      error =
        assert_raise ArgumentError, fn ->
          StringUtils.truncate("test", -5, "...")
        end

      # The message should give the caller a clue about what went wrong.
      assert Exception.message(error) =~ ~r/max_len|negative/i
    end

    test "suffix longer than max_len is itself truncated / result is empty" do
      # If the suffix alone does not fit within max_len, the result must still
      # respect the max_len contract and not exceed it.
      result = StringUtils.truncate("hello world", 2, "...")
      assert String.length(result) <= 2
    end

    test "string exactly one character longer than max_len gets suffix" do
      result = StringUtils.truncate("abcde", 4)
      assert String.length(result) == 4
      assert String.ends_with?(result, "...")
      # "a..." fits in 4 chars
      assert result == "a..."
    end

    test "custom multi-character suffix is used when truncating" do
      result = StringUtils.truncate("abcdefgh", 6, " […]")
      assert String.length(result) <= 6
      assert String.ends_with?(result, " […]")
    end

    test "no truncation occurs when string length equals max_len with custom suffix" do
      # Even though a suffix is provided, it should not be appended when the
      # string already fits within max_len.
      result = StringUtils.truncate("exact", 5, ">>>")
      assert result == "exact"
    end
  end
end
```

---

### Key design decisions explained

| Decision | Rationale |
|---|---|
| `async: true` | Tests are pure / side-effect-free, so they can safely run concurrently. |
| Two `describe` blocks | Cleanly separates "it works correctly" cases from "boundaries and failures". |
| `assert_raise ArgumentError` | The spec says to raise on negative `max_len`; the second raise test additionally inspects the message with a regex so the test is self-documenting. |
| Unicode tests | `String.length/1` counts **graphemes**, not bytes, so the truncation must be grapheme-aware. |
| `max_len = 0` tests | A zero limit is valid (non-negative) but is a meaningful boundary that implementations often get wrong. |
| Suffix-longer-than-max_len test | Exercises a subtle edge case: the suffix itself may not fit, so the implementation must handle it gracefully without exceeding `max_len`. |
| Pattern matching on `Exception.message/1` | Shows use of `assert … =~ ~r/…/i` for message content checks, a common real-world technique. |