From 47b23b85b0b493960647ffcf58df1eb8a8a2e6e6 Mon Sep 17 00:00:00 2001 From: sergioperezcheco Date: Sun, 11 Oct 2026 17:31:00 +0800 Subject: [PATCH] Fix global clearing of exclusion-only unique generators Register wrappers when exclude populates their thread-local results, so global clear also visits generators that have not generated a value since its last call. Cover both lifecycle cases and thread isolation. Assisted-by: OpenAI Signed-off-by: sergioperezcheco --- lib/helpers/unique_generator.rb | 1 + .../default/test_faker_unique_generator.rb | 48 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/lib/helpers/unique_generator.rb b/lib/helpers/unique_generator.rb index 634589ea94..45d8f69e82 100644 --- a/lib/helpers/unique_generator.rb +++ b/lib/helpers/unique_generator.rb @@ -51,6 +51,7 @@ def self.clear end def exclude(name, arguments, values) + self.class.marked_unique.add(self) values ||= [] values.each do |value| previous_results[[name, arguments]] << value diff --git a/test/faker/default/test_faker_unique_generator.rb b/test/faker/default/test_faker_unique_generator.rb index 66554db655..c5cffbdc16 100644 --- a/test/faker/default/test_faker_unique_generator.rb +++ b/test/faker/default/test_faker_unique_generator.rb @@ -123,6 +123,54 @@ def stubbed_generator2.test end end + def test_global_clear_removes_exclusions_before_first_generation + source = Object.new + def source.value + 1 + end + + generator = Faker::UniqueGenerator.new(source, 3) + generator.exclude(:value, [], [1]) + + Faker::UniqueGenerator.clear + + assert_equal(1, generator.value) + end + + def test_global_clear_removes_exclusions_after_previous_clear + source = Object.new + def source.value + 1 + end + + generator = Faker::UniqueGenerator.new(source, 3) + + assert_equal(1, generator.value) + Faker::UniqueGenerator.clear + generator.exclude(:value, [], [1]) + Faker::UniqueGenerator.clear + + assert_equal(1, generator.value) + end + + def test_global_clear_keeps_exclusions_in_other_threads + source = Object.new + def source.value + 1 + end + + generator = Faker::UniqueGenerator.new(source, 3) + generator.exclude(:value, [], [1]) + Thread.new { Faker::UniqueGenerator.clear }.join + + assert_raises Faker::UniqueGenerator::RetryLimitExceeded do + generator.value + end + Faker::UniqueGenerator.clear + + assert_equal(1, generator.value) + end + def test_thread_safety stubbed_generator = Object.new def stubbed_generator.test