Unexpected value from Ash.Generator.changeset_generator for required string attributes

I’m in the process of learning Elixir + Ash and I hit a scenario that is confusing me. In short, I’m getting a value of "?⃞" if I don’t provide a required string attribute when I use Ash.Generator.changeset_generator/3 to create a resource record.

After more research and testing I realized that I’m definitely abusing how generators are intended to be used, so this is more of a knowledge question than a bug report.

Here’s the resource I created:

defmodule TestApp.Groups.Group do
  use Ash.Resource, domain: TestApp.Groups, data_layer: Ash.DataLayer.Ets

  actions do
    defaults [:read]

    create :create do
      accept [:name]
      validate present([:name])
    end
  end

  attributes do
    uuid_v7_primary_key :id

    attribute :name, :string do
      allow_nil? false
      public? true
    end
  end
end

To help test that resource, I then created this generator:

defmodule TestApp.Generator do
  use Ash.Generator

  def group(opts \\ []) do
    changeset_generator(
      TestApp.Groups.Group,
      :create,
      defaults: [
        # Intentionally left out :name for this example
      ],
      overrides: opts
    )
  end
end

And this test:

defmodule TestApp.Groups.GroupTest do
  use ExUnit.Case
  import TestApp.Generator

  describe "valid inputs" do
    test "can create group record" do
      group = generate(group())
      IO.inspect(group)
    end
end

The result of IO.inspect(group) is:

%TestApp.Groups.Group{
  id: "01986631-4a81-712f-841c-510b7ed42eeb",
  name: "?⃞",
  __meta__: #Ecto.Schema.Metadata<:loaded>
}

What I’d expect is for :name to be nil or perhaps "" and for the test to fail, but instead I get the above output and the test passes because :name does technically exist.

There are definitely better ways to accomplish what I’m trying to do (e.g. explicitly passing name: nil rather than relying on implicit behavior), so this question is just pure curiosity. Am I seeing "?⃞" because of a mistake in my code, a quirk in how changeset_generator/3 interacts with resources, or something else entirely?

Generators fill in valid values by default for action inputs using the underlying type generators. IIRC you can do things like: name: "" in the defaults to prevent that.

Oh! Thanks, that pointed me in the right direction (props on how easy the Ash codebase is to read btw).

So if I’m reading this correctly, Ash is essentially calling StreamData.string/2 with :printable to generate default values for :string types. Since StreamData.string/2 doesn’t make any assumptions about :min_length or :max_length, what I’m getting back is a valid string of random length. Mystery solved.