diff --git a/lib/govuk_schemas/random_schema_generator.rb b/lib/govuk_schemas/random_schema_generator.rb index 0b6381d..6251a4f 100644 --- a/lib/govuk_schemas/random_schema_generator.rb +++ b/lib/govuk_schemas/random_schema_generator.rb @@ -116,12 +116,27 @@ def generate_random_object(subschema) def generate_random_array(props) min = props["minItems"] || 0 max = props["maxItems"] || 10 + unique = props["uniqueItems"] == true num_items = @random.rand(min..max) + items = [] + attempts = 0 + max_attempts = num_items * 100 - num_items.times.map do + until items.length == num_items # sometimes arrays don't have `items` specified, not sure if this is a bug - generate_value(props["items"] || {}) + new_value = generate_value(props["items"] || {}) + + if unique && items.include?(new_value) + attempts += 1 + raise "Failed to create a unique array item after #{max_attempts} attempts" if attempts >= max_attempts + next + end + + attempts = 0 + items << new_value end + + items end def generate_random_string(props) diff --git a/spec/lib/random_schema_generator_spec.rb b/spec/lib/random_schema_generator_spec.rb index 82f0c98..6ff3f45 100644 --- a/spec/lib/random_schema_generator_spec.rb +++ b/spec/lib/random_schema_generator_spec.rb @@ -110,5 +110,44 @@ expect(generator.payload["my_enum"]).to eq("a") expect(generator.payload.keys).to include("my_field") end + + describe "unique arrays" do + it "handles arrays that require unique items" do + schema = { + "type" => "array", + "items" => { "type" => "string" }, + "uniqueItems" => true, + "minItems" => 5, + "maxItems" => 5, + } + + generator = GovukSchemas::RandomSchemaGenerator.new(schema: schema) + + # These stubs are to ensure determinism in the random array value + # generation. + allow(generator).to receive(:generate_value).and_call_original + allow(generator) + .to receive(:generate_value) + .with({ "type" => "string" }) + .and_return(*%w[a a b b c c d d e e]) + + expect(generator.payload).to match_array(%w[a b c d e]) + end + + it "raises an error for a situation where it can't generate a random array" do + schema = { + "type" => "array", + "items" => { "enum" => %w[a b] }, + "uniqueItems" => true, + "minItems" => 3, + "maxItems" => 3, + } + + generator = GovukSchemas::RandomSchemaGenerator.new(schema: schema) + + expect { generator.payload } + .to raise_error "Failed to create a unique array item after 300 attempts" + end + end end end