Skip to content

Commit

Permalink
Merge branch 'faker-ruby:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
tiff-o authored Aug 14, 2022
2 parents 1692eec + 6aecb58 commit fa96811
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 18 deletions.
17 changes: 10 additions & 7 deletions lib/faker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,26 @@

module Faker
module Config
@locale = nil
@random = nil

class << self
attr_writer :locale, :random
def locale=(new_locale)
Thread.current[:faker_config_locale] = new_locale
end

def locale
# Because I18n.locale defaults to :en, if we don't have :en in our available_locales, errors will happen
@locale || (I18n.available_locales.include?(I18n.locale) ? I18n.locale : I18n.available_locales.first)
Thread.current[:faker_config_locale] || (I18n.available_locales.include?(I18n.locale) ? I18n.locale : I18n.available_locales.first)
end

def own_locale
@locale
Thread.current[:faker_config_locale]
end

def random=(new_random)
Thread.current[:faker_config_random] = new_random
end

def random
@random || Random
Thread.current[:faker_config_random] || Random
end
end
end
Expand Down
24 changes: 13 additions & 11 deletions lib/helpers/unique_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,9 @@

module Faker
class UniqueGenerator
@marked_unique = Set.new # Holds names of generators with unique values

class << self
attr_reader :marked_unique
end

def initialize(generator, max_retries)
@generator = generator
@max_retries = max_retries
@previous_results = Hash.new { |hash, key| hash[key] = Set.new }
end

def method_missing(name, *arguments)
Expand All @@ -20,9 +13,9 @@ def method_missing(name, *arguments)
@max_retries.times do
result = @generator.public_send(name, *arguments)

next if @previous_results[[name, arguments]].include?(result)
next if previous_results[[name, arguments]].include?(result)

@previous_results[[name, arguments]] << result
previous_results[[name, arguments]] << result
return result
end

Expand All @@ -39,8 +32,17 @@ def respond_to_missing?(method_name, include_private = false)

RetryLimitExceeded = Class.new(StandardError)

def previous_results
Thread.current[:faker_unique_generator_previous_results] ||= {}
Thread.current[:faker_unique_generator_previous_results][@generator] ||= Hash.new { |hash, key| hash[key] = Set.new }
end

def clear
@previous_results.clear
previous_results.clear
end

def self.marked_unique
Thread.current[:faker_unique_generator_marked_unique] ||= Set.new
end

def self.clear
Expand All @@ -51,7 +53,7 @@ def self.clear
def exclude(name, arguments, values)
values ||= []
values.each do |value|
@previous_results[[name, arguments]] << value
previous_results[[name, arguments]] << value
end
end
end
Expand Down
39 changes: 39 additions & 0 deletions test/faker/default/test_faker_unique_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,43 @@ def stubbed_generator2.test
assert_equal(2, generator2.test)
end
end

def test_thread_safety
stubbed_generator = Object.new
def stubbed_generator.test
1
end

generator = Faker::UniqueGenerator.new(stubbed_generator, 3)

Thread.new do
assert_equal(1, generator.test)

assert_raises Faker::UniqueGenerator::RetryLimitExceeded do
generator.test
end
end.join

Thread.new do
assert_equal(1, generator.test)
end.join

assert_equal(1, generator.test)

assert_raises Faker::UniqueGenerator::RetryLimitExceeded do
generator.test
end

Thread.new do
generator.clear
end.join

assert_raises Faker::UniqueGenerator::RetryLimitExceeded do
generator.test
end

generator.clear

assert_equal(1, generator.test)
end
end
20 changes: 20 additions & 0 deletions test/test_determinism.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,26 @@ def test_determinism
end
end

def test_thread_safety
expected_values = 2.times.map do |index|
Faker::Config.random = Random.new(index)
Faker::Number.digit
end

threads = expected_values.each_with_index.map do |expected_value, index|
Thread.new do
100_000.times.each do
Faker::Config.random = Random.new(index)
output = Faker::Number.digit

assert_equal output, expected_value
end
end
end

threads.each(&:join)
end

private

def deterministic_random?(first, method_name)
Expand Down

0 comments on commit fa96811

Please sign in to comment.