synthra 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +4 -0
- data/.rubocop.yml +40 -0
- data/.yardopts +18 -0
- data/ACCESS_DOCS.md +116 -0
- data/ADVANCED_FEATURES_SUMMARY.md +245 -0
- data/CHANGELOG.md +498 -0
- data/CODE_OF_CONDUCT.md +122 -0
- data/CONTRIBUTING.md +307 -0
- data/DOCUMENTATION.md +204 -0
- data/DOCUMENTATION_GUIDE.md +194 -0
- data/LICENSE +22 -0
- data/README.md +1458 -0
- data/Rakefile +128 -0
- data/benchmark/README.md +591 -0
- data/benchmark/batch_generation.rb +63 -0
- data/benchmark/engine_comparison.rb +295 -0
- data/benchmark/single_record.rb +108 -0
- data/benchmark/streaming.rb +74 -0
- data/docs/ACTIVERECORD_INFERENCE.md +524 -0
- data/docs/API_SERVER.md +278 -0
- data/docs/CONFIG_FILE.md +315 -0
- data/docs/DATA_CONTRACTS.md +312 -0
- data/docs/ENHANCED_REPL.md +304 -0
- data/docs/FACTORY_BOT.md +271 -0
- data/docs/GITHUB_ACTION.md +420 -0
- data/docs/GRAPHQL_EXPORT.md +303 -0
- data/docs/GRAPHQL_FEDERATION.md +651 -0
- data/docs/HOW_TO_GENERATE_DOCS.md +252 -0
- data/docs/LSP.md +189 -0
- data/docs/MIGRATION_GENERATOR.md +547 -0
- data/docs/MOCK_SERVER.md +280 -0
- data/docs/NATIVE_ENGINE.md +298 -0
- data/docs/OPENAPI_EXPORT.md +252 -0
- data/docs/PERFORMANCE_MODE.md +228 -0
- data/docs/PERSONAS.md +547 -0
- data/docs/PROPERTY_TESTING.md +284 -0
- data/docs/PROTOBUF_EXPORT.md +276 -0
- data/docs/QUALITY_METRICS.md +555 -0
- data/docs/QUICK_REFERENCE.md +88 -0
- data/docs/RAILS_ENGINE.md +404 -0
- data/docs/RAILS_INTEGRATION.md +454 -0
- data/docs/README.md +175 -0
- data/docs/REPL_QUICK_REFERENCE.md +149 -0
- data/docs/RUST_INTEGRATION_GUIDE.md +1376 -0
- data/docs/SCENARIOS.md +576 -0
- data/docs/SECURITY_TESTING.md +318 -0
- data/docs/SNAPSHOT_TESTING.md +308 -0
- data/docs/STRING_TEXT_TYPES_REFERENCE.md +512 -0
- data/docs/TERRAFORM_EXPORT.md +447 -0
- data/docs/TIME_TRAVEL.md +507 -0
- data/docs/USAGE_GUIDE.md +980 -0
- data/docs/WEBHOOK_SIMULATOR.md +579 -0
- data/docs/advanced_features.md +183 -0
- data/docs/api_reference.md +153 -0
- data/docs/behaviors.md +138 -0
- data/docs/best_practices.md +191 -0
- data/docs/dsl_reference.md +172 -0
- data/docs/examples.md +162 -0
- data/docs/generation_modes.md +125 -0
- data/docs/getting_started.md +92 -0
- data/docs/index.html +177 -0
- data/docs/strategic/CLOUD_REGISTRY_ARCHITECTURE.md +268 -0
- data/docs/strategic/SIMD_OPTIMIZATION_STRATEGY.md +153 -0
- data/docs/troubleshooting.md +215 -0
- data/docs/type_reference.md +224 -0
- data/examples/hostile_mode_demo.rb +64 -0
- data/exe/synthra +6 -0
- data/ext/synthra_native/Cargo.lock +972 -0
- data/ext/synthra_native/Cargo.toml +46 -0
- data/ext/synthra_native/extconf.rb +41 -0
- data/ext/synthra_native/src/generator.rs +397 -0
- data/ext/synthra_native/src/lib.rs +229 -0
- data/ext/synthra_native/src/types.rs +1485 -0
- data/lib/generators/synthra/install_generator.rb +86 -0
- data/lib/generators/synthra/templates/api_response.dsl +15 -0
- data/lib/generators/synthra/templates/fake_data.rake +116 -0
- data/lib/generators/synthra/templates/synthra.yml +31 -0
- data/lib/generators/synthra/templates/synthra_support.rb +19 -0
- data/lib/generators/synthra/templates/user.dsl +11 -0
- data/lib/synthra/activerecord_inference.rb +394 -0
- data/lib/synthra/api.rb +381 -0
- data/lib/synthra/api_server.rb +718 -0
- data/lib/synthra/behaviors/applicator.rb +165 -0
- data/lib/synthra/behaviors/base.rb +155 -0
- data/lib/synthra/behaviors/close_connection.rb +60 -0
- data/lib/synthra/behaviors/deprecated.rb +100 -0
- data/lib/synthra/behaviors/failure.rb +69 -0
- data/lib/synthra/behaviors/latency.rb +103 -0
- data/lib/synthra/behaviors/partial_data.rb +83 -0
- data/lib/synthra/behaviors/randomize_order.rb +74 -0
- data/lib/synthra/behaviors/registry.rb +238 -0
- data/lib/synthra/behaviors/simulate_error.rb +79 -0
- data/lib/synthra/cli/commands/base.rb +105 -0
- data/lib/synthra/cli/commands/diff.rb +227 -0
- data/lib/synthra/cli/commands/docs.rb +67 -0
- data/lib/synthra/cli/commands/export.rb +150 -0
- data/lib/synthra/cli/commands/generate.rb +72 -0
- data/lib/synthra/cli/commands/import.rb +80 -0
- data/lib/synthra/cli/commands/lint.rb +53 -0
- data/lib/synthra/cli/commands/live.rb +57 -0
- data/lib/synthra/cli/commands/seed.rb +99 -0
- data/lib/synthra/cli/commands/validate.rb +28 -0
- data/lib/synthra/cli.rb +2471 -0
- data/lib/synthra/config_file.rb +129 -0
- data/lib/synthra/configuration.rb +281 -0
- data/lib/synthra/contracts_registry.rb +408 -0
- data/lib/synthra/database_seeder.rb +268 -0
- data/lib/synthra/deterministic_ids.rb +218 -0
- data/lib/synthra/documentation_generator.rb +414 -0
- data/lib/synthra/engine.rb +251 -0
- data/lib/synthra/errors.rb +1169 -0
- data/lib/synthra/export/base.rb +85 -0
- data/lib/synthra/export/csv.rb +101 -0
- data/lib/synthra/export/graphql.rb +266 -0
- data/lib/synthra/export/graphql_federation.rb +377 -0
- data/lib/synthra/export/graphviz.rb +258 -0
- data/lib/synthra/export/javascript.rb +327 -0
- data/lib/synthra/export/json_data.rb +61 -0
- data/lib/synthra/export/json_schema.rb +290 -0
- data/lib/synthra/export/openapi.rb +514 -0
- data/lib/synthra/export/protobuf.rb +483 -0
- data/lib/synthra/export/python.rb +560 -0
- data/lib/synthra/export/sql.rb +381 -0
- data/lib/synthra/export/sql_insert.rb +152 -0
- data/lib/synthra/export/terraform.rb +501 -0
- data/lib/synthra/export/type_mapping.rb +389 -0
- data/lib/synthra/export/typescript.rb +300 -0
- data/lib/synthra/export/xml_data.rb +104 -0
- data/lib/synthra/export/yaml_data.rb +56 -0
- data/lib/synthra/export.rb +404 -0
- data/lib/synthra/factory_bot_integration.rb +157 -0
- data/lib/synthra/field.rb +440 -0
- data/lib/synthra/functions/registry.rb +104 -0
- data/lib/synthra/generator/context.rb +372 -0
- data/lib/synthra/generator/engine.rb +336 -0
- data/lib/synthra/generator/faker_adapter.rb +425 -0
- data/lib/synthra/generator/modes.rb +444 -0
- data/lib/synthra/generator/resolver.rb +256 -0
- data/lib/synthra/generator/rng.rb +273 -0
- data/lib/synthra/generator/streamer.rb +63 -0
- data/lib/synthra/generator/uniqueness.rb +118 -0
- data/lib/synthra/initializer.rb +97 -0
- data/lib/synthra/limits.rb +279 -0
- data/lib/synthra/live_preview.rb +518 -0
- data/lib/synthra/loader_config.rb +78 -0
- data/lib/synthra/lsp/server.rb +689 -0
- data/lib/synthra/migration_generator.rb +301 -0
- data/lib/synthra/mixin.rb +174 -0
- data/lib/synthra/mock_server.rb +458 -0
- data/lib/synthra/native_engine.rb +304 -0
- data/lib/synthra/openapi_importer.rb +228 -0
- data/lib/synthra/output/json_formatter.rb +40 -0
- data/lib/synthra/output/ndjson_formatter.rb +55 -0
- data/lib/synthra/parser/ast.rb +1287 -0
- data/lib/synthra/parser/lexer.rb +1152 -0
- data/lib/synthra/parser/parser.rb +1664 -0
- data/lib/synthra/parser/tokens.rb +461 -0
- data/lib/synthra/performance_mode.rb +364 -0
- data/lib/synthra/personas.rb +397 -0
- data/lib/synthra/property_testing.rb +172 -0
- data/lib/synthra/quality_metrics.rb +405 -0
- data/lib/synthra/rails_test_helper.rb +248 -0
- data/lib/synthra/registry.rb +533 -0
- data/lib/synthra/relationships.rb +193 -0
- data/lib/synthra/repl/enhanced_repl.rb +607 -0
- data/lib/synthra/repl/formatter.rb +191 -0
- data/lib/synthra/scenarios.rb +423 -0
- data/lib/synthra/schema.rb +605 -0
- data/lib/synthra/schema_inheritance.rb +104 -0
- data/lib/synthra/schema_versioning.rb +212 -0
- data/lib/synthra/snapshot_testing.rb +199 -0
- data/lib/synthra/time_travel.rb +338 -0
- data/lib/synthra/type_definitions.rb +274 -0
- data/lib/synthra/types/address_location/addresses.rb +125 -0
- data/lib/synthra/types/address_location/airports.rb +200 -0
- data/lib/synthra/types/address_location/banks_hospitals.rb +207 -0
- data/lib/synthra/types/address_location/locations.rb +406 -0
- data/lib/synthra/types/base.rb +48 -0
- data/lib/synthra/types/commerce_products/commerce.rb +119 -0
- data/lib/synthra/types/commerce_products/companies.rb +71 -0
- data/lib/synthra/types/commerce_products/construction.rb +126 -0
- data/lib/synthra/types/commerce_products/products.rb +205 -0
- data/lib/synthra/types/core/collections.rb +513 -0
- data/lib/synthra/types/core/defaults.rb +76 -0
- data/lib/synthra/types/core/enums.rb +102 -0
- data/lib/synthra/types/core/identifiers.rb +445 -0
- data/lib/synthra/types/core/primitives.rb +586 -0
- data/lib/synthra/types/core/references.rb +466 -0
- data/lib/synthra/types/core/sequences.rb +304 -0
- data/lib/synthra/types/crypto/crypto.rb +162 -0
- data/lib/synthra/types/date_time/dates.rb +387 -0
- data/lib/synthra/types/finance_banking/banking.rb +424 -0
- data/lib/synthra/types/finance_banking/credit_cards.rb +24 -0
- data/lib/synthra/types/finance_banking/identifiers.rb +93 -0
- data/lib/synthra/types/formula.rb +184 -0
- data/lib/synthra/types/health_medical/medical.rb +150 -0
- data/lib/synthra/types/hostile_payloads.rb +122 -0
- data/lib/synthra/types/json_array.rb +51 -0
- data/lib/synthra/types/media_entertainment/media.rb +62 -0
- data/lib/synthra/types/naughty_string.rb +30 -0
- data/lib/synthra/types/personal_names/chinese.rb +41 -0
- data/lib/synthra/types/personal_names/identifiers.rb +187 -0
- data/lib/synthra/types/personal_names/names.rb +246 -0
- data/lib/synthra/types/personal_names/national_id.rb +89 -0
- data/lib/synthra/types/personal_names/titles_suffixes.rb +41 -0
- data/lib/synthra/types/regex.rb +248 -0
- data/lib/synthra/types/registry.rb +182 -0
- data/lib/synthra/types/repeating_element.rb +50 -0
- data/lib/synthra/types/scenario.rb +29 -0
- data/lib/synthra/types/technology_internet/apps.rb +67 -0
- data/lib/synthra/types/technology_internet/communication.rb +162 -0
- data/lib/synthra/types/technology_internet/devices.rb +80 -0
- data/lib/synthra/types/technology_internet/formats.rb +139 -0
- data/lib/synthra/types/technology_internet/networking.rb +143 -0
- data/lib/synthra/types/template.rb +92 -0
- data/lib/synthra/types/text_content/business.rb +128 -0
- data/lib/synthra/types/text_content/colors.rb +70 -0
- data/lib/synthra/types/text_content/misc.rb +237 -0
- data/lib/synthra/types/text_content/security.rb +130 -0
- data/lib/synthra/types/text_content/text_generation.rb +532 -0
- data/lib/synthra/types/travel/travel.rb +150 -0
- data/lib/synthra/utils/string_distance.rb +133 -0
- data/lib/synthra/validator/dsl_validator.rb +339 -0
- data/lib/synthra/validator/path_validator.rb +615 -0
- data/lib/synthra/version.rb +35 -0
- data/lib/synthra/webhook_simulator.rb +341 -0
- data/lib/synthra.rb +259 -0
- data/schemas/address.dsl +16 -0
- data/schemas/api_response.dsl +8 -0
- data/schemas/error_payload.dsl +9 -0
- data/schemas/order.dsl +10 -0
- data/schemas/order_item.dsl +8 -0
- data/schemas/payment.dsl +11 -0
- data/schemas/social_post.dsl +13 -0
- data/schemas/user.dsl +10 -0
- data/scripts/batch_fix_all.rb +96 -0
- data/scripts/delete_old_files.rb +32 -0
- data/scripts/fix_all_grouped_files.rb +137 -0
- data/scripts/fix_all_indentation.rb +48 -0
- data/scripts/fix_all_syntax.rb +124 -0
- data/scripts/fix_grouped_files.rb +184 -0
- data/scripts/fix_syntax_errors.rb +108 -0
- data/scripts/group_domain_types.rb +112 -0
- data/scripts/group_domain_types_fixed.rb +150 -0
- data/scripts/merge_domains_to_one_file.rb +68 -0
- data/scripts/move_existing_types.rb +130 -0
- data/scripts/split_grouped_types.rb +142 -0
- data/tech_docs/README.md +134 -0
- data/tech_docs/advanced/streaming.md +405 -0
- data/tech_docs/advanced/thread_safety.md +253 -0
- data/tech_docs/api/overview.md +485 -0
- data/tech_docs/appendices/type_chart.md +193 -0
- data/tech_docs/basic_concepts.md +383 -0
- data/tech_docs/behaviors/overview.md +346 -0
- data/tech_docs/dsl/complex_types.md +790 -0
- data/tech_docs/dsl/core_types.md +464 -0
- data/tech_docs/dsl/datetime_types.md +325 -0
- data/tech_docs/dsl/field_modifiers.md +414 -0
- data/tech_docs/dsl/grammar.md +431 -0
- data/tech_docs/dsl/schema_definition.md +399 -0
- data/tech_docs/export/README.md +276 -0
- data/tech_docs/installation.md +273 -0
- data/tech_docs/integration/ci_cd.md +707 -0
- data/tech_docs/integration/ci_cd_guide.md +579 -0
- data/tech_docs/integration/factory_bot.md +485 -0
- data/tech_docs/integration/rails.md +630 -0
- data/tech_docs/integration/rspec.md +449 -0
- data/tech_docs/modes/overview.md +350 -0
- data/tech_docs/performance/NATIVE_RUST_EXTENSION.md +1270 -0
- data/tech_docs/performance/OPTIMIZATION_GUIDE.md +901 -0
- data/tech_docs/quick_start.md +256 -0
- data/tech_docs/templates/README.md +805 -0
- data/tech_docs/tutorials/advanced.md +371 -0
- data/tech_docs/tutorials/getting_started.md +189 -0
- data/tech_docs/tutorials/intermediate.md +231 -0
- data/tech_docs/tutorials/template_gallery.md +569 -0
- data/tech_example/01_basic_usage.rb +238 -0
- data/tech_example/02_types_demo.rb +336 -0
- data/tech_example/04_cli_usage.md +429 -0
- data/tech_example/05_database_seeding.rb +283 -0
- data/tech_example/07_rspec_integration.rb +359 -0
- data/tech_example/10_custom_types.rb +387 -0
- data/tech_example/12_behaviors.rb +372 -0
- data/tech_example/13_twitter_dm_example.rb +120 -0
- data/tech_example/14_exact_json_structure.rb +253 -0
- data/tech_example/16_lsp_server.rb +56 -0
- data/tech_example/17_property_testing.rb +92 -0
- data/tech_example/18_enhanced_repl.rb +120 -0
- data/tech_example/19_security_fuzzing.rb +145 -0
- data/tech_example/NEW_FEATURES.md +169 -0
- data/tech_example/README.md +118 -0
- data/tech_example/schemas/api_response.dsl +123 -0
- data/tech_example/schemas/ecommerce.dsl +121 -0
- data/tech_example/schemas/twitter_dm.dsl +109 -0
- data/tech_example/schemas/user.dsl +36 -0
- data/vscode-extension/README.md +246 -0
- data/vscode-extension/language-configuration.json +31 -0
- data/vscode-extension/package.json +55 -0
- data/vscode-extension/snippets/fakedatadsl.json +198 -0
- data/vscode-extension/syntaxes/fakedatadsl.tmLanguage.json +128 -0
- metadata +478 -0
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Synthra
|
|
4
|
+
module Types
|
|
5
|
+
module AddressLocation
|
|
6
|
+
# City type
|
|
7
|
+
class City < Base
|
|
8
|
+
# Generate random city name
|
|
9
|
+
#
|
|
10
|
+
# @param rng [Generator::RNG] random number generator (not directly used)
|
|
11
|
+
# @param context [Generator::Context] generation context
|
|
12
|
+
# @param args [Hash] type arguments (not used)
|
|
13
|
+
# @return [String] generated city name
|
|
14
|
+
#
|
|
15
|
+
def generate_random(rng, context, args)
|
|
16
|
+
adapter = faker_adapter(context)
|
|
17
|
+
if adapter
|
|
18
|
+
adapter.city
|
|
19
|
+
|
|
20
|
+
else
|
|
21
|
+
Faker::Address.city
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
rescue StandardError
|
|
25
|
+
rng.sample(["New York", "Los Angeles", "Chicago", "Houston", "Phoenix"])
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def generate_edge(rng, context, args)
|
|
30
|
+
["", "A", "Very Long City Name That Exceeds Normal Limits"].sample(random: rng.instance_variable_get(:@random))
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def generate_invalid(rng, context, args)
|
|
34
|
+
[nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# State type
|
|
39
|
+
class State < Base
|
|
40
|
+
# Generate random state/province name
|
|
41
|
+
#
|
|
42
|
+
# @param rng [Generator::RNG] random number generator (not directly used)
|
|
43
|
+
# @param context [Generator::Context] generation context
|
|
44
|
+
# @param args [Hash] type arguments
|
|
45
|
+
# @option args [Symbol, String] :country country code (:us, :ca, etc.)
|
|
46
|
+
# @return [String] generated state/province name
|
|
47
|
+
#
|
|
48
|
+
def generate_random(rng, context, args)
|
|
49
|
+
country = (args[:country] || :us).to_sym
|
|
50
|
+
|
|
51
|
+
adapter = faker_adapter(context)
|
|
52
|
+
if adapter
|
|
53
|
+
case country
|
|
54
|
+
when :us
|
|
55
|
+
adapter.state
|
|
56
|
+
when :ca
|
|
57
|
+
adapter.state_abbr # Faker uses state_abbr for Canada
|
|
58
|
+
|
|
59
|
+
else
|
|
60
|
+
adapter.state
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
else
|
|
64
|
+
# Fallback to Faker with default locale
|
|
65
|
+
case country
|
|
66
|
+
when :us
|
|
67
|
+
Faker::Address.state
|
|
68
|
+
when :ca
|
|
69
|
+
Faker::Address.state_abbr
|
|
70
|
+
else
|
|
71
|
+
Faker::Address.state
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
rescue StandardError
|
|
77
|
+
rng.sample(["California", "New York", "Texas", "Florida", "Illinois"])
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def generate_edge(rng, context, args)
|
|
82
|
+
["", "CA", "Very Long State Name That Exceeds Normal Limits"].sample(random: rng.instance_variable_get(:@random))
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def generate_invalid(rng, context, args)
|
|
86
|
+
[nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Country type
|
|
91
|
+
class Country < Base
|
|
92
|
+
# Generate random country name
|
|
93
|
+
#
|
|
94
|
+
# @param rng [Generator::RNG] random number generator (not directly used)
|
|
95
|
+
# @param context [Generator::Context] generation context
|
|
96
|
+
# @param args [Hash] type arguments (not used)
|
|
97
|
+
# @return [String] generated country name
|
|
98
|
+
#
|
|
99
|
+
def generate_random(rng, context, args)
|
|
100
|
+
adapter = faker_adapter(context)
|
|
101
|
+
if adapter
|
|
102
|
+
adapter.country
|
|
103
|
+
|
|
104
|
+
else
|
|
105
|
+
Faker::Address.country
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
rescue StandardError
|
|
109
|
+
rng.sample(["United States", "Canada", "Mexico", "Germany", "France"])
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def generate_edge(rng, context, args)
|
|
114
|
+
["", "A", "Very Long Country Name That Exceeds Normal Limits"].sample(random: rng.instance_variable_get(:@random))
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def generate_invalid(rng, context, args)
|
|
118
|
+
[nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# CountryCode type
|
|
123
|
+
class CountryCode < Base
|
|
124
|
+
# Fallback country codes if Faker is unavailable
|
|
125
|
+
#
|
|
126
|
+
# ISO 3166-1 alpha-2 country codes used when Faker cannot generate codes.
|
|
127
|
+
#
|
|
128
|
+
# @return [Array<String>] list of 2-letter country codes
|
|
129
|
+
#
|
|
130
|
+
FALLBACK_CODES = %w[
|
|
131
|
+
US GB CA AU DE FR JP CN IN BR
|
|
132
|
+
MX ES IT NL SE NO DK FI CH AT
|
|
133
|
+
BE IE NZ SG KR TW HK MY PH ID
|
|
134
|
+
TH VN PL CZ HU RO BG GR PT EG
|
|
135
|
+
ZA NG KE MA AE SA IL TR UA RU
|
|
136
|
+
].freeze
|
|
137
|
+
|
|
138
|
+
# Generate a random country code
|
|
139
|
+
#
|
|
140
|
+
# Uses Faker::Address.country_code for realistic ISO 3166-1 alpha-2 codes.
|
|
141
|
+
#
|
|
142
|
+
# @param rng [Generator::RNG] random number generator
|
|
143
|
+
# @param args [Hash] type arguments (not used)
|
|
144
|
+
# @return [String] two-letter country code
|
|
145
|
+
#
|
|
146
|
+
# @example
|
|
147
|
+
# generate_random(rng, {})
|
|
148
|
+
# # => "DE"
|
|
149
|
+
#
|
|
150
|
+
def generate_random(rng, context, args)
|
|
151
|
+
adapter = faker_adapter(context)
|
|
152
|
+
if adapter
|
|
153
|
+
adapter.country_code
|
|
154
|
+
|
|
155
|
+
else
|
|
156
|
+
Faker::Address.country_code
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
rescue StandardError
|
|
160
|
+
rng.sample(FALLBACK_CODES)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def generate_edge(rng, context, args)
|
|
165
|
+
["", "A", "USA"].sample(random: rng.instance_variable_get(:@random))
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def generate_invalid(rng, context, args)
|
|
169
|
+
[nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# PostalCode type
|
|
174
|
+
class PostalCode < Base
|
|
175
|
+
# Generate a random postal code
|
|
176
|
+
#
|
|
177
|
+
# Uses Faker::Address.zip_code or postcode for realistic values.
|
|
178
|
+
# Falls back to manual generation if needed.
|
|
179
|
+
#
|
|
180
|
+
# @param rng [Generator::RNG] random number generator
|
|
181
|
+
# @param args [Hash] type arguments
|
|
182
|
+
# @option args [String] :country country code for format hint (US, GB, CA, etc.)
|
|
183
|
+
# @return [String] postal code
|
|
184
|
+
#
|
|
185
|
+
# @example
|
|
186
|
+
# generate_random(rng, { country: "US" })
|
|
187
|
+
# # => "90210"
|
|
188
|
+
#
|
|
189
|
+
def generate_random(rng, context, args)
|
|
190
|
+
country = args[:country]
|
|
191
|
+
adapter = faker_adapter(context)
|
|
192
|
+
|
|
193
|
+
# Use Faker with locale switching if country specified
|
|
194
|
+
if country
|
|
195
|
+
result = generate_for_country(country, rng, adapter)
|
|
196
|
+
return result if result && !result.empty?
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Fallback to country-specific format if Faker didn't work
|
|
200
|
+
if country
|
|
201
|
+
return generate_country_format(country.to_s.upcase, rng)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Default Faker locale
|
|
205
|
+
if adapter
|
|
206
|
+
adapter.zip_code
|
|
207
|
+
|
|
208
|
+
else
|
|
209
|
+
Faker::Address.zip_code
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
rescue StandardError
|
|
213
|
+
# Fallback to a generic format
|
|
214
|
+
country = args[:country]
|
|
215
|
+
if country
|
|
216
|
+
generate_country_format(country.to_s.upcase, rng)
|
|
217
|
+
else
|
|
218
|
+
rng.sample(["12345", "90210", "SW1A 0AA", "M5V 2L9"])
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def generate_edge(rng, context, args)
|
|
224
|
+
["", "00000", "99999", "A1A 1A1"].sample(random: rng.instance_variable_get(:@random))
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def generate_invalid(rng, context, args)
|
|
228
|
+
["invalid", nil, 123, "ABCDE"].sample(random: rng.instance_variable_get(:@random))
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
private
|
|
232
|
+
|
|
233
|
+
# Generates a postal code for a specific country, handling Faker locales.
|
|
234
|
+
def generate_for_country(country, rng, adapter)
|
|
235
|
+
original_locale = Faker::Config.locale
|
|
236
|
+
begin
|
|
237
|
+
Faker::Config.locale = country.to_sym
|
|
238
|
+
# :nocov:
|
|
239
|
+
# The :us then-arm is unreachable to completion in the bundled Faker
|
|
240
|
+
# version: :us is not a valid I18n locale for Faker::Address, so both
|
|
241
|
+
# zip_code calls raise I18n::InvalidLocale before returning, and the
|
|
242
|
+
# rescue below references an undefined constant. (latent-bug, do not
|
|
243
|
+
# "fix" here)
|
|
244
|
+
if Faker::Config.locale == :us
|
|
245
|
+
adapter&.zip_code || Faker::Address.zip_code
|
|
246
|
+
# :nocov:
|
|
247
|
+
else
|
|
248
|
+
adapter&.postcode || Faker::Address.postcode
|
|
249
|
+
end
|
|
250
|
+
# :nocov:
|
|
251
|
+
# Unreachable in the bundled Faker version: an invalid locale raises
|
|
252
|
+
# I18n::InvalidLocale (not Faker::UnresolvedLocaleError, which is not
|
|
253
|
+
# even defined here), so this rescue clause itself would raise NameError
|
|
254
|
+
# and never bind. See coverage-spec note. (latent-bug, do not "fix" here)
|
|
255
|
+
rescue Faker::UnresolvedLocaleError
|
|
256
|
+
# Fallback to default locale if specific locale is not found
|
|
257
|
+
Faker::Config.locale = original_locale
|
|
258
|
+
adapter&.zip_code || Faker::Address.zip_code
|
|
259
|
+
# :nocov:
|
|
260
|
+
ensure
|
|
261
|
+
Faker::Config.locale = original_locale
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# Generate postal code in country-specific format
|
|
266
|
+
def generate_country_format(country_code, rng)
|
|
267
|
+
case country_code
|
|
268
|
+
when "US"
|
|
269
|
+
"#{rng.int(10000, 99999)}"
|
|
270
|
+
when "DE"
|
|
271
|
+
"#{rng.int(10000, 99999)}"
|
|
272
|
+
when "JP"
|
|
273
|
+
"#{rng.int(100, 999)}-#{rng.int(1000, 9999)}"
|
|
274
|
+
when "AU"
|
|
275
|
+
"#{rng.int(1000, 9999)}"
|
|
276
|
+
when "GB", "UK"
|
|
277
|
+
rng.sample(["SW1A 0AA", "M1 1AA", "B33 8TH", "W1A 0AX"])
|
|
278
|
+
when "CA"
|
|
279
|
+
"#{rng.sample(['A', 'B', 'C', 'E', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'V', 'X', 'Y'])}#{rng.int(0, 9)}#{rng.sample(['A', 'B', 'C', 'E', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z'])} #{rng.int(0, 9)}#{rng.sample(['A', 'B', 'C', 'E', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z'])}#{rng.int(0, 9)}"
|
|
280
|
+
else
|
|
281
|
+
"#{rng.int(10000, 99999)}"
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# Latitude type
|
|
287
|
+
class Latitude < Base
|
|
288
|
+
# Generate random latitude
|
|
289
|
+
#
|
|
290
|
+
# @param rng [Generator::RNG] random number generator
|
|
291
|
+
# @param context [Generator::Context] generation context
|
|
292
|
+
# @param args [Hash] type arguments
|
|
293
|
+
# @option args [Range] :range latitude range (default: -90..90)
|
|
294
|
+
# @option args [Integer] :precision decimal precision (default: 6)
|
|
295
|
+
# @return [Float] generated latitude
|
|
296
|
+
#
|
|
297
|
+
def generate_random(rng, context, args)
|
|
298
|
+
range = args[:range] || (-90.0..90.0)
|
|
299
|
+
precision = args[:precision] || 6
|
|
300
|
+
|
|
301
|
+
min = [range.min, -90.0].max
|
|
302
|
+
max = [range.max, 90.0].min
|
|
303
|
+
|
|
304
|
+
value = rng.rand * (max - min) + min
|
|
305
|
+
value.round(precision)
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def generate_edge(rng, context, args)
|
|
309
|
+
[-90.0, 90.0, 0.0].sample(random: rng.instance_variable_get(:@random))
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
def generate_invalid(rng, context, args)
|
|
313
|
+
[nil, "not a number", [], {}].sample(random: rng.instance_variable_get(:@random))
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# Longitude type
|
|
318
|
+
class Longitude < Base
|
|
319
|
+
# Generate random longitude
|
|
320
|
+
#
|
|
321
|
+
# @param rng [Generator::RNG] random number generator
|
|
322
|
+
# @param context [Generator::Context] generation context
|
|
323
|
+
# @param args [Hash] type arguments
|
|
324
|
+
# @option args [Range] :range longitude range (default: -180..180)
|
|
325
|
+
# @option args [Integer] :precision decimal precision (default: 6)
|
|
326
|
+
# @return [Float] generated longitude
|
|
327
|
+
#
|
|
328
|
+
def generate_random(rng, context, args)
|
|
329
|
+
range = args[:range] || (-180.0..180.0)
|
|
330
|
+
precision = args[:precision] || 6
|
|
331
|
+
|
|
332
|
+
min = [range.min, -180.0].max
|
|
333
|
+
max = [range.max, 180.0].min
|
|
334
|
+
|
|
335
|
+
value = rng.rand * (max - min) + min
|
|
336
|
+
value.round(precision)
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
def generate_edge(rng, context, args)
|
|
340
|
+
[-180.0, 180.0, 0.0].sample(random: rng.instance_variable_get(:@random))
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
def generate_invalid(rng, context, args)
|
|
344
|
+
[nil, "not a number", [], {}].sample(random: rng.instance_variable_get(:@random))
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
# Timezone type
|
|
349
|
+
class Timezone < Base
|
|
350
|
+
# Common IANA timezone identifiers
|
|
351
|
+
#
|
|
352
|
+
# @return [Array<String>] list of timezone identifiers
|
|
353
|
+
#
|
|
354
|
+
TIMEZONES = [
|
|
355
|
+
"America/New_York",
|
|
356
|
+
"America/Chicago",
|
|
357
|
+
"America/Denver",
|
|
358
|
+
"America/Los_Angeles",
|
|
359
|
+
"Europe/London",
|
|
360
|
+
"Europe/Paris",
|
|
361
|
+
"Europe/Berlin",
|
|
362
|
+
"Asia/Tokyo",
|
|
363
|
+
"Asia/Shanghai",
|
|
364
|
+
"Asia/Dubai",
|
|
365
|
+
"Australia/Sydney",
|
|
366
|
+
"Australia/Melbourne",
|
|
367
|
+
"America/Toronto",
|
|
368
|
+
"America/Mexico_City",
|
|
369
|
+
"America/Sao_Paulo",
|
|
370
|
+
"Africa/Johannesburg",
|
|
371
|
+
"Pacific/Auckland"
|
|
372
|
+
].freeze
|
|
373
|
+
|
|
374
|
+
# Generate random timezone
|
|
375
|
+
#
|
|
376
|
+
# @param rng [Generator::RNG] random number generator
|
|
377
|
+
# @param context [Generator::Context] generation context
|
|
378
|
+
# @param args [Hash] type arguments (not used)
|
|
379
|
+
# @return [String] generated timezone identifier
|
|
380
|
+
#
|
|
381
|
+
def generate_random(rng, context, args)
|
|
382
|
+
# Try Faker first
|
|
383
|
+
adapter = faker_adapter(context)
|
|
384
|
+
if adapter
|
|
385
|
+
adapter.time_zone
|
|
386
|
+
|
|
387
|
+
else
|
|
388
|
+
Faker::Address.time_zone
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
rescue StandardError
|
|
392
|
+
rng.sample(TIMEZONES)
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def generate_edge(rng, context, args)
|
|
397
|
+
["UTC", "GMT", "Z"].sample(random: rng.instance_variable_get(:@random))
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
def generate_invalid(rng, context, args)
|
|
401
|
+
[nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
|
|
402
|
+
end
|
|
403
|
+
end
|
|
404
|
+
end
|
|
405
|
+
end
|
|
406
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Synthra
|
|
4
|
+
module Types
|
|
5
|
+
class Base
|
|
6
|
+
def generate(rng, context, args, mode)
|
|
7
|
+
case mode
|
|
8
|
+
when :random then generate_random(rng, context, args)
|
|
9
|
+
when :edge then generate_edge(rng, context, args)
|
|
10
|
+
when :invalid then generate_invalid(rng, context, args)
|
|
11
|
+
when :hostile then generate_hostile(rng, context, args)
|
|
12
|
+
else generate_random(rng, context, args)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def generate_random(rng, context, args)
|
|
17
|
+
raise NotImplementedError, "#{self.class} must implement #generate_random"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def generate_edge(rng, context, args)
|
|
21
|
+
generate_random(rng, context, args)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def generate_invalid(rng, context, args)
|
|
25
|
+
nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Generate hostile/malicious data for security testing
|
|
29
|
+
# Override this method in type classes to provide specific attack vectors
|
|
30
|
+
# @param rng [Generator::RNG] random number generator
|
|
31
|
+
# @param context [Generator::Context] generation context
|
|
32
|
+
# @param args [Hash] type arguments
|
|
33
|
+
# @return [Object] hostile data payload
|
|
34
|
+
def generate_hostile(rng, context, args)
|
|
35
|
+
# Default: return edge case value (fallback)
|
|
36
|
+
generate_edge(rng, context, args)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
protected
|
|
40
|
+
|
|
41
|
+
def faker_adapter(context)
|
|
42
|
+
return nil unless context
|
|
43
|
+
|
|
44
|
+
context.faker_adapter if context.respond_to?(:faker_adapter)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Synthra
|
|
4
|
+
module Types
|
|
5
|
+
module CommerceProducts
|
|
6
|
+
# Discount type
|
|
7
|
+
class Discount < Base
|
|
8
|
+
# Generate random discount
|
|
9
|
+
#
|
|
10
|
+
# @param rng [Generator::RNG] random number generator
|
|
11
|
+
# @param context [Generator::Context] generation context
|
|
12
|
+
# @param args [Hash] type arguments
|
|
13
|
+
# @option args [Symbol] :type discount type (:percentage, :amount)
|
|
14
|
+
# @option args [Range] :range discount range (e.g., 0..50 for percentages)
|
|
15
|
+
# @option args [Integer] :min minimum value
|
|
16
|
+
# @option args [Integer, Float] :max maximum value
|
|
17
|
+
# @return [Numeric] generated discount value
|
|
18
|
+
#
|
|
19
|
+
def generate_random(rng, context, args)
|
|
20
|
+
type = (args[:type] || :percentage).to_sym
|
|
21
|
+
|
|
22
|
+
if args[:range].is_a?(Range)
|
|
23
|
+
min = args[:range].min
|
|
24
|
+
max = args[:range].max
|
|
25
|
+
else
|
|
26
|
+
min = args[:min] || 0
|
|
27
|
+
max = args[:max] || (type == :percentage ? 100 : 1000)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
case type
|
|
31
|
+
when :percentage
|
|
32
|
+
rng.int(min, max)
|
|
33
|
+
when :amount
|
|
34
|
+
(rng.rand * (max - min) + min).round(2)
|
|
35
|
+
else
|
|
36
|
+
rng.int(min, max) # fallback
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def generate_edge(rng, context, args)
|
|
41
|
+
[0, 100, 0.0, 999.99].sample(random: rng.instance_variable_get(:@random))
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def generate_invalid(rng, context, args)
|
|
45
|
+
[nil, "abc", -1, [], {}].sample(random: rng.instance_variable_get(:@random))
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# TaxRate type
|
|
50
|
+
class TaxRate < Base
|
|
51
|
+
# Common tax rates by country (as percentages)
|
|
52
|
+
#
|
|
53
|
+
# Maps country codes to arrays of typical tax rate percentages.
|
|
54
|
+
#
|
|
55
|
+
# @return [Hash<Symbol, Array<Float>>] country code to tax rates mapping
|
|
56
|
+
# @example
|
|
57
|
+
# TAX_RATES[:us] # => [0.0, 4.0, 5.0, 6.0, 7.0, 8.0, 8.5, 9.0, 10.0]
|
|
58
|
+
# TAX_RATES[:uk] # => [0.0, 5.0, 20.0]
|
|
59
|
+
#
|
|
60
|
+
TAX_RATES = {
|
|
61
|
+
us: [0.0, 4.0, 5.0, 6.0, 7.0, 8.0, 8.5, 9.0, 10.0],
|
|
62
|
+
uk: [0.0, 5.0, 20.0],
|
|
63
|
+
ca: [0.0, 5.0, 13.0, 15.0],
|
|
64
|
+
de: [0.0, 7.0, 19.0],
|
|
65
|
+
fr: [0.0, 5.5, 10.0, 20.0],
|
|
66
|
+
general: [0.0, 5.0, 10.0, 15.0, 20.0, 25.0]
|
|
67
|
+
}.freeze
|
|
68
|
+
|
|
69
|
+
# Generate random tax rate
|
|
70
|
+
#
|
|
71
|
+
# @param rng [Generator::RNG] random number generator
|
|
72
|
+
# @param context [Generator::Context] generation context
|
|
73
|
+
# @param args [Hash] type arguments
|
|
74
|
+
# @option args [Symbol, String] :country country code for tax rates
|
|
75
|
+
# @option args [Range] :range tax rate range (e.g., 0..20)
|
|
76
|
+
# @return [Float] generated tax rate percentage
|
|
77
|
+
#
|
|
78
|
+
def generate_random(rng, context, args)
|
|
79
|
+
country = (args[:country] || :general).to_sym
|
|
80
|
+
|
|
81
|
+
if args[:range].is_a?(Range)
|
|
82
|
+
min = args[:range].min
|
|
83
|
+
max = args[:range].max
|
|
84
|
+
value = rng.rand * (max - min) + min
|
|
85
|
+
value.round(2)
|
|
86
|
+
else
|
|
87
|
+
rates = TAX_RATES[country] || TAX_RATES[:general]
|
|
88
|
+
rng.sample(rates)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def generate_edge(rng, context, args)
|
|
93
|
+
[0.0, 0.25, 0.50].sample(random: rng.instance_variable_get(:@random))
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def generate_invalid(rng, context, args)
|
|
97
|
+
[nil, "abc", -0.1, 1.1, [], {}].sample(random: rng.instance_variable_get(:@random))
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# ShirtSize type
|
|
102
|
+
class ShirtSize < Base
|
|
103
|
+
SIZES = ["XS", "S", "M", "L", "XL", "XXL", "XXXL"].freeze
|
|
104
|
+
|
|
105
|
+
def generate_random(rng, context, args)
|
|
106
|
+
rng.sample(SIZES)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def generate_edge(rng, context, args)
|
|
110
|
+
["XS", "XXXL"].sample(random: rng.instance_variable_get(:@random))
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def generate_invalid(rng, context, args)
|
|
114
|
+
[nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Synthra
|
|
4
|
+
module Types
|
|
5
|
+
module CommerceProducts
|
|
6
|
+
# CompanyName type
|
|
7
|
+
class CompanyName < Base
|
|
8
|
+
# Generate random company name
|
|
9
|
+
#
|
|
10
|
+
# @param rng [Generator::RNG] random number generator (not directly used)
|
|
11
|
+
# @param context [Generator::Context] generation context
|
|
12
|
+
# @param args [Hash] type arguments (not used)
|
|
13
|
+
# @return [String] generated company name
|
|
14
|
+
#
|
|
15
|
+
def generate_random(rng, context, args)
|
|
16
|
+
adapter = faker_adapter(context)
|
|
17
|
+
if adapter
|
|
18
|
+
adapter.company_name
|
|
19
|
+
|
|
20
|
+
else
|
|
21
|
+
Faker::Company.name
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
rescue StandardError
|
|
25
|
+
rng.sample(["Acme Corp", "Tech Solutions Inc", "Global Industries"])
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def generate_edge(rng, context, args)
|
|
30
|
+
["", "A", "Very Long Company Name That Exceeds Normal Limits"].sample(random: rng.instance_variable_get(:@random))
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def generate_invalid(rng, context, args)
|
|
34
|
+
[nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# JobTitle type
|
|
39
|
+
class JobTitle < Base
|
|
40
|
+
# Generate random job title
|
|
41
|
+
#
|
|
42
|
+
# @param rng [Generator::RNG] random number generator (not directly used)
|
|
43
|
+
# @param context [Generator::Context] generation context
|
|
44
|
+
# @param args [Hash] type arguments (not used)
|
|
45
|
+
# @return [String] generated job title
|
|
46
|
+
#
|
|
47
|
+
def generate_random(rng, context, args)
|
|
48
|
+
adapter = faker_adapter(context)
|
|
49
|
+
if adapter
|
|
50
|
+
adapter.job
|
|
51
|
+
|
|
52
|
+
else
|
|
53
|
+
Faker::Job.title
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
rescue StandardError
|
|
57
|
+
rng.sample(["Software Engineer", "Product Manager", "Sales Representative"])
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def generate_edge(rng, context, args)
|
|
62
|
+
["", "A", "Very Long Job Title That Exceeds Normal Limits"].sample(random: rng.instance_variable_get(:@random))
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def generate_invalid(rng, context, args)
|
|
66
|
+
[nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|