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
data/docs/PERSONAS.md
ADDED
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
# Personas: Named Data Profiles
|
|
2
|
+
|
|
3
|
+
Personas let you define **named data profiles** that combine generation modes, field overrides, and behaviors into reusable configurations. Instead of thinking in technical terms like "edge mode" or "hostile mode," think in user archetypes: "happy path user," "free tier customer," or "problematic account."
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
# Define personas
|
|
9
|
+
FakeDataDSL::Personas.define(:happy_path) do
|
|
10
|
+
mode :random
|
|
11
|
+
override "User", email_verified: true, subscription: "premium"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
FakeDataDSL::Personas.define(:problematic) do
|
|
15
|
+
mode :hostile
|
|
16
|
+
override "User", name: "'; DROP TABLE users; --"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Use personas
|
|
20
|
+
user = FakeDataDSL.as(:happy_path) { FakeDataDSL.generate("User") }
|
|
21
|
+
hacker = FakeDataDSL.as(:problematic) { FakeDataDSL.generate("User") }
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Defining Personas
|
|
25
|
+
|
|
26
|
+
### Basic Persona
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
FakeDataDSL::Personas.define(:standard_user) do
|
|
30
|
+
mode :random
|
|
31
|
+
end
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### With Overrides
|
|
35
|
+
|
|
36
|
+
```ruby
|
|
37
|
+
FakeDataDSL::Personas.define(:premium_customer) do
|
|
38
|
+
mode :random
|
|
39
|
+
|
|
40
|
+
override "User",
|
|
41
|
+
subscription: "premium",
|
|
42
|
+
email_verified: true,
|
|
43
|
+
created_at: 1.year.ago
|
|
44
|
+
|
|
45
|
+
override "Account",
|
|
46
|
+
plan: "enterprise",
|
|
47
|
+
seats: 50
|
|
48
|
+
end
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### With Behaviors
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
FakeDataDSL::Personas.define(:slow_connection) do
|
|
55
|
+
mode :random
|
|
56
|
+
|
|
57
|
+
behavior :latency, min: 500, max: 2000 # 500-2000ms delays
|
|
58
|
+
behavior :timeout, probability: 0.1 # 10% timeout rate
|
|
59
|
+
end
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Built-in Personas
|
|
63
|
+
|
|
64
|
+
FakeDataDSL includes several built-in personas:
|
|
65
|
+
|
|
66
|
+
### :happy_path
|
|
67
|
+
|
|
68
|
+
Standard, valid data that represents the ideal user journey.
|
|
69
|
+
|
|
70
|
+
```ruby
|
|
71
|
+
FakeDataDSL.as(:happy_path) do
|
|
72
|
+
user = FakeDataDSL.generate("User")
|
|
73
|
+
# All fields valid, all required fields present
|
|
74
|
+
# Represents a "normal" user
|
|
75
|
+
end
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### :edge_case
|
|
79
|
+
|
|
80
|
+
Data at the boundaries of valid ranges.
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
FakeDataDSL.as(:edge_case) do
|
|
84
|
+
user = FakeDataDSL.generate("User")
|
|
85
|
+
# age might be 0 or 150
|
|
86
|
+
# name might be 1 character or 255 characters
|
|
87
|
+
# Tests boundary conditions
|
|
88
|
+
end
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### :minimal
|
|
92
|
+
|
|
93
|
+
Only required fields, everything else nil/empty.
|
|
94
|
+
|
|
95
|
+
```ruby
|
|
96
|
+
FakeDataDSL.as(:minimal) do
|
|
97
|
+
user = FakeDataDSL.generate("User")
|
|
98
|
+
# Only id, name, email (required fields)
|
|
99
|
+
# All optional fields are nil
|
|
100
|
+
end
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### :maximal
|
|
104
|
+
|
|
105
|
+
All fields populated, arrays at max length.
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
FakeDataDSL.as(:maximal) do
|
|
109
|
+
user = FakeDataDSL.generate("User")
|
|
110
|
+
# All optional fields populated
|
|
111
|
+
# Arrays at maximum allowed length
|
|
112
|
+
end
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### :hacker
|
|
116
|
+
|
|
117
|
+
Malicious input attempting to exploit vulnerabilities.
|
|
118
|
+
|
|
119
|
+
```ruby
|
|
120
|
+
FakeDataDSL.as(:hacker) do
|
|
121
|
+
user = FakeDataDSL.generate("User")
|
|
122
|
+
# SQL injection in text fields
|
|
123
|
+
# XSS attempts in HTML-allowed fields
|
|
124
|
+
# Path traversal in file fields
|
|
125
|
+
end
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### :international
|
|
129
|
+
|
|
130
|
+
Data with international characters and formats.
|
|
131
|
+
|
|
132
|
+
```ruby
|
|
133
|
+
FakeDataDSL.as(:international) do
|
|
134
|
+
user = FakeDataDSL.generate("User")
|
|
135
|
+
# Names in various scripts (Chinese, Arabic, Cyrillic)
|
|
136
|
+
# International phone formats
|
|
137
|
+
# Non-ASCII email addresses
|
|
138
|
+
end
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Using Personas
|
|
142
|
+
|
|
143
|
+
### Block Syntax
|
|
144
|
+
|
|
145
|
+
```ruby
|
|
146
|
+
FakeDataDSL.as(:premium_customer) do
|
|
147
|
+
user = FakeDataDSL.generate("User")
|
|
148
|
+
orders = FakeDataDSL.generate_many("Order", 5)
|
|
149
|
+
end
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Method Chaining
|
|
153
|
+
|
|
154
|
+
```ruby
|
|
155
|
+
user = FakeDataDSL.generate("User").as(:happy_path)
|
|
156
|
+
orders = FakeDataDSL.generate_many("Order", 10).as(:edge_case)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### In Tests
|
|
160
|
+
|
|
161
|
+
```ruby
|
|
162
|
+
RSpec.describe "User Registration" do
|
|
163
|
+
FakeDataDSL::Personas.each do |persona_name|
|
|
164
|
+
context "as #{persona_name}" do
|
|
165
|
+
let(:user_data) { FakeDataDSL.as(persona_name) { generate("User") } }
|
|
166
|
+
|
|
167
|
+
it "handles registration" do
|
|
168
|
+
result = UserRegistration.call(user_data)
|
|
169
|
+
# Verify behavior for each persona
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Advanced Configuration
|
|
177
|
+
|
|
178
|
+
### Persona Inheritance
|
|
179
|
+
|
|
180
|
+
```ruby
|
|
181
|
+
FakeDataDSL::Personas.define(:base_customer) do
|
|
182
|
+
mode :random
|
|
183
|
+
override "User", role: "customer"
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
FakeDataDSL::Personas.define(:new_customer, extends: :base_customer) do
|
|
187
|
+
override "User",
|
|
188
|
+
created_at: 1.day.ago,
|
|
189
|
+
first_purchase: nil
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
FakeDataDSL::Personas.define(:loyal_customer, extends: :base_customer) do
|
|
193
|
+
override "User",
|
|
194
|
+
created_at: 2.years.ago,
|
|
195
|
+
purchase_count: 50,
|
|
196
|
+
loyalty_tier: "gold"
|
|
197
|
+
end
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Conditional Overrides
|
|
201
|
+
|
|
202
|
+
```ruby
|
|
203
|
+
FakeDataDSL::Personas.define(:seasonal_shopper) do
|
|
204
|
+
mode :random
|
|
205
|
+
|
|
206
|
+
override "User" do |context|
|
|
207
|
+
if context[:month].in?([11, 12]) # Holiday season
|
|
208
|
+
{ purchase_frequency: "high", budget: 1000..5000 }
|
|
209
|
+
else
|
|
210
|
+
{ purchase_frequency: "low", budget: 50..200 }
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Dynamic Personas
|
|
217
|
+
|
|
218
|
+
```ruby
|
|
219
|
+
FakeDataDSL::Personas.define(:load_test) do |scale: 1|
|
|
220
|
+
mode :random
|
|
221
|
+
|
|
222
|
+
override "User",
|
|
223
|
+
connections: 10 * scale,
|
|
224
|
+
requests_per_minute: 100 * scale
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Usage
|
|
228
|
+
FakeDataDSL.as(:load_test, scale: 10) { ... }
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## YAML Configuration
|
|
232
|
+
|
|
233
|
+
Define personas in configuration files:
|
|
234
|
+
|
|
235
|
+
```yaml
|
|
236
|
+
# config/fake_data_dsl.yml
|
|
237
|
+
personas:
|
|
238
|
+
happy_path:
|
|
239
|
+
mode: random
|
|
240
|
+
overrides:
|
|
241
|
+
User:
|
|
242
|
+
email_verified: true
|
|
243
|
+
subscription: premium
|
|
244
|
+
|
|
245
|
+
free_user:
|
|
246
|
+
mode: random
|
|
247
|
+
overrides:
|
|
248
|
+
User:
|
|
249
|
+
subscription: free
|
|
250
|
+
created_at: 2.years.ago
|
|
251
|
+
|
|
252
|
+
problematic:
|
|
253
|
+
mode: edge
|
|
254
|
+
overrides:
|
|
255
|
+
User:
|
|
256
|
+
name: "'; DROP TABLE users; --"
|
|
257
|
+
email: test@test.test
|
|
258
|
+
|
|
259
|
+
international:
|
|
260
|
+
mode: random
|
|
261
|
+
locale: multi
|
|
262
|
+
overrides:
|
|
263
|
+
User:
|
|
264
|
+
name_locale: [zh, ar, ru, ja, ko]
|
|
265
|
+
|
|
266
|
+
# Environment-specific
|
|
267
|
+
test:
|
|
268
|
+
default_persona: happy_path
|
|
269
|
+
|
|
270
|
+
development:
|
|
271
|
+
default_persona: random
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Persona Combinations
|
|
275
|
+
|
|
276
|
+
### Multiple Personas
|
|
277
|
+
|
|
278
|
+
```ruby
|
|
279
|
+
# Combine persona traits
|
|
280
|
+
FakeDataDSL.as(:premium_customer, :international) do
|
|
281
|
+
user = FakeDataDSL.generate("User")
|
|
282
|
+
# Premium subscription + international formatting
|
|
283
|
+
end
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Persona with Mode Override
|
|
287
|
+
|
|
288
|
+
```ruby
|
|
289
|
+
# Persona as base, mode overrides specifics
|
|
290
|
+
FakeDataDSL.as(:premium_customer).mode(:edge) do
|
|
291
|
+
user = FakeDataDSL.generate("User")
|
|
292
|
+
# Premium overrides + edge case values for other fields
|
|
293
|
+
end
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Persona with Additional Overrides
|
|
297
|
+
|
|
298
|
+
```ruby
|
|
299
|
+
FakeDataDSL.as(:happy_path).override(active: false) do
|
|
300
|
+
user = FakeDataDSL.generate("User")
|
|
301
|
+
# Happy path + explicitly inactive
|
|
302
|
+
end
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## Testing Patterns
|
|
306
|
+
|
|
307
|
+
### Test All Personas
|
|
308
|
+
|
|
309
|
+
```ruby
|
|
310
|
+
RSpec.describe "API Endpoint" do
|
|
311
|
+
FakeDataDSL::Personas.all.each do |persona|
|
|
312
|
+
context "with #{persona.name} persona" do
|
|
313
|
+
let(:data) { FakeDataDSL.as(persona.name) { generate("Request") } }
|
|
314
|
+
|
|
315
|
+
it "responds successfully" do
|
|
316
|
+
post "/api/endpoint", params: data
|
|
317
|
+
expect(response).to have_http_status(:ok)
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Persona Matrix
|
|
325
|
+
|
|
326
|
+
```ruby
|
|
327
|
+
RSpec.describe "Security" do
|
|
328
|
+
# Test dangerous personas don't cause issues
|
|
329
|
+
[:hacker, :problematic, :edge_case].each do |persona|
|
|
330
|
+
context "with #{persona} data" do
|
|
331
|
+
let(:input) { FakeDataDSL.as(persona) { generate("UserInput") } }
|
|
332
|
+
|
|
333
|
+
it "sanitizes input" do
|
|
334
|
+
result = Sanitizer.clean(input)
|
|
335
|
+
expect(result).not_to include("DROP TABLE")
|
|
336
|
+
expect(result).not_to include("<script>")
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Persona-Specific Assertions
|
|
344
|
+
|
|
345
|
+
```ruby
|
|
346
|
+
RSpec.describe "Order Processing" do
|
|
347
|
+
context "as premium customer" do
|
|
348
|
+
include_persona :premium_customer
|
|
349
|
+
|
|
350
|
+
it "applies premium discount" do
|
|
351
|
+
order = FakeDataDSL.generate("Order")
|
|
352
|
+
processed = OrderProcessor.process(order, user)
|
|
353
|
+
expect(processed.discount_rate).to eq(0.15)
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
context "as free user" do
|
|
358
|
+
include_persona :free_user
|
|
359
|
+
|
|
360
|
+
it "applies no discount" do
|
|
361
|
+
order = FakeDataDSL.generate("Order")
|
|
362
|
+
processed = OrderProcessor.process(order, user)
|
|
363
|
+
expect(processed.discount_rate).to eq(0)
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
end
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## API Reference
|
|
370
|
+
|
|
371
|
+
### Personas.define
|
|
372
|
+
|
|
373
|
+
```ruby
|
|
374
|
+
FakeDataDSL::Personas.define(name, options = {}, &block)
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
**Parameters:**
|
|
378
|
+
- `name` - Symbol name for the persona
|
|
379
|
+
- `options[:extends]` - Parent persona(s) to inherit from
|
|
380
|
+
- `block` - Persona definition block
|
|
381
|
+
|
|
382
|
+
### Persona DSL Methods
|
|
383
|
+
|
|
384
|
+
Inside a persona definition block:
|
|
385
|
+
|
|
386
|
+
```ruby
|
|
387
|
+
FakeDataDSL::Personas.define(:example) do
|
|
388
|
+
# Set generation mode
|
|
389
|
+
mode :random # :random, :edge, :invalid, :hostile, :mixed
|
|
390
|
+
|
|
391
|
+
# Set locale for Faker
|
|
392
|
+
locale :en # or [:en, :de, :ja] for mixed
|
|
393
|
+
|
|
394
|
+
# Set default seed
|
|
395
|
+
seed 42
|
|
396
|
+
|
|
397
|
+
# Add field overrides for a schema
|
|
398
|
+
override "SchemaName", field: value, other_field: other_value
|
|
399
|
+
|
|
400
|
+
# Add behaviors
|
|
401
|
+
behavior :latency, min: 100, max: 500
|
|
402
|
+
behavior :failure, probability: 0.05
|
|
403
|
+
|
|
404
|
+
# Add description
|
|
405
|
+
description "A persona representing premium customers"
|
|
406
|
+
end
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### FakeDataDSL.as
|
|
410
|
+
|
|
411
|
+
```ruby
|
|
412
|
+
FakeDataDSL.as(persona_name, **options, &block)
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
**Parameters:**
|
|
416
|
+
- `persona_name` - Symbol name of the persona
|
|
417
|
+
- `options` - Override persona parameters
|
|
418
|
+
- `block` - Block to execute with persona active
|
|
419
|
+
|
|
420
|
+
**Returns:** Result of the block
|
|
421
|
+
|
|
422
|
+
### Personas.all
|
|
423
|
+
|
|
424
|
+
```ruby
|
|
425
|
+
FakeDataDSL::Personas.all
|
|
426
|
+
# => Array of all defined personas
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### Personas.find
|
|
430
|
+
|
|
431
|
+
```ruby
|
|
432
|
+
FakeDataDSL::Personas.find(:happy_path)
|
|
433
|
+
# => Persona instance
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
## Best Practices
|
|
437
|
+
|
|
438
|
+
### 1. Name Personas by User Type
|
|
439
|
+
|
|
440
|
+
```ruby
|
|
441
|
+
# Good: Descriptive user archetypes
|
|
442
|
+
:premium_customer
|
|
443
|
+
:trial_user
|
|
444
|
+
:enterprise_admin
|
|
445
|
+
:churned_customer
|
|
446
|
+
|
|
447
|
+
# Avoid: Technical descriptions
|
|
448
|
+
:random_data
|
|
449
|
+
:edge_mode_user
|
|
450
|
+
:test_data_1
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### 2. Document Persona Purpose
|
|
454
|
+
|
|
455
|
+
```ruby
|
|
456
|
+
FakeDataDSL::Personas.define(:fraud_suspect) do
|
|
457
|
+
description <<~DESC
|
|
458
|
+
A user account showing suspicious activity patterns:
|
|
459
|
+
- Multiple failed payment attempts
|
|
460
|
+
- Mismatched billing/shipping addresses
|
|
461
|
+
- Recently created account with high-value orders
|
|
462
|
+
DESC
|
|
463
|
+
|
|
464
|
+
override "User",
|
|
465
|
+
created_at: 1.day.ago,
|
|
466
|
+
failed_payments: 3,
|
|
467
|
+
billing_country: "US",
|
|
468
|
+
shipping_country: "NG"
|
|
469
|
+
end
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### 3. Keep Personas Focused
|
|
473
|
+
|
|
474
|
+
```ruby
|
|
475
|
+
# Good: Single responsibility
|
|
476
|
+
FakeDataDSL::Personas.define(:international_user) do
|
|
477
|
+
locale [:zh, :ar, :ru]
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
FakeDataDSL::Personas.define(:premium_user) do
|
|
481
|
+
override "User", subscription: "premium"
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
# Use combinations
|
|
485
|
+
FakeDataDSL.as(:international_user, :premium_user) { ... }
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
### 4. Test Coverage with Personas
|
|
489
|
+
|
|
490
|
+
```ruby
|
|
491
|
+
# Ensure critical paths are tested with multiple personas
|
|
492
|
+
CRITICAL_PERSONAS = [:happy_path, :edge_case, :hacker, :international]
|
|
493
|
+
|
|
494
|
+
RSpec.describe "Payment Processing" do
|
|
495
|
+
CRITICAL_PERSONAS.each do |persona|
|
|
496
|
+
it "handles #{persona} correctly" do
|
|
497
|
+
# Test each persona
|
|
498
|
+
end
|
|
499
|
+
end
|
|
500
|
+
end
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
## Troubleshooting
|
|
504
|
+
|
|
505
|
+
### Persona Not Found
|
|
506
|
+
|
|
507
|
+
```ruby
|
|
508
|
+
# Error: Unknown persona: :my_persona
|
|
509
|
+
|
|
510
|
+
# Fix: Define before use
|
|
511
|
+
FakeDataDSL::Personas.define(:my_persona) { ... }
|
|
512
|
+
|
|
513
|
+
# Or check available personas
|
|
514
|
+
FakeDataDSL::Personas.all.map(&:name)
|
|
515
|
+
# => [:happy_path, :edge_case, ...]
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
### Overrides Not Applied
|
|
519
|
+
|
|
520
|
+
```ruby
|
|
521
|
+
# Make sure override schema name matches exactly
|
|
522
|
+
FakeDataDSL::Personas.define(:test) do
|
|
523
|
+
override "User", active: true # ✓ Matches "User" schema
|
|
524
|
+
override "user", active: true # ✗ Case sensitive!
|
|
525
|
+
override :User, active: true # ✗ Symbol won't match string
|
|
526
|
+
end
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
### Inheritance Conflicts
|
|
530
|
+
|
|
531
|
+
```ruby
|
|
532
|
+
# Child overrides take precedence
|
|
533
|
+
FakeDataDSL::Personas.define(:parent) do
|
|
534
|
+
override "User", status: "active"
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
FakeDataDSL::Personas.define(:child, extends: :parent) do
|
|
538
|
+
override "User", status: "pending" # This wins
|
|
539
|
+
end
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
## See Also
|
|
543
|
+
|
|
544
|
+
- [Generation Modes](generation_modes.md)
|
|
545
|
+
- [Behaviors](behaviors.md)
|
|
546
|
+
- [Scenarios](SCENARIOS.md)
|
|
547
|
+
- [Factory Bot Integration](FACTORY_BOT.md)
|