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.
Files changed (302) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +4 -0
  3. data/.rubocop.yml +40 -0
  4. data/.yardopts +18 -0
  5. data/ACCESS_DOCS.md +116 -0
  6. data/ADVANCED_FEATURES_SUMMARY.md +245 -0
  7. data/CHANGELOG.md +498 -0
  8. data/CODE_OF_CONDUCT.md +122 -0
  9. data/CONTRIBUTING.md +307 -0
  10. data/DOCUMENTATION.md +204 -0
  11. data/DOCUMENTATION_GUIDE.md +194 -0
  12. data/LICENSE +22 -0
  13. data/README.md +1458 -0
  14. data/Rakefile +128 -0
  15. data/benchmark/README.md +591 -0
  16. data/benchmark/batch_generation.rb +63 -0
  17. data/benchmark/engine_comparison.rb +295 -0
  18. data/benchmark/single_record.rb +108 -0
  19. data/benchmark/streaming.rb +74 -0
  20. data/docs/ACTIVERECORD_INFERENCE.md +524 -0
  21. data/docs/API_SERVER.md +278 -0
  22. data/docs/CONFIG_FILE.md +315 -0
  23. data/docs/DATA_CONTRACTS.md +312 -0
  24. data/docs/ENHANCED_REPL.md +304 -0
  25. data/docs/FACTORY_BOT.md +271 -0
  26. data/docs/GITHUB_ACTION.md +420 -0
  27. data/docs/GRAPHQL_EXPORT.md +303 -0
  28. data/docs/GRAPHQL_FEDERATION.md +651 -0
  29. data/docs/HOW_TO_GENERATE_DOCS.md +252 -0
  30. data/docs/LSP.md +189 -0
  31. data/docs/MIGRATION_GENERATOR.md +547 -0
  32. data/docs/MOCK_SERVER.md +280 -0
  33. data/docs/NATIVE_ENGINE.md +298 -0
  34. data/docs/OPENAPI_EXPORT.md +252 -0
  35. data/docs/PERFORMANCE_MODE.md +228 -0
  36. data/docs/PERSONAS.md +547 -0
  37. data/docs/PROPERTY_TESTING.md +284 -0
  38. data/docs/PROTOBUF_EXPORT.md +276 -0
  39. data/docs/QUALITY_METRICS.md +555 -0
  40. data/docs/QUICK_REFERENCE.md +88 -0
  41. data/docs/RAILS_ENGINE.md +404 -0
  42. data/docs/RAILS_INTEGRATION.md +454 -0
  43. data/docs/README.md +175 -0
  44. data/docs/REPL_QUICK_REFERENCE.md +149 -0
  45. data/docs/RUST_INTEGRATION_GUIDE.md +1376 -0
  46. data/docs/SCENARIOS.md +576 -0
  47. data/docs/SECURITY_TESTING.md +318 -0
  48. data/docs/SNAPSHOT_TESTING.md +308 -0
  49. data/docs/STRING_TEXT_TYPES_REFERENCE.md +512 -0
  50. data/docs/TERRAFORM_EXPORT.md +447 -0
  51. data/docs/TIME_TRAVEL.md +507 -0
  52. data/docs/USAGE_GUIDE.md +980 -0
  53. data/docs/WEBHOOK_SIMULATOR.md +579 -0
  54. data/docs/advanced_features.md +183 -0
  55. data/docs/api_reference.md +153 -0
  56. data/docs/behaviors.md +138 -0
  57. data/docs/best_practices.md +191 -0
  58. data/docs/dsl_reference.md +172 -0
  59. data/docs/examples.md +162 -0
  60. data/docs/generation_modes.md +125 -0
  61. data/docs/getting_started.md +92 -0
  62. data/docs/index.html +177 -0
  63. data/docs/strategic/CLOUD_REGISTRY_ARCHITECTURE.md +268 -0
  64. data/docs/strategic/SIMD_OPTIMIZATION_STRATEGY.md +153 -0
  65. data/docs/troubleshooting.md +215 -0
  66. data/docs/type_reference.md +224 -0
  67. data/examples/hostile_mode_demo.rb +64 -0
  68. data/exe/synthra +6 -0
  69. data/ext/synthra_native/Cargo.lock +972 -0
  70. data/ext/synthra_native/Cargo.toml +46 -0
  71. data/ext/synthra_native/extconf.rb +41 -0
  72. data/ext/synthra_native/src/generator.rs +397 -0
  73. data/ext/synthra_native/src/lib.rs +229 -0
  74. data/ext/synthra_native/src/types.rs +1485 -0
  75. data/lib/generators/synthra/install_generator.rb +86 -0
  76. data/lib/generators/synthra/templates/api_response.dsl +15 -0
  77. data/lib/generators/synthra/templates/fake_data.rake +116 -0
  78. data/lib/generators/synthra/templates/synthra.yml +31 -0
  79. data/lib/generators/synthra/templates/synthra_support.rb +19 -0
  80. data/lib/generators/synthra/templates/user.dsl +11 -0
  81. data/lib/synthra/activerecord_inference.rb +394 -0
  82. data/lib/synthra/api.rb +381 -0
  83. data/lib/synthra/api_server.rb +718 -0
  84. data/lib/synthra/behaviors/applicator.rb +165 -0
  85. data/lib/synthra/behaviors/base.rb +155 -0
  86. data/lib/synthra/behaviors/close_connection.rb +60 -0
  87. data/lib/synthra/behaviors/deprecated.rb +100 -0
  88. data/lib/synthra/behaviors/failure.rb +69 -0
  89. data/lib/synthra/behaviors/latency.rb +103 -0
  90. data/lib/synthra/behaviors/partial_data.rb +83 -0
  91. data/lib/synthra/behaviors/randomize_order.rb +74 -0
  92. data/lib/synthra/behaviors/registry.rb +238 -0
  93. data/lib/synthra/behaviors/simulate_error.rb +79 -0
  94. data/lib/synthra/cli/commands/base.rb +105 -0
  95. data/lib/synthra/cli/commands/diff.rb +227 -0
  96. data/lib/synthra/cli/commands/docs.rb +67 -0
  97. data/lib/synthra/cli/commands/export.rb +150 -0
  98. data/lib/synthra/cli/commands/generate.rb +72 -0
  99. data/lib/synthra/cli/commands/import.rb +80 -0
  100. data/lib/synthra/cli/commands/lint.rb +53 -0
  101. data/lib/synthra/cli/commands/live.rb +57 -0
  102. data/lib/synthra/cli/commands/seed.rb +99 -0
  103. data/lib/synthra/cli/commands/validate.rb +28 -0
  104. data/lib/synthra/cli.rb +2471 -0
  105. data/lib/synthra/config_file.rb +129 -0
  106. data/lib/synthra/configuration.rb +281 -0
  107. data/lib/synthra/contracts_registry.rb +408 -0
  108. data/lib/synthra/database_seeder.rb +268 -0
  109. data/lib/synthra/deterministic_ids.rb +218 -0
  110. data/lib/synthra/documentation_generator.rb +414 -0
  111. data/lib/synthra/engine.rb +251 -0
  112. data/lib/synthra/errors.rb +1169 -0
  113. data/lib/synthra/export/base.rb +85 -0
  114. data/lib/synthra/export/csv.rb +101 -0
  115. data/lib/synthra/export/graphql.rb +266 -0
  116. data/lib/synthra/export/graphql_federation.rb +377 -0
  117. data/lib/synthra/export/graphviz.rb +258 -0
  118. data/lib/synthra/export/javascript.rb +327 -0
  119. data/lib/synthra/export/json_data.rb +61 -0
  120. data/lib/synthra/export/json_schema.rb +290 -0
  121. data/lib/synthra/export/openapi.rb +514 -0
  122. data/lib/synthra/export/protobuf.rb +483 -0
  123. data/lib/synthra/export/python.rb +560 -0
  124. data/lib/synthra/export/sql.rb +381 -0
  125. data/lib/synthra/export/sql_insert.rb +152 -0
  126. data/lib/synthra/export/terraform.rb +501 -0
  127. data/lib/synthra/export/type_mapping.rb +389 -0
  128. data/lib/synthra/export/typescript.rb +300 -0
  129. data/lib/synthra/export/xml_data.rb +104 -0
  130. data/lib/synthra/export/yaml_data.rb +56 -0
  131. data/lib/synthra/export.rb +404 -0
  132. data/lib/synthra/factory_bot_integration.rb +157 -0
  133. data/lib/synthra/field.rb +440 -0
  134. data/lib/synthra/functions/registry.rb +104 -0
  135. data/lib/synthra/generator/context.rb +372 -0
  136. data/lib/synthra/generator/engine.rb +336 -0
  137. data/lib/synthra/generator/faker_adapter.rb +425 -0
  138. data/lib/synthra/generator/modes.rb +444 -0
  139. data/lib/synthra/generator/resolver.rb +256 -0
  140. data/lib/synthra/generator/rng.rb +273 -0
  141. data/lib/synthra/generator/streamer.rb +63 -0
  142. data/lib/synthra/generator/uniqueness.rb +118 -0
  143. data/lib/synthra/initializer.rb +97 -0
  144. data/lib/synthra/limits.rb +279 -0
  145. data/lib/synthra/live_preview.rb +518 -0
  146. data/lib/synthra/loader_config.rb +78 -0
  147. data/lib/synthra/lsp/server.rb +689 -0
  148. data/lib/synthra/migration_generator.rb +301 -0
  149. data/lib/synthra/mixin.rb +174 -0
  150. data/lib/synthra/mock_server.rb +458 -0
  151. data/lib/synthra/native_engine.rb +304 -0
  152. data/lib/synthra/openapi_importer.rb +228 -0
  153. data/lib/synthra/output/json_formatter.rb +40 -0
  154. data/lib/synthra/output/ndjson_formatter.rb +55 -0
  155. data/lib/synthra/parser/ast.rb +1287 -0
  156. data/lib/synthra/parser/lexer.rb +1152 -0
  157. data/lib/synthra/parser/parser.rb +1664 -0
  158. data/lib/synthra/parser/tokens.rb +461 -0
  159. data/lib/synthra/performance_mode.rb +364 -0
  160. data/lib/synthra/personas.rb +397 -0
  161. data/lib/synthra/property_testing.rb +172 -0
  162. data/lib/synthra/quality_metrics.rb +405 -0
  163. data/lib/synthra/rails_test_helper.rb +248 -0
  164. data/lib/synthra/registry.rb +533 -0
  165. data/lib/synthra/relationships.rb +193 -0
  166. data/lib/synthra/repl/enhanced_repl.rb +607 -0
  167. data/lib/synthra/repl/formatter.rb +191 -0
  168. data/lib/synthra/scenarios.rb +423 -0
  169. data/lib/synthra/schema.rb +605 -0
  170. data/lib/synthra/schema_inheritance.rb +104 -0
  171. data/lib/synthra/schema_versioning.rb +212 -0
  172. data/lib/synthra/snapshot_testing.rb +199 -0
  173. data/lib/synthra/time_travel.rb +338 -0
  174. data/lib/synthra/type_definitions.rb +274 -0
  175. data/lib/synthra/types/address_location/addresses.rb +125 -0
  176. data/lib/synthra/types/address_location/airports.rb +200 -0
  177. data/lib/synthra/types/address_location/banks_hospitals.rb +207 -0
  178. data/lib/synthra/types/address_location/locations.rb +406 -0
  179. data/lib/synthra/types/base.rb +48 -0
  180. data/lib/synthra/types/commerce_products/commerce.rb +119 -0
  181. data/lib/synthra/types/commerce_products/companies.rb +71 -0
  182. data/lib/synthra/types/commerce_products/construction.rb +126 -0
  183. data/lib/synthra/types/commerce_products/products.rb +205 -0
  184. data/lib/synthra/types/core/collections.rb +513 -0
  185. data/lib/synthra/types/core/defaults.rb +76 -0
  186. data/lib/synthra/types/core/enums.rb +102 -0
  187. data/lib/synthra/types/core/identifiers.rb +445 -0
  188. data/lib/synthra/types/core/primitives.rb +586 -0
  189. data/lib/synthra/types/core/references.rb +466 -0
  190. data/lib/synthra/types/core/sequences.rb +304 -0
  191. data/lib/synthra/types/crypto/crypto.rb +162 -0
  192. data/lib/synthra/types/date_time/dates.rb +387 -0
  193. data/lib/synthra/types/finance_banking/banking.rb +424 -0
  194. data/lib/synthra/types/finance_banking/credit_cards.rb +24 -0
  195. data/lib/synthra/types/finance_banking/identifiers.rb +93 -0
  196. data/lib/synthra/types/formula.rb +184 -0
  197. data/lib/synthra/types/health_medical/medical.rb +150 -0
  198. data/lib/synthra/types/hostile_payloads.rb +122 -0
  199. data/lib/synthra/types/json_array.rb +51 -0
  200. data/lib/synthra/types/media_entertainment/media.rb +62 -0
  201. data/lib/synthra/types/naughty_string.rb +30 -0
  202. data/lib/synthra/types/personal_names/chinese.rb +41 -0
  203. data/lib/synthra/types/personal_names/identifiers.rb +187 -0
  204. data/lib/synthra/types/personal_names/names.rb +246 -0
  205. data/lib/synthra/types/personal_names/national_id.rb +89 -0
  206. data/lib/synthra/types/personal_names/titles_suffixes.rb +41 -0
  207. data/lib/synthra/types/regex.rb +248 -0
  208. data/lib/synthra/types/registry.rb +182 -0
  209. data/lib/synthra/types/repeating_element.rb +50 -0
  210. data/lib/synthra/types/scenario.rb +29 -0
  211. data/lib/synthra/types/technology_internet/apps.rb +67 -0
  212. data/lib/synthra/types/technology_internet/communication.rb +162 -0
  213. data/lib/synthra/types/technology_internet/devices.rb +80 -0
  214. data/lib/synthra/types/technology_internet/formats.rb +139 -0
  215. data/lib/synthra/types/technology_internet/networking.rb +143 -0
  216. data/lib/synthra/types/template.rb +92 -0
  217. data/lib/synthra/types/text_content/business.rb +128 -0
  218. data/lib/synthra/types/text_content/colors.rb +70 -0
  219. data/lib/synthra/types/text_content/misc.rb +237 -0
  220. data/lib/synthra/types/text_content/security.rb +130 -0
  221. data/lib/synthra/types/text_content/text_generation.rb +532 -0
  222. data/lib/synthra/types/travel/travel.rb +150 -0
  223. data/lib/synthra/utils/string_distance.rb +133 -0
  224. data/lib/synthra/validator/dsl_validator.rb +339 -0
  225. data/lib/synthra/validator/path_validator.rb +615 -0
  226. data/lib/synthra/version.rb +35 -0
  227. data/lib/synthra/webhook_simulator.rb +341 -0
  228. data/lib/synthra.rb +259 -0
  229. data/schemas/address.dsl +16 -0
  230. data/schemas/api_response.dsl +8 -0
  231. data/schemas/error_payload.dsl +9 -0
  232. data/schemas/order.dsl +10 -0
  233. data/schemas/order_item.dsl +8 -0
  234. data/schemas/payment.dsl +11 -0
  235. data/schemas/social_post.dsl +13 -0
  236. data/schemas/user.dsl +10 -0
  237. data/scripts/batch_fix_all.rb +96 -0
  238. data/scripts/delete_old_files.rb +32 -0
  239. data/scripts/fix_all_grouped_files.rb +137 -0
  240. data/scripts/fix_all_indentation.rb +48 -0
  241. data/scripts/fix_all_syntax.rb +124 -0
  242. data/scripts/fix_grouped_files.rb +184 -0
  243. data/scripts/fix_syntax_errors.rb +108 -0
  244. data/scripts/group_domain_types.rb +112 -0
  245. data/scripts/group_domain_types_fixed.rb +150 -0
  246. data/scripts/merge_domains_to_one_file.rb +68 -0
  247. data/scripts/move_existing_types.rb +130 -0
  248. data/scripts/split_grouped_types.rb +142 -0
  249. data/tech_docs/README.md +134 -0
  250. data/tech_docs/advanced/streaming.md +405 -0
  251. data/tech_docs/advanced/thread_safety.md +253 -0
  252. data/tech_docs/api/overview.md +485 -0
  253. data/tech_docs/appendices/type_chart.md +193 -0
  254. data/tech_docs/basic_concepts.md +383 -0
  255. data/tech_docs/behaviors/overview.md +346 -0
  256. data/tech_docs/dsl/complex_types.md +790 -0
  257. data/tech_docs/dsl/core_types.md +464 -0
  258. data/tech_docs/dsl/datetime_types.md +325 -0
  259. data/tech_docs/dsl/field_modifiers.md +414 -0
  260. data/tech_docs/dsl/grammar.md +431 -0
  261. data/tech_docs/dsl/schema_definition.md +399 -0
  262. data/tech_docs/export/README.md +276 -0
  263. data/tech_docs/installation.md +273 -0
  264. data/tech_docs/integration/ci_cd.md +707 -0
  265. data/tech_docs/integration/ci_cd_guide.md +579 -0
  266. data/tech_docs/integration/factory_bot.md +485 -0
  267. data/tech_docs/integration/rails.md +630 -0
  268. data/tech_docs/integration/rspec.md +449 -0
  269. data/tech_docs/modes/overview.md +350 -0
  270. data/tech_docs/performance/NATIVE_RUST_EXTENSION.md +1270 -0
  271. data/tech_docs/performance/OPTIMIZATION_GUIDE.md +901 -0
  272. data/tech_docs/quick_start.md +256 -0
  273. data/tech_docs/templates/README.md +805 -0
  274. data/tech_docs/tutorials/advanced.md +371 -0
  275. data/tech_docs/tutorials/getting_started.md +189 -0
  276. data/tech_docs/tutorials/intermediate.md +231 -0
  277. data/tech_docs/tutorials/template_gallery.md +569 -0
  278. data/tech_example/01_basic_usage.rb +238 -0
  279. data/tech_example/02_types_demo.rb +336 -0
  280. data/tech_example/04_cli_usage.md +429 -0
  281. data/tech_example/05_database_seeding.rb +283 -0
  282. data/tech_example/07_rspec_integration.rb +359 -0
  283. data/tech_example/10_custom_types.rb +387 -0
  284. data/tech_example/12_behaviors.rb +372 -0
  285. data/tech_example/13_twitter_dm_example.rb +120 -0
  286. data/tech_example/14_exact_json_structure.rb +253 -0
  287. data/tech_example/16_lsp_server.rb +56 -0
  288. data/tech_example/17_property_testing.rb +92 -0
  289. data/tech_example/18_enhanced_repl.rb +120 -0
  290. data/tech_example/19_security_fuzzing.rb +145 -0
  291. data/tech_example/NEW_FEATURES.md +169 -0
  292. data/tech_example/README.md +118 -0
  293. data/tech_example/schemas/api_response.dsl +123 -0
  294. data/tech_example/schemas/ecommerce.dsl +121 -0
  295. data/tech_example/schemas/twitter_dm.dsl +109 -0
  296. data/tech_example/schemas/user.dsl +36 -0
  297. data/vscode-extension/README.md +246 -0
  298. data/vscode-extension/language-configuration.json +31 -0
  299. data/vscode-extension/package.json +55 -0
  300. data/vscode-extension/snippets/fakedatadsl.json +198 -0
  301. data/vscode-extension/syntaxes/fakedatadsl.tmLanguage.json +128 -0
  302. metadata +478 -0
@@ -0,0 +1,284 @@
1
+ # Property-Based Testing
2
+
3
+ FakeDataDSL integrates seamlessly with RSpec for property-based testing, allowing you to verify that properties hold for all generated data.
4
+
5
+ ## Quick Start
6
+
7
+ ```ruby
8
+ require 'fake_data_dsl'
9
+ include FakeDataDSL::PropertyTesting
10
+
11
+ RSpec.describe "User Registration" do
12
+ it "accepts all valid users" do
13
+ verify_property("User", count: 1000) do |user_data|
14
+ user = User.create(user_data)
15
+ expect(user).to be_valid
16
+ expect(user.save).to be_truthy
17
+ end
18
+ end
19
+ end
20
+ ```
21
+
22
+ ## Features
23
+
24
+ ### verify_property
25
+
26
+ Verifies a property holds for multiple generated records:
27
+
28
+ ```ruby
29
+ verify_property("User", count: 100) do |user_data|
30
+ expect(user_data["email"]).to match(/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i)
31
+ expect(user_data["age"]).to be_between(18, 80)
32
+ end
33
+ ```
34
+
35
+ **Options:**
36
+ - `count` - Number of records to generate (default: 100)
37
+ - `seed` - Random seed for reproducibility
38
+ - `mode` - Generation mode (`:random`, `:edge`, `:invalid`, `:hostile`, `:mixed`)
39
+ - `registry` - Custom schema registry
40
+
41
+ ### verify_property_stream
42
+
43
+ Memory-efficient streaming verification for large counts:
44
+
45
+ ```ruby
46
+ verify_property_stream("User", count: 10_000) do |user_data|
47
+ expect(user_data["id"]).to be_a(String)
48
+ end
49
+ ```
50
+
51
+ Records are generated lazily and garbage collected as they're processed.
52
+
53
+ ### shrink_counterexample
54
+
55
+ Shrinks a failing test case to find a minimal counterexample:
56
+
57
+ ```ruby
58
+ failing_record = schema.generate(mode: :hostile)
59
+
60
+ minimal = shrink_counterexample("User", failing_record) do |record|
61
+ expect(record["age"]).to be > 100 # This will fail
62
+ end
63
+
64
+ # minimal contains the smallest record that still fails
65
+ ```
66
+
67
+ ## Examples
68
+
69
+ ### Email Format Validation
70
+
71
+ ```ruby
72
+ verify_property("User", count: 1000) do |user_data|
73
+ email = user_data["email"]
74
+ expect(email).to match(/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i)
75
+ end
76
+ ```
77
+
78
+ ### Age Range Validation
79
+
80
+ ```ruby
81
+ verify_property("User", count: 1000) do |user_data|
82
+ age = user_data["age"]
83
+ expect(age).to be_between(18, 80)
84
+ end
85
+ ```
86
+
87
+ ### UUID Format Validation
88
+
89
+ ```ruby
90
+ verify_property("User", count: 1000) do |user_data|
91
+ uuid = user_data["id"]
92
+ expect(uuid).to match(/\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/i)
93
+ end
94
+ ```
95
+
96
+ ### Model Validation
97
+
98
+ ```ruby
99
+ verify_property("User", count: 500) do |user_data|
100
+ user = User.new(user_data)
101
+ expect(user).to be_valid
102
+ end
103
+ ```
104
+
105
+ ### API Endpoint Testing
106
+
107
+ ```ruby
108
+ verify_property("Order", count: 200) do |order_data|
109
+ response = post("/api/orders", order_data)
110
+ expect(response.status).to eq(201)
111
+ expect(response.json["id"]).to be_present
112
+ end
113
+ ```
114
+
115
+ ### Deterministic Testing
116
+
117
+ ```ruby
118
+ seed = 12345
119
+
120
+ verify_property("User", count: 100, seed: seed) do |user_data|
121
+ # Same seed = same data every time
122
+ expect(user_data["email"]).to eq(expected_email)
123
+ end
124
+ ```
125
+
126
+ ## Error Messages
127
+
128
+ When a property fails, you get detailed error information:
129
+
130
+ ```
131
+ Property failed for record 42/100 (seed: 12345):
132
+ expected 25 to be > 100
133
+ Record: {"id"=>"550e8400...", "age"=>25, ...}
134
+ ```
135
+
136
+ This includes:
137
+ - Record index (which record failed)
138
+ - Seed (for reproducibility)
139
+ - Full error message
140
+ - Complete record data
141
+
142
+ ## Best Practices
143
+
144
+ ### 1. Use Appropriate Counts
145
+
146
+ ```ruby
147
+ # Quick validation (fast)
148
+ verify_property("User", count: 10) do |user_data|
149
+ expect(user_data).to be_a(Hash)
150
+ end
151
+
152
+ # Comprehensive testing (thorough)
153
+ verify_property("User", count: 1000) do |user_data|
154
+ expect(user_data["email"]).to match(/@/)
155
+ end
156
+ ```
157
+
158
+ ### 2. Use Seeds for Reproducibility
159
+
160
+ ```ruby
161
+ # Same seed = same data = reproducible tests
162
+ verify_property("User", count: 100, seed: 42) do |user_data|
163
+ # Test logic
164
+ end
165
+ ```
166
+
167
+ ### 3. Use Streaming for Large Counts
168
+
169
+ ```ruby
170
+ # Memory-efficient for 10K+ records
171
+ verify_property_stream("User", count: 50_000) do |user_data|
172
+ expect(user_data["id"]).to be_present
173
+ end
174
+ ```
175
+
176
+ ### 4. Test Edge Cases
177
+
178
+ ```ruby
179
+ # Test with edge case mode
180
+ verify_property("User", count: 100, mode: :edge) do |user_data|
181
+ # Should handle empty strings, nulls, extremes
182
+ expect(user_data["email"]).to be_a(String).or(be_nil)
183
+ end
184
+ ```
185
+
186
+ ### 5. Test Invalid Data Handling
187
+
188
+ ```ruby
189
+ # Test validation logic
190
+ verify_property("User", count: 100, mode: :invalid) do |user_data|
191
+ # Should reject invalid data
192
+ user = User.new(user_data)
193
+ expect(user).not_to be_valid
194
+ end
195
+ ```
196
+
197
+ ## Integration with RSpec
198
+
199
+ The `PropertyTesting` module is automatically included in RSpec when available:
200
+
201
+ ```ruby
202
+ # No need to include manually
203
+ RSpec.describe "User" do
204
+ it "validates all users" do
205
+ verify_property("User") do |user_data|
206
+ # Test logic
207
+ end
208
+ end
209
+ end
210
+ ```
211
+
212
+ ## Advanced Usage
213
+
214
+ ### Custom Registry
215
+
216
+ ```ruby
217
+ custom_registry = FakeDataDSL::Registry.new
218
+ custom_registry.load_dir("spec/schemas/")
219
+
220
+ verify_property("User", count: 100, registry: custom_registry) do |user_data|
221
+ # Test logic
222
+ end
223
+ ```
224
+
225
+ ### Multiple Properties
226
+
227
+ ```ruby
228
+ RSpec.describe "User" do
229
+ it "validates email format" do
230
+ verify_property("User", count: 100) do |user_data|
231
+ expect(user_data["email"]).to match(/@/)
232
+ end
233
+ end
234
+
235
+ it "validates age range" do
236
+ verify_property("User", count: 100) do |user_data|
237
+ expect(user_data["age"]).to be_between(18, 80)
238
+ end
239
+ end
240
+ end
241
+ ```
242
+
243
+ ### Shrinking Counterexamples
244
+
245
+ ```ruby
246
+ it "finds minimal failing case" do
247
+ failing_record = {
248
+ "id" => "test",
249
+ "name" => "Test",
250
+ "email" => "test@example.com",
251
+ "age" => 25,
252
+ "optional_field" => "can be removed"
253
+ }
254
+
255
+ minimal = shrink_counterexample("User", failing_record) do |record|
256
+ expect(record["age"]).to be > 100
257
+ end
258
+
259
+ # minimal may have optional_field removed if it still fails
260
+ expect(minimal["age"]).to be <= 100
261
+ end
262
+ ```
263
+
264
+ ## Performance
265
+
266
+ Property-based testing is efficient:
267
+
268
+ - **100 records**: ~0.1s
269
+ - **1,000 records**: ~1s
270
+ - **10,000 records**: ~10s (use streaming)
271
+
272
+ Use `verify_property_stream` for counts > 1,000 to avoid memory issues.
273
+
274
+ ## Limitations
275
+
276
+ - Requires RSpec (automatically detected)
277
+ - Shrinking is basic (removes optional fields, simplifies arrays)
278
+ - No automatic property discovery (you must write properties)
279
+
280
+ ## See Also
281
+
282
+ - [RSpec Integration Guide](tech_docs/integration/rspec.md)
283
+ - [Generation Modes](tech_docs/modes/overview.md)
284
+ - [API Reference](tech_docs/api/overview.md)
@@ -0,0 +1,276 @@
1
+ # gRPC/Protobuf Export
2
+
3
+ Export your FakeDataDSL schemas to **Protocol Buffer definitions** for use with gRPC microservices.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # Export single schema
9
+ fake_data_dsl export User -d schemas/ -f protobuf -o user.proto
10
+
11
+ # Export all schemas
12
+ fake_data_dsl export --all -d schemas/ -f protobuf -o all.proto
13
+ ```
14
+
15
+ ## Generated Output
16
+
17
+ For this schema:
18
+
19
+ ```
20
+ User:
21
+ id: uuid
22
+ name: name
23
+ email: email
24
+ age: number(18..65)
25
+ active: boolean
26
+ role: enum(admin, user, moderator)
27
+ ```
28
+
29
+ The exporter generates:
30
+
31
+ ```protobuf
32
+ syntax = "proto3";
33
+
34
+ package generated;
35
+
36
+ import "google/protobuf/timestamp.proto";
37
+
38
+ enum UserRole {
39
+ USERROLE_UNSPECIFIED = 0;
40
+ USERROLE_ADMIN = 1;
41
+ USERROLE_USER = 2;
42
+ USERROLE_MODERATOR = 3;
43
+ }
44
+
45
+ message User {
46
+ string id = 1;
47
+ string name = 2;
48
+ string email = 3;
49
+ int64 age = 4;
50
+ bool active = 5;
51
+ UserRole role = 6;
52
+ }
53
+
54
+ service UserService {
55
+ rpc GetUser(GetUserRequest) returns (User);
56
+ rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
57
+ rpc GenerateUser(GenerateUserRequest) returns (User);
58
+ rpc GenerateManyUsers(GenerateManyUsersRequest) returns (stream User);
59
+ }
60
+
61
+ message GetUserRequest {
62
+ string id = 1;
63
+ }
64
+
65
+ message ListUsersRequest {
66
+ int32 page = 1;
67
+ int32 page_size = 2;
68
+ }
69
+
70
+ message ListUsersResponse {
71
+ repeated User users = 1;
72
+ int32 total_count = 2;
73
+ int32 page = 3;
74
+ int32 page_size = 4;
75
+ }
76
+
77
+ message GenerateUserRequest {
78
+ optional int64 seed = 1;
79
+ optional string mode = 2;
80
+ map<string, string> overrides = 3;
81
+ }
82
+
83
+ message GenerateManyUsersRequest {
84
+ int32 count = 1;
85
+ optional int64 seed = 2;
86
+ optional string mode = 3;
87
+ }
88
+ ```
89
+
90
+ ## Ruby API
91
+
92
+ ### Single Schema
93
+
94
+ ```ruby
95
+ schema = FakeDataDSL.load("schemas/user.dsl")
96
+
97
+ exporter = FakeDataDSL::Export::Protobuf.new(
98
+ schema,
99
+ registry: registry,
100
+ package: "myapp.v1",
101
+ go_package: "github.com/myapp/proto/v1",
102
+ with_service: true
103
+ )
104
+
105
+ proto = exporter.export
106
+ File.write("user.proto", proto)
107
+ ```
108
+
109
+ ### All Schemas
110
+
111
+ ```ruby
112
+ proto = FakeDataDSL::Export::Protobuf.export_all(
113
+ registry,
114
+ package: "myapp.v1",
115
+ go_package: "github.com/myapp/proto/v1",
116
+ with_service: true
117
+ )
118
+
119
+ File.write("all.proto", proto)
120
+ ```
121
+
122
+ ## Options
123
+
124
+ | Option | Description | Default |
125
+ |--------|-------------|---------|
126
+ | `package` | Proto package name | "generated" |
127
+ | `go_package` | Go package path | nil |
128
+ | `syntax` | Proto syntax version | "proto3" |
129
+ | `with_service` | Generate gRPC service | true |
130
+
131
+ ## Type Mapping
132
+
133
+ | FakeDataDSL | Protobuf |
134
+ |-------------|----------|
135
+ | `text`, `name`, `email`, etc. | `string` |
136
+ | `uuid`, `ulid`, `nanoid` | `string` |
137
+ | `number`, `integer` | `int64` |
138
+ | `int`, `int32` | `int32` |
139
+ | `float`, `double`, `money` | `double` |
140
+ | `boolean` | `bool` |
141
+ | `timestamp`, `datetime` | `google.protobuf.Timestamp` |
142
+ | `date`, `time` | `string` |
143
+ | `binary`, `base64` | `bytes` |
144
+ | `array(T)` | `repeated T` |
145
+ | `enum(a, b, c)` | Custom enum |
146
+ | `SchemaRef` | Message reference |
147
+
148
+ ## Arrays
149
+
150
+ Arrays map to `repeated` fields:
151
+
152
+ ```
153
+ Tags:
154
+ items: array(text, 1..10)
155
+ ```
156
+
157
+ Becomes:
158
+
159
+ ```protobuf
160
+ message Tags {
161
+ repeated string items = 1;
162
+ }
163
+ ```
164
+
165
+ ## Nested Schemas
166
+
167
+ Schema references become message references:
168
+
169
+ ```
170
+ Address:
171
+ street: street
172
+ city: city
173
+
174
+ Person:
175
+ name: name
176
+ address: Address
177
+ ```
178
+
179
+ Becomes:
180
+
181
+ ```protobuf
182
+ message Address {
183
+ string street = 1;
184
+ string city = 2;
185
+ }
186
+
187
+ message Person {
188
+ string name = 1;
189
+ Address address = 2;
190
+ }
191
+ ```
192
+
193
+ ## Enums
194
+
195
+ Enums are extracted and generated separately:
196
+
197
+ ```
198
+ User:
199
+ role: enum(admin, user, moderator)
200
+ ```
201
+
202
+ Becomes:
203
+
204
+ ```protobuf
205
+ enum UserRole {
206
+ USERROLE_UNSPECIFIED = 0; // Required zero value
207
+ USERROLE_ADMIN = 1;
208
+ USERROLE_USER = 2;
209
+ USERROLE_MODERATOR = 3;
210
+ }
211
+
212
+ message User {
213
+ UserRole role = 1;
214
+ }
215
+ ```
216
+
217
+ ## Using with gRPC
218
+
219
+ 1. Generate the .proto file:
220
+ ```bash
221
+ fake_data_dsl export --all -d schemas/ -f protobuf -o service.proto
222
+ ```
223
+
224
+ 2. Compile to your language:
225
+ ```bash
226
+ # Go
227
+ protoc --go_out=. --go-grpc_out=. service.proto
228
+
229
+ # Ruby
230
+ grpc_tools_ruby_protoc --ruby_out=. --grpc_out=. service.proto
231
+
232
+ # Python
233
+ python -m grpc_tools.protoc --python_out=. --grpc_python_out=. service.proto
234
+ ```
235
+
236
+ 3. Implement the service using FakeDataDSL for data generation.
237
+
238
+ ## Example gRPC Server (Ruby)
239
+
240
+ ```ruby
241
+ require 'grpc'
242
+ require_relative 'service_services_pb'
243
+ require 'fake_data_dsl'
244
+
245
+ class DataGenerationService < Generated::DataGenerationService::Service
246
+ def initialize
247
+ @registry = FakeDataDSL::Registry.new
248
+ @registry.load_dir("schemas/")
249
+ end
250
+
251
+ def generate_user(request, _call)
252
+ schema = @registry.schema("User")
253
+ data = schema.generate(
254
+ seed: request.seed.zero? ? nil : request.seed,
255
+ mode: request.mode.empty? ? :random : request.mode.to_sym
256
+ )
257
+
258
+ Generated::User.new(data)
259
+ end
260
+
261
+ def generate_many_users(request, _call)
262
+ schema = @registry.schema("User")
263
+
264
+ return enum_for(:generate_many_users, request, _call) unless block_given?
265
+
266
+ schema.generate_stream(count: request.count).each do |data|
267
+ yield Generated::User.new(data)
268
+ end
269
+ end
270
+ end
271
+
272
+ server = GRPC::RpcServer.new
273
+ server.add_http2_port('0.0.0.0:50051', :this_port_is_insecure)
274
+ server.handle(DataGenerationService.new)
275
+ server.run_till_terminated
276
+ ```