├── .gitattributes ├── .gitignore ├── DataGenerator.sln ├── LICENSE ├── README.md ├── appveyor.yml ├── build ├── common.props ├── sourcelink.props └── version.props ├── logo.png ├── src └── DataGenerator │ ├── AssemblyResolver.cs │ ├── ClassMapping.cs │ ├── Configuration.cs │ ├── DataGenerator.csproj │ ├── Extensions │ ├── AssemblyExtensions.cs │ └── RandomExtensions.cs │ ├── Fluent │ ├── ClassMappingBuilder.cs │ ├── ConfigurationBuilder.cs │ ├── ListGeneratorBuilder.cs │ └── MemberConfigurationBuilder.cs │ ├── GenerateContext.cs │ ├── Generator.cs │ ├── IDataSource.cs │ ├── IDataSourceDiscover.cs │ ├── IGenerateContext.cs │ ├── IMappingContext.cs │ ├── IMappingProfile.cs │ ├── MappingContext.cs │ ├── MappingProfile.cs │ ├── MemberMapping.cs │ ├── RandomGenerator.cs │ ├── Reflection │ ├── DelegateFactory.cs │ ├── DynamicMethodFactory.cs │ ├── ExpressionFactory.cs │ ├── FieldAccessor.cs │ ├── IMemberAccessor.cs │ ├── IMemberInfo.cs │ ├── IMethodAccessor.cs │ ├── LateBinder.cs │ ├── MemberAccessor.cs │ ├── MethodAccessor.cs │ ├── PropertyAccessor.cs │ ├── ReflectionExtensions.cs │ ├── ReflectionHelper.cs │ └── TypeAccessor.cs │ ├── Sources │ ├── BooleanSource.cs │ ├── CitySource.cs │ ├── CompanySource.cs │ ├── CreditCardSource.cs │ ├── DataSourceBase.cs │ ├── DataSourceContainName.cs │ ├── DataSourceMatchName.cs │ ├── DataSourcePropertyType.cs │ ├── DateTimeSource.cs │ ├── DateTimeSourceExtensions.cs │ ├── DecimalSource.cs │ ├── DecimalSourceExtensions.cs │ ├── EmailSource.cs │ ├── EnumSource.cs │ ├── FactoryDataSource.cs │ ├── FirstNameSource.cs │ ├── FloatSource.cs │ ├── FloatSourceExtensions.cs │ ├── GenerateListSource.cs │ ├── GenerateSingleSource.cs │ ├── GuidSource.cs │ ├── IdentifierSource.cs │ ├── IntegerSource.cs │ ├── IntegerSourceExtensions.cs │ ├── LastNameSource.cs │ ├── ListDataSource.cs │ ├── LoremIpsumSource.cs │ ├── MoneySource.cs │ ├── NameSource.cs │ ├── PasswordSource.cs │ ├── PhoneSource.cs │ ├── PostalCodeSource.cs │ ├── SocialSecuritySource.cs │ ├── StateSource.cs │ ├── StreetSource.cs │ ├── TimeSpanSource.cs │ ├── TimeSpanSourceExtensions.cs │ ├── ValueSource.cs │ └── WebsiteSource.cs │ └── WeightedValue.cs └── test └── DataGenerator.Tests ├── CsvTest.cs ├── DataGenerator.Tests.csproj ├── GeneratorTest.cs ├── Models ├── Employee.cs ├── Order.cs ├── OrderLine.cs └── User.cs ├── Sources ├── BooleanSourceTest.cs ├── CompanySourceTest.cs ├── CreditCardSourceTest.cs ├── DateTimeSourceTest.cs ├── DecimalSourceTest.cs ├── EmailSourceTest.cs ├── EnumSourceTest.cs ├── FirstNameSourceTest.cs ├── FloatSourceTest.cs ├── IntegerSourceTest.cs ├── LastNameSourceTest.cs ├── LoremIpsumSourceTest.cs ├── PasswordSourceTest.cs ├── PhoneSourceTest.cs ├── PostalCodeSourceTest.cs ├── SocialSecuritySourceTest.cs ├── StateSourceTest.cs ├── StreetSourceTest.cs ├── TimeSpanSourceTest.cs └── WebsiteSourceTest.cs ├── UserProfile.cs └── coverage.opencover.xml /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015/2017 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # Visual Studio 2017 auto generated files 33 | Generated\ Files/ 34 | 35 | # MSTest test Results 36 | [Tt]est[Rr]esult*/ 37 | [Bb]uild[Ll]og.* 38 | 39 | # NUNIT 40 | *.VisualState.xml 41 | TestResult.xml 42 | 43 | # Build Results of an ATL Project 44 | [Dd]ebugPS/ 45 | [Rr]eleasePS/ 46 | dlldata.c 47 | 48 | # Benchmark Results 49 | BenchmarkDotNet.Artifacts/ 50 | 51 | # .NET Core 52 | project.lock.json 53 | project.fragment.lock.json 54 | artifacts/ 55 | **/Properties/launchSettings.json 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_i.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *.log 81 | *.vspscc 82 | *.vssscc 83 | .builds 84 | *.pidb 85 | *.svclog 86 | *.scc 87 | 88 | # Chutzpah Test files 89 | _Chutzpah* 90 | 91 | # Visual C++ cache files 92 | ipch/ 93 | *.aps 94 | *.ncb 95 | *.opendb 96 | *.opensdf 97 | *.sdf 98 | *.cachefile 99 | *.VC.db 100 | *.VC.VC.opendb 101 | 102 | # Visual Studio profiler 103 | *.psess 104 | *.vsp 105 | *.vspx 106 | *.sap 107 | 108 | # Visual Studio Trace Files 109 | *.e2e 110 | 111 | # TFS 2012 Local Workspace 112 | $tf/ 113 | 114 | # Guidance Automation Toolkit 115 | *.gpState 116 | 117 | # ReSharper is a .NET coding add-in 118 | _ReSharper*/ 119 | *.[Rr]e[Ss]harper 120 | *.DotSettings.user 121 | 122 | # JustCode is a .NET coding add-in 123 | .JustCode 124 | 125 | # TeamCity is a build add-in 126 | _TeamCity* 127 | 128 | # DotCover is a Code Coverage Tool 129 | *.dotCover 130 | 131 | # AxoCover is a Code Coverage Tool 132 | .axoCover/* 133 | !.axoCover/settings.json 134 | 135 | # Visual Studio code coverage results 136 | *.coverage 137 | *.coveragexml 138 | 139 | # NCrunch 140 | _NCrunch_* 141 | .*crunch*.local.xml 142 | nCrunchTemp_* 143 | 144 | # MightyMoose 145 | *.mm.* 146 | AutoTest.Net/ 147 | 148 | # Web workbench (sass) 149 | .sass-cache/ 150 | 151 | # Installshield output folder 152 | [Ee]xpress/ 153 | 154 | # DocProject is a documentation generator add-in 155 | DocProject/buildhelp/ 156 | DocProject/Help/*.HxT 157 | DocProject/Help/*.HxC 158 | DocProject/Help/*.hhc 159 | DocProject/Help/*.hhk 160 | DocProject/Help/*.hhp 161 | DocProject/Help/Html2 162 | DocProject/Help/html 163 | 164 | # Click-Once directory 165 | publish/ 166 | 167 | # Publish Web Output 168 | *.[Pp]ublish.xml 169 | *.azurePubxml 170 | # Note: Comment the next line if you want to checkin your web deploy settings, 171 | # but database connection strings (with potential passwords) will be unencrypted 172 | *.pubxml 173 | *.publishproj 174 | 175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 176 | # checkin your Azure Web App publish settings, but sensitive information contained 177 | # in these scripts will be unencrypted 178 | PublishScripts/ 179 | 180 | # NuGet Packages 181 | *.nupkg 182 | # The packages folder can be ignored because of Package Restore 183 | **/[Pp]ackages/* 184 | # except build/, which is used as an MSBuild target. 185 | !**/[Pp]ackages/build/ 186 | # Uncomment if necessary however generally it will be regenerated when needed 187 | #!**/[Pp]ackages/repositories.config 188 | # NuGet v3's project.json files produces more ignorable files 189 | *.nuget.props 190 | *.nuget.targets 191 | 192 | # Microsoft Azure Build Output 193 | csx/ 194 | *.build.csdef 195 | 196 | # Microsoft Azure Emulator 197 | ecf/ 198 | rcf/ 199 | 200 | # Windows Store app package directories and files 201 | AppPackages/ 202 | BundleArtifacts/ 203 | Package.StoreAssociation.xml 204 | _pkginfo.txt 205 | *.appx 206 | 207 | # Visual Studio cache files 208 | # files ending in .cache can be ignored 209 | *.[Cc]ache 210 | # but keep track of directories ending in .cache 211 | !*.[Cc]ache/ 212 | 213 | # Others 214 | ClientBin/ 215 | ~$* 216 | *~ 217 | *.dbmdl 218 | *.dbproj.schemaview 219 | *.jfm 220 | *.pfx 221 | *.publishsettings 222 | orleans.codegen.cs 223 | 224 | # Including strong name files can present a security risk 225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 226 | #*.snk 227 | 228 | # Since there are multiple workflows, uncomment next line to ignore bower_components 229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 230 | #bower_components/ 231 | 232 | # RIA/Silverlight projects 233 | Generated_Code/ 234 | 235 | # Backup & report files from converting an old project file 236 | # to a newer Visual Studio version. Backup files are not needed, 237 | # because we have git ;-) 238 | _UpgradeReport_Files/ 239 | Backup*/ 240 | UpgradeLog*.XML 241 | UpgradeLog*.htm 242 | ServiceFabricBackup/ 243 | *.rptproj.bak 244 | 245 | # SQL Server files 246 | *.mdf 247 | *.ldf 248 | *.ndf 249 | 250 | # Business Intelligence projects 251 | *.rdl.data 252 | *.bim.layout 253 | *.bim_*.settings 254 | *.rptproj.rsuser 255 | 256 | # Microsoft Fakes 257 | FakesAssemblies/ 258 | 259 | # GhostDoc plugin setting file 260 | *.GhostDoc.xml 261 | 262 | # Node.js Tools for Visual Studio 263 | .ntvs_analysis.dat 264 | node_modules/ 265 | 266 | # Visual Studio 6 build log 267 | *.plg 268 | 269 | # Visual Studio 6 workspace options file 270 | *.opt 271 | 272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 273 | *.vbw 274 | 275 | # Visual Studio LightSwitch build output 276 | **/*.HTMLClient/GeneratedArtifacts 277 | **/*.DesktopClient/GeneratedArtifacts 278 | **/*.DesktopClient/ModelManifest.xml 279 | **/*.Server/GeneratedArtifacts 280 | **/*.Server/ModelManifest.xml 281 | _Pvt_Extensions 282 | 283 | # Paket dependency manager 284 | .paket/paket.exe 285 | paket-files/ 286 | 287 | # FAKE - F# Make 288 | .fake/ 289 | 290 | # JetBrains Rider 291 | .idea/ 292 | *.sln.iml 293 | 294 | # CodeRush 295 | .cr/ 296 | 297 | # Python Tools for Visual Studio (PTVS) 298 | __pycache__/ 299 | *.pyc 300 | 301 | # Cake - Uncomment if you are using it 302 | # tools/** 303 | # !tools/packages.config 304 | 305 | # Tabs Studio 306 | *.tss 307 | 308 | # Telerik's JustMock configuration file 309 | *.jmconfig 310 | 311 | # BizTalk build output 312 | *.btp.cs 313 | *.btm.cs 314 | *.odx.cs 315 | *.xsd.cs 316 | 317 | # OpenCover UI analysis results 318 | OpenCover/ 319 | 320 | # Azure Stream Analytics local run output 321 | ASALocalRun/ 322 | 323 | # MSBuild Binary and Structured Log 324 | *.binlog 325 | 326 | # NVidia Nsight GPU debugger configuration file 327 | *.nvuser 328 | 329 | # MFractors (Xamarin productivity tool) working folder 330 | .mfractor/ 331 | 332 | # Custom 333 | /artifacts 334 | /Tools 335 | /*.txt 336 | *.GhostDoc.xml 337 | *.csv -------------------------------------------------------------------------------- /DataGenerator.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio Version 16 3 | VisualStudioVersion = 16.0.28803.202 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{AAFC7935-A4D6-40F0-9340-CBB915D10517}" 6 | ProjectSection(SolutionItems) = preProject 7 | appveyor.yml = appveyor.yml 8 | build\common.props = build\common.props 9 | build\sourcelink.props = build\sourcelink.props 10 | build\version.props = build\version.props 11 | EndProjectSection 12 | EndProject 13 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataGenerator", "src\DataGenerator\DataGenerator.csproj", "{54A7A50D-FE62-45BF-B978-B26A59CB37FA}" 14 | EndProject 15 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataGenerator.Tests", "test\DataGenerator.Tests\DataGenerator.Tests.csproj", "{7525ABFC-D6E5-48E4-9F60-571D54B94141}" 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Any CPU = Debug|Any CPU 20 | Release|Any CPU = Release|Any CPU 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {54A7A50D-FE62-45BF-B978-B26A59CB37FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {54A7A50D-FE62-45BF-B978-B26A59CB37FA}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {54A7A50D-FE62-45BF-B978-B26A59CB37FA}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {54A7A50D-FE62-45BF-B978-B26A59CB37FA}.Release|Any CPU.Build.0 = Release|Any CPU 27 | {7525ABFC-D6E5-48E4-9F60-571D54B94141}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {7525ABFC-D6E5-48E4-9F60-571D54B94141}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {7525ABFC-D6E5-48E4-9F60-571D54B94141}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {7525ABFC-D6E5-48E4-9F60-571D54B94141}.Release|Any CPU.Build.0 = Release|Any CPU 31 | EndGlobalSection 32 | GlobalSection(SolutionProperties) = preSolution 33 | HideSolutionNode = FALSE 34 | EndGlobalSection 35 | GlobalSection(ExtensibilityGlobals) = postSolution 36 | SolutionGuid = {3A19C29A-3DEF-4890-8398-7C8C3A3E7A85} 37 | EndGlobalSection 38 | EndGlobal 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 LoreSoft 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DataGenerator 2 | 3 | Automatically generate intelligent and realistic test data for an object. 4 | 5 | [![Build status](https://ci.appveyor.com/api/projects/status/toygpxy8o3u2b9ah?svg=true)](https://ci.appveyor.com/project/LoreSoft/DataGenerator) 6 | 7 | [![NuGet Version](https://img.shields.io/nuget/v/DataGenerator.svg?style=flat-square)](https://www.nuget.org/packages/DataGenerator/) 8 | 9 | [![Coverage Status](https://coveralls.io/repos/github/loresoft/DataGenerator/badge.svg?branch=master)](https://coveralls.io/github/loresoft/DataGenerator?branch=master) 10 | 11 | ## Download 12 | 13 | The DataGenerator library is available on nuget.org via package name `DataGenerator`. 14 | 15 | To install DataGenerator, run the following command in the Package Manager Console 16 | 17 | PM> Install-Package DataGenerator 18 | 19 | More information about NuGet package available at 20 | 21 | 22 | ## Development Builds 23 | 24 | 25 | Development builds are available on the myget.org feed. A development build is promoted to the main NuGet feed when it's determined to be stable. 26 | 27 | In your Package Manager settings add the following package source for development builds: 28 | 29 | 30 | ## Features 31 | 32 | - Generate intelligent test data based on property type and name 33 | - Automatic discovery of data sources 34 | - Fully customizable property data sources 35 | - Realistic data sources 36 | - Weighted value selection 37 | - Easy fluent API 38 | 39 | 40 | ## Configuration 41 | 42 | Full class property configuration 43 | 44 | ```csharp 45 | Generator.Default.Configure(c => c 46 | .Entity(e => 47 | { 48 | e.Property(p => p.FirstName).DataSource(); 49 | e.Property(p => p.LastName).DataSource(); 50 | e.Property(p => p.Address1).DataSource(); 51 | e.Property(p => p.City).DataSource(); 52 | e.Property(p => p.State).DataSource(); 53 | e.Property(p => p.Zip).DataSource(); 54 | 55 | e.Property(p => p.Note).DataSource(); 56 | e.Property(p => p.Password).DataSource(); 57 | 58 | // array of values 59 | e.Property(p => p.Status).DataSource(new[] { Status.New, Status.Verified }); 60 | 61 | 62 | // don't generate 63 | e.Property(p => p.Budget).Ignore(); 64 | 65 | // static value 66 | e.Property(p => p.IsActive).Value(true); 67 | 68 | // delegate value 69 | e.Property(p => p.Created).Value(() => DateTime.Now); 70 | }) 71 | ); 72 | ``` 73 | 74 | Example of configuration for generating child classes 75 | 76 | ```csharp 77 | Generator.Default.Configure(c => c 78 | .Entity(e => 79 | { 80 | e.AutoMap(); 81 | // generate a User instance 82 | e.Property(p => p.User).Single(); 83 | // generate list of OrderLine items 84 | e.Property(p => p.Items).List(2); 85 | }) 86 | .Entity(e => 87 | { 88 | e.AutoMap(); 89 | e.Property(p => p.Quantity).IntegerSource(1, 10); 90 | }) 91 | ); 92 | ``` 93 | There are extension methods to configure properties as well 94 | 95 | ```csharp 96 | Generator.Default.Configure(c => c 97 | .Entity(e => 98 | { 99 | // random number between 1 and 10 100 | e.Property(p => p.Quantity).IntegerSource(1, 10); 101 | // between 100 and 1,000 102 | e.Property(p => p.UnitAmount).DecimalSource(100, 1000); 103 | }) 104 | ); 105 | ``` 106 | 107 | ### Profiles 108 | 109 | DataGenerator support class profiles to make configuration easier. To create a profile, inherit from the `MappingProfile` base class. 110 | 111 | Sample Profile for the User class 112 | 113 | ```csharp 114 | public class UserProfile : MappingProfile 115 | { 116 | public override void Configure() 117 | { 118 | Property(p => p.FirstName).DataSource(); 119 | Property(p => p.LastName).DataSource(); 120 | Property(p => p.Address1).DataSource(); 121 | Property(p => p.City).DataSource(); 122 | Property(p => p.State).DataSource(); 123 | Property(p => p.Zip).DataSource(); 124 | 125 | Property(p => p.Note).DataSource(); 126 | Property(p => p.Password).DataSource(); 127 | 128 | // array of values 129 | Property(p => p.Status).DataSource(new[] { Status.New, Status.Verified }); 130 | 131 | 132 | // don't generate 133 | Property(p => p.Budget).Ignore(); 134 | 135 | // static value 136 | Property(p => p.IsActive).Value(true); 137 | 138 | // delegate value 139 | Property(p => p.Created).Value(() => DateTime.UtcNow); 140 | } 141 | } 142 | 143 | ``` 144 | 145 | Register a profile in the configuration 146 | 147 | ```csharp 148 | Generator.Default.Configure(c => c 149 | .Profile() 150 | ); 151 | ``` 152 | 153 | ## Generation 154 | 155 | Generate test data 156 | 157 | ```csharp 158 | // generate a user 159 | var instance = Generator.Default.Single(); 160 | 161 | // generate 10 users 162 | var users = Generator.Default.List(10) 163 | 164 | ``` 165 | 166 | You can override the configuration 167 | 168 | ```csharp 169 | var instance = Generator.Default.Single(c => 170 | { 171 | // override note property with static value 172 | c.Property(p => p.Note).Value("Testing static value"); 173 | }); 174 | ``` 175 | 176 | ## Data Sources 177 | 178 | ### Primitive Value Data Sources 179 | 180 | **BooleanSource** - Random true or false 181 | **DateTimeSource** - Random date plus or minus 10 years from now 182 | **DecimalSource** - Random decimal between 0 and 1,000,000 183 | **FloatSource** - Random float between 0 and 1,000,000 184 | **GuidSource** - Random GUID value 185 | **IntegerSource** - Random integer between 0 and 32,000 186 | **ListDataSource** - Random value from the specified list 187 | **TimeSpanSource** - Random TimeSpan between 0 sec and 1 day 188 | **ValueSource** - Static value source 189 | 190 | ### Smart Data Sources 191 | 192 | **CitySource** - Random city name from a list of the largest US cities 193 | **CompanySource** - Random company name from a list of fortune 500 companies 194 | **CreditCardSource** - Random credit care number 195 | **EmailSource** - Random email address using common domains 196 | **EnumSource** - Random value from available enum values 197 | **FirstNameSource** - Random first name from 100 common first names 198 | **IdentifierSource** - Random identifier value 199 | **LastNameSource** - Random last name from 100 common last names 200 | **LoremIpsumSource** - Random lorem ipsum text 201 | **MoneySource** - Random dollar amount between 0 and 10,000 202 | **NameSource** - Random code name from various sources 203 | **PasswordSource** - Random pronounceable password 204 | **PhoneSource** - Random phone number in US format 205 | **PostalCodeSource** - Random US zip code 206 | **SocialSecuritySource** - Random US Social Security Number 207 | **StateSource** - Random US State 208 | **StreetSource** - Random US house number and street 209 | **WebsiteSource** - Random website from top 100 list 210 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 5.0.0.{build} 2 | os: Visual Studio 2022 3 | environment: 4 | ASPNETCORE_ENVIRONMENT: appveyor 5 | COVERALLS_REPO_TOKEN: 6 | secure: ZUu/hqbNugncqPkxoYv3hT7hUtv2JHRQLjH/B4r/ymawzUIfaVHFOYbfxLKMQifk 7 | 8 | init: 9 | - git config --global core.autocrlf input 10 | 11 | dotnet_csproj: 12 | patch: true 13 | file: 'build\version.props' 14 | version: '{version}' 15 | package_version: '{version}' 16 | assembly_version: '{version}' 17 | file_version: '{version}' 18 | informational_version: '{version}' 19 | 20 | configuration: Release 21 | 22 | install: 23 | - dotnet tool install --global coveralls.net 24 | 25 | build_script: 26 | - dotnet pack DataGenerator.sln --configuration Release --include-symbols --include-source 27 | 28 | test_script: 29 | - dotnet test DataGenerator.sln --configuration Release /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[xunit*]*" 30 | 31 | after_test: 32 | - csmacnz.coveralls --useRelativePaths --multiple --input "opencover=test\DataGenerator.Tests\coverage.opencover.xml" 33 | 34 | artifacts: 35 | - path: artifacts\*.*nupkg 36 | name: Packages 37 | 38 | deploy: 39 | - provider: Environment 40 | name: MyGet -------------------------------------------------------------------------------- /build/common.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $([System.IO.Path]::GetDirectoryName('$(MSBuildProjectDirectory)')) 6 | $([System.IO.Path]::GetFileName('$(ProjectParentDirectory)')) 7 | 8 | 9 | 10 | 11 | 12 | Automatically generate intelligent and realistic test data for an object. 13 | Copyright © 2019 LoreSoft 14 | LoreSoft 15 | true 16 | est;Data Generation;Fake;Sample 17 | $(SolutionDir)artifacts 18 | https://github.com/loresoft/DataGenerator 19 | LICENSE 20 | logo.png 21 | git 22 | https://github.com/loresoft/DataGenerator 23 | 24 | 25 | 26 | 27 | True 28 | 29 | 30 | 31 | 32 | 33 | 34 | True 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /build/sourcelink.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | portable 4 | true 5 | true 6 | snupkg 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /build/version.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5.0.0.0 4 | 5.0.0.0 5 | 5.0.0.0 6 | 5.0.0.0 7 | 5.0.0.0 8 | 9 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loresoft/DataGenerator/1a52e140b66b4fc155db3bd6a3eddfe91995c25a/logo.png -------------------------------------------------------------------------------- /src/DataGenerator/AssemblyResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Reflection; 6 | using DataGenerator.Reflection; 7 | 8 | namespace DataGenerator 9 | { 10 | /// 11 | /// A class to resolve assemblies for scanning. 12 | /// 13 | public class AssemblyResolver 14 | { 15 | private readonly List>> _sources; 16 | private readonly List> _includes; 17 | private readonly List> _excludes; 18 | 19 | /// 20 | /// Initializes a new instance of the class. 21 | /// 22 | public AssemblyResolver() 23 | { 24 | _sources = new List>>(); 25 | _includes = new List>(); 26 | _excludes = new List>(); 27 | } 28 | 29 | /// 30 | /// Gets the assembly sources. 31 | /// 32 | /// 33 | /// The assembly sources. 34 | /// 35 | public List>> Sources 36 | { 37 | get { return _sources; } 38 | } 39 | 40 | /// 41 | /// Gets the include rules. 42 | /// 43 | /// 44 | /// The include rules. 45 | /// 46 | public List> Includes 47 | { 48 | get { return _includes; } 49 | } 50 | 51 | /// 52 | /// Gets the exclude rules. 53 | /// 54 | /// 55 | /// The exclude rules. 56 | /// 57 | public List> Excludes 58 | { 59 | get { return _excludes; } 60 | } 61 | 62 | 63 | /// 64 | /// Include the current loaded assemblies as a source. 65 | /// 66 | public void IncludeLoadedAssemblies() 67 | { 68 | #if NETSTANDARD1_3 || NETSTANDARD1_5 69 | //TDOD figure out how to do this 70 | #else 71 | _sources.Add(() => AppDomain.CurrentDomain.GetAssemblies()); 72 | #endif 73 | } 74 | 75 | /// 76 | /// Include the assembly from the specified type . 77 | /// 78 | /// The type to get assembly from. 79 | public void IncludeAssemblyFor() 80 | { 81 | IncludeAssembly(typeof(T).GetTypeInfo().Assembly); 82 | } 83 | 84 | /// 85 | /// Include the specified . 86 | /// 87 | /// The assembly to include. 88 | public void IncludeAssembly(Assembly assembly) 89 | { 90 | _sources.Add(() => new[] { assembly }); 91 | } 92 | 93 | /// 94 | /// Include the assemblies that contain the specified name. 95 | /// 96 | /// The name to compare. 97 | public void IncludeName(string name) 98 | { 99 | _includes.Add(a => a.FullName.Contains(name)); 100 | } 101 | 102 | 103 | /// 104 | /// Exclude the assembly from the specified type . 105 | /// 106 | /// The type to get assembly from. 107 | public void ExcludeAssemblyFor() 108 | { 109 | ExcludeAssembly(typeof(T).GetTypeInfo().Assembly); 110 | } 111 | 112 | /// 113 | /// Exclude the specified . 114 | /// 115 | /// The assembly to exclude. 116 | public void ExcludeAssembly(Assembly assembly) 117 | { 118 | _excludes.Add(a => a == assembly); 119 | } 120 | 121 | /// 122 | /// Exclude the assemblies that start with the specified name. 123 | /// 124 | /// The name to compare. 125 | public void ExcludeName(string name) 126 | { 127 | _excludes.Add(a => a.FullName.StartsWith(name)); 128 | } 129 | 130 | 131 | /// 132 | /// Resolves a list of assemblies using the , , and rules. 133 | /// 134 | /// An enumberable list of assemblies. 135 | public IEnumerable Resolve() 136 | { 137 | // default to loaded assemblies 138 | if (_sources.Count == 0) 139 | IncludeLoadedAssemblies(); 140 | 141 | var assemblies = _sources 142 | .SelectMany(source => source()) 143 | .Where(assembly => _includes.Count == 0 || _includes.Any(include => include(assembly))) 144 | .Where(assembly => _excludes.Count == 0 || !_excludes.Any(exclude => exclude(assembly))) 145 | .Distinct() 146 | .ToList(); 147 | 148 | return assemblies; 149 | } 150 | } 151 | } -------------------------------------------------------------------------------- /src/DataGenerator/ClassMapping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using DataGenerator.Reflection; 4 | 5 | namespace DataGenerator 6 | { 7 | /// 8 | /// Mapping information on how to generate a class 9 | /// 10 | public class ClassMapping 11 | #if !NETSTANDARD1_3 && !NETSTANDARD1_5 12 | : ICloneable 13 | #endif 14 | { 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | public ClassMapping() 19 | { 20 | AutoMap = true; 21 | Members = new List(); 22 | SyncRoot = new object(); 23 | } 24 | 25 | /// 26 | /// Initializes a new instance of the class. 27 | /// 28 | /// The type accessor. 29 | public ClassMapping(TypeAccessor typeAccessor) : this() 30 | { 31 | TypeAccessor = typeAccessor; 32 | } 33 | 34 | /// 35 | /// Gets or sets a value indicating whether to automatic map properties of the class. 36 | /// 37 | /// 38 | /// true to automatic map properties; otherwise, false. 39 | /// 40 | public bool AutoMap { get; set; } 41 | 42 | /// 43 | /// Gets or sets a value indicating whether the class is ignored. 44 | /// 45 | /// 46 | /// true if ignored; otherwise, false. 47 | /// 48 | public bool Ignored { get; set; } 49 | 50 | /// 51 | /// Gets or sets a value indicating whether has completed. 52 | /// 53 | /// 54 | /// true if AutoMap completed; otherwise, false. 55 | /// 56 | public bool Mapped { get; set; } 57 | 58 | /// 59 | /// Gets or sets the instance creation factory. 60 | /// 61 | /// 62 | /// The instance creation factory. 63 | /// 64 | public Func Factory { get; set; } 65 | 66 | /// 67 | /// Gets or sets the type accessor. 68 | /// 69 | /// 70 | /// The type accessor. 71 | /// 72 | public TypeAccessor TypeAccessor { get; set; } 73 | 74 | /// 75 | /// Gets the class mapped members. 76 | /// 77 | /// 78 | /// The class mapped members. 79 | /// 80 | public List Members { get; } 81 | 82 | /// 83 | /// Gets the synchronize object. 84 | /// 85 | /// 86 | /// The synchronize object. 87 | /// 88 | public object SyncRoot { get; } 89 | 90 | #if !NETSTANDARD1_3 && !NETSTANDARD1_5 91 | /// 92 | /// Creates a new that is a copy of the current instance. 93 | /// 94 | /// 95 | /// A new object that is a copy of this instance. 96 | /// 97 | object ICloneable.Clone() 98 | { 99 | return Clone(); 100 | } 101 | #endif 102 | 103 | /// 104 | /// Creates a new that is a copy of the current instance. 105 | /// 106 | /// 107 | /// A new object that is a copy of this instance. 108 | /// 109 | public ClassMapping Clone() 110 | { 111 | var classMapping = new ClassMapping 112 | { 113 | AutoMap = AutoMap, 114 | Ignored = Ignored, 115 | Mapped = Mapped, 116 | TypeAccessor = TypeAccessor, 117 | 118 | }; 119 | 120 | 121 | foreach (var m in Members) 122 | { 123 | var memberMapping = new MemberMapping 124 | { 125 | Ignored = m.Ignored, 126 | MemberAccessor = m.MemberAccessor, 127 | DataSource = m.DataSource 128 | }; 129 | 130 | classMapping.Members.Add(memberMapping); 131 | } 132 | 133 | return classMapping; 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/DataGenerator/Configuration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using DataGenerator.Extensions; 7 | 8 | namespace DataGenerator 9 | { 10 | /// 11 | /// A class defining the DataGenerator configuration. 12 | /// 13 | public class Configuration 14 | { 15 | private readonly ConcurrentDictionary _cache; 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | public Configuration() 21 | { 22 | _cache = new ConcurrentDictionary(); 23 | Mapping = new ConcurrentDictionary(); 24 | Assemblies = new AssemblyResolver(); 25 | AutoMap = true; 26 | 27 | #if NETSTANDARD1_3 || NETSTANDARD1_5 28 | Assemblies.IncludeAssemblyFor(); 29 | #endif 30 | 31 | // exclude system assemblies 32 | Assemblies.ExcludeName("mscorlib"); 33 | Assemblies.ExcludeName("Microsoft"); 34 | Assemblies.ExcludeName("System"); 35 | 36 | 37 | } 38 | 39 | /// 40 | /// Gets the assemblies used by DataGenerator. 41 | /// 42 | /// 43 | /// The assemblies use by DataGenerator. 44 | /// 45 | public AssemblyResolver Assemblies { get; } 46 | 47 | /// 48 | /// Gets or sets a value indicating whether to automatic map properties of the class by default. 49 | /// 50 | /// 51 | /// true to automatic map properties; otherwise, false. 52 | /// 53 | public bool AutoMap { get; set; } 54 | 55 | /// 56 | /// Gets the mapped class definitions. 57 | /// 58 | /// 59 | /// The mapped class definitions. 60 | /// 61 | public ConcurrentDictionary Mapping { get; } 62 | 63 | 64 | /// 65 | /// Gets a list of by scanning the . 66 | /// 67 | /// 68 | /// The result of the assembly scan is cached. Repeated calls will return results from cache. Call to re-scan assemblies. 69 | /// 70 | /// The discovered data sources 71 | public IEnumerable DataSources() 72 | { 73 | var dataSources = _cache.GetOrAdd("DataSource", k => 74 | { 75 | var assemblies = Assemblies.Resolve().ToList(); 76 | 77 | return assemblies 78 | .SelectMany(GetTypesAssignableFrom) 79 | .Select(CreateInstance) 80 | .OfType() 81 | .ToList(); 82 | }); 83 | 84 | return dataSources as IEnumerable; 85 | } 86 | 87 | /// 88 | /// Clears the cached data sources. 89 | /// 90 | public void ClearCache() 91 | { 92 | _cache.Clear(); 93 | } 94 | 95 | 96 | private static IEnumerable GetTypesAssignableFrom(Assembly assembly) 97 | { 98 | return assembly.GetTypesAssignableFrom(); 99 | } 100 | 101 | private static object CreateInstance(Type type) 102 | { 103 | return Activator.CreateInstance(type); 104 | } 105 | 106 | } 107 | } -------------------------------------------------------------------------------- /src/DataGenerator/DataGenerator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | netstandard2.0 6 | 1591 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/DataGenerator/Extensions/AssemblyExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using DataGenerator.Reflection; 6 | 7 | namespace DataGenerator.Extensions 8 | { 9 | /// 10 | /// extension methods 11 | /// 12 | public static class AssemblyExtensions 13 | { 14 | /// 15 | /// Gets the types assignable from . 16 | /// 17 | /// The type to determine whether if it can be assigned. 18 | /// The assembly to search types. 19 | /// An enumerable list of types the are assignable from . 20 | /// When assembly is null. 21 | public static IEnumerable GetTypesAssignableFrom(this Assembly assembly) 22 | { 23 | if (assembly == null) 24 | throw new ArgumentNullException(nameof(assembly)); 25 | 26 | var type = typeof(T); 27 | var typeInfo = type.GetTypeInfo(); 28 | 29 | return assembly 30 | .GetLoadableTypes() 31 | .Where(t => 32 | { 33 | var i = t.GetTypeInfo(); 34 | return i.IsPublic && !i.IsAbstract && typeInfo.IsAssignableFrom(i); 35 | }); 36 | } 37 | 38 | /// 39 | /// Gets the public types defined in this assembly that are visible and can be loaded outside the assembly. 40 | /// 41 | /// The assembly to search types. 42 | /// 43 | /// assembly 44 | public static IEnumerable GetLoadableTypes(this Assembly assembly) 45 | { 46 | if (assembly == null) 47 | throw new ArgumentNullException(nameof(assembly)); 48 | 49 | // skip dynamic assemblies 50 | if (assembly.IsDynamic) 51 | return Enumerable.Empty(); 52 | 53 | Type[] types; 54 | 55 | try 56 | { 57 | types = assembly.GetExportedTypes(); 58 | } 59 | catch (ReflectionTypeLoadException e) 60 | { 61 | //not interested in the types which cause the problem, load what we can 62 | types = e.Types.Where(t => t != null).ToArray(); 63 | } 64 | catch (NotSupportedException) 65 | { 66 | // some assemblies don't support getting types, ignore 67 | return Enumerable.Empty(); 68 | } 69 | 70 | return types; 71 | } 72 | 73 | #if NET40 || PORTABLE 74 | /// 75 | /// Retrieves an object that represents this type. 76 | /// 77 | /// Type to retrieve 78 | /// 79 | public static Type GetTypeInfo(this Type type) 80 | { 81 | return type; 82 | } 83 | #endif 84 | } 85 | } -------------------------------------------------------------------------------- /src/DataGenerator/Extensions/RandomExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Security.Cryptography; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DataGenerator.Extensions 9 | { 10 | /// 11 | /// Extension methods for randomization 12 | /// 13 | public static class RandomExtensions 14 | { 15 | /// 16 | /// Gets a random value from the specified . 17 | /// 18 | /// The type of elements in the list. 19 | /// The list to get a random value from. 20 | /// A random value from the list. 21 | public static T Random(this IList list) 22 | { 23 | if (list == null || list.Count < 1) 24 | return default(T); 25 | 26 | var index = RandomGenerator.Current.Next(list.Count); 27 | return list[index]; 28 | } 29 | 30 | /// 31 | /// Gets random values from the specified . 32 | /// 33 | /// The type of elements in the list. 34 | /// The list to get a random value from. 35 | /// The number of random items to return. 36 | /// 37 | /// Random values from the list. 38 | /// 39 | public static IEnumerable Random(this IList list, int count) 40 | { 41 | if (list == null || list.Count < 1 || count < 1) 42 | yield break; 43 | 44 | for (int i = 0; i < count; i++) 45 | yield return Random(list); 46 | } 47 | 48 | /// 49 | /// Gets a random value from the specified using the to weight the values. 50 | /// 51 | /// The type of elements in the list. 52 | /// The list to get a random value from. 53 | /// The value weight selector. 54 | /// 55 | /// A random value from the list. 56 | /// 57 | public static T Random(this IList list, Func weightSelector) 58 | { 59 | if (list == null || list.Count < 1) 60 | return default(T); 61 | 62 | if (weightSelector == null) 63 | return list.Random(); 64 | 65 | int totalWeight = 0; 66 | var selected = default(T); 67 | 68 | foreach (var data in list) 69 | { 70 | int weight = weightSelector(data); 71 | int r = RandomGenerator.Current.Next(totalWeight + weight); 72 | 73 | if (r >= totalWeight) 74 | selected = data; 75 | 76 | totalWeight += weight; 77 | } 78 | 79 | return selected; 80 | } 81 | 82 | /// 83 | /// Gets random values from the specified using the to weight the values. 84 | /// 85 | /// The type of elements in the list. 86 | /// The list to get a random value from. 87 | /// The value weight selector. 88 | /// The number of random items to return. 89 | /// 90 | /// Random values from the list. 91 | /// 92 | public static IEnumerable Random(this IList list, Func weightSelector, int count) 93 | { 94 | if (list == null || list.Count < 1 || count < 1) 95 | yield break; 96 | 97 | for (int i = 0; i < count; i++) 98 | yield return Random(list, weightSelector); 99 | } 100 | 101 | 102 | /// 103 | /// Returns a non-negative random integer. 104 | /// 105 | /// The generator. 106 | /// A 32-bit signed integer that is greater than or equal to 0 and less than MaxValue. 107 | public static int Next(this RandomNumberGenerator generator) 108 | { 109 | var buffer = new byte[4]; 110 | generator.GetBytes(buffer); 111 | 112 | return BitConverter.ToInt32(buffer, 0); 113 | } 114 | 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/DataGenerator/Fluent/ClassMappingBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | 4 | namespace DataGenerator.Fluent 5 | { 6 | /// 7 | /// Fluent builder for . 8 | /// 9 | /// The type of the entity. 10 | public class ClassMappingBuilder 11 | { 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | protected ClassMappingBuilder() 16 | { 17 | 18 | } 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | /// The class mapping. 24 | public ClassMappingBuilder(ClassMapping classMapping) 25 | { 26 | ClassMapping = classMapping; 27 | } 28 | 29 | /// 30 | /// Gets or sets the class mapping. 31 | /// 32 | /// 33 | /// The class mapping. 34 | /// 35 | public ClassMapping ClassMapping { get; protected set; } 36 | 37 | 38 | /// 39 | /// Sets a value indicating whether to automatic map properties of the class. 40 | /// 41 | /// true to automatic map properties; otherwise, false. 42 | /// A fluent builder for class mapping. 43 | public ClassMappingBuilder AutoMap(bool value = true) 44 | { 45 | ClassMapping.AutoMap = value; 46 | return this; 47 | } 48 | 49 | /// 50 | /// Sets the instance creation factory . 51 | /// 52 | /// The instance creation factory. 53 | /// 54 | /// A fluent builder for class mapping. 55 | /// 56 | public ClassMappingBuilder Factory(Func factory) 57 | { 58 | ClassMapping.Factory = factory; 59 | return this; 60 | } 61 | 62 | 63 | /// 64 | /// Start a fluent configuration for the specified . 65 | /// 66 | /// The type of the property. 67 | /// The source property to configure. 68 | /// A fluent member builder for the specified property. 69 | public MemberConfigurationBuilder Property(Expression> property) 70 | { 71 | var propertyAccessor = ClassMapping.TypeAccessor.FindProperty(property); 72 | 73 | var memberMapping = ClassMapping.Members.Find(m => m.MemberAccessor.MemberInfo == propertyAccessor.MemberInfo); 74 | if (memberMapping == null) 75 | { 76 | memberMapping = new MemberMapping(); 77 | memberMapping.MemberAccessor = propertyAccessor; 78 | 79 | ClassMapping.Members.Add(memberMapping); 80 | } 81 | 82 | var builder = new MemberConfigurationBuilder(memberMapping); 83 | return builder; 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /src/DataGenerator/Fluent/ConfigurationBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using DataGenerator.Reflection; 8 | 9 | namespace DataGenerator.Fluent 10 | { 11 | /// 12 | /// Fluent builder. 13 | /// 14 | public class ConfigurationBuilder 15 | { 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | /// The configuration to update. 20 | public ConfigurationBuilder(Configuration configuration) 21 | { 22 | Configuration = configuration; 23 | } 24 | 25 | 26 | /// 27 | /// Gets the current configuration. 28 | /// 29 | /// 30 | /// The current configuration. 31 | /// 32 | public Configuration Configuration { get; } 33 | 34 | 35 | /// 36 | /// Include the current loaded assemblies as a source. 37 | /// 38 | /// 39 | /// A fluent to configure DataGenerator. 40 | /// 41 | public ConfigurationBuilder IncludeLoadedAssemblies() 42 | { 43 | Configuration.Assemblies.IncludeLoadedAssemblies(); 44 | Configuration.ClearCache(); 45 | return this; 46 | } 47 | 48 | /// 49 | /// Include the assembly from the specified type . 50 | /// 51 | /// The type to get assembly from. 52 | /// 53 | /// A fluent to configure DataGenerator. 54 | /// 55 | public ConfigurationBuilder IncludeAssemblyFor() 56 | { 57 | return IncludeAssembly(typeof(T).GetTypeInfo().Assembly); 58 | } 59 | 60 | /// 61 | /// Include the specified . 62 | /// 63 | /// The assembly to include. 64 | /// 65 | /// A fluent to configure DataGenerator. 66 | /// 67 | public ConfigurationBuilder IncludeAssembly(Assembly assembly) 68 | { 69 | Configuration.Assemblies.IncludeAssembly(assembly); 70 | Configuration.ClearCache(); 71 | return this; 72 | } 73 | 74 | /// 75 | /// Include the assemblies that contain the specified name. 76 | /// 77 | /// The name to compare. 78 | /// 79 | /// A fluent to configure DataGenerator. 80 | /// 81 | public ConfigurationBuilder IncludeName(string name) 82 | { 83 | Configuration.Assemblies.IncludeName(name); 84 | Configuration.ClearCache(); 85 | return this; 86 | } 87 | 88 | 89 | /// 90 | /// Exclude the assembly from the specified type . 91 | /// 92 | /// The type to get assembly from. 93 | /// 94 | /// A fluent to configure DataGenerator. 95 | /// 96 | public ConfigurationBuilder ExcludeAssemblyFor() 97 | { 98 | return ExcludeAssembly(typeof(T).GetTypeInfo().Assembly); 99 | } 100 | 101 | /// 102 | /// Exclude the specified . 103 | /// 104 | /// The assembly to exclude. 105 | /// 106 | /// A fluent to configure DataGenerator. 107 | /// 108 | public ConfigurationBuilder ExcludeAssembly(Assembly assembly) 109 | { 110 | Configuration.Assemblies.ExcludeAssembly(assembly); 111 | Configuration.ClearCache(); 112 | return this; 113 | } 114 | 115 | /// 116 | /// Exclude the assemblies that start with the specified name. 117 | /// 118 | /// The name to compare. 119 | /// 120 | /// A fluent builder to configure DataGenerator. 121 | /// 122 | public ConfigurationBuilder ExcludeName(string name) 123 | { 124 | Configuration.Assemblies.ExcludeName(name); 125 | Configuration.ClearCache(); 126 | return this; 127 | } 128 | 129 | 130 | /// 131 | /// Fluent configuration for . 132 | /// 133 | /// The type of the entity for the class mapping. 134 | /// The fluent builder for . 135 | /// 136 | /// A fluent builder to configure DataGenerator. 137 | /// 138 | /// The parameter is . 139 | public ConfigurationBuilder Entity(Action> builder) 140 | { 141 | if (builder == null) 142 | throw new ArgumentNullException(nameof(builder)); 143 | 144 | var type = typeof(TEntity); 145 | var classMapping = GetClassMap(type); 146 | 147 | var mappingBuilder = new ClassMappingBuilder(classMapping); 148 | builder(mappingBuilder); 149 | 150 | return this; 151 | } 152 | 153 | 154 | /// 155 | /// Add the profile of type to the configuration 156 | /// 157 | /// The type of the profile. 158 | /// 159 | /// A fluent builder to configure DataGenerator. 160 | /// 161 | public ConfigurationBuilder Profile() 162 | where TProfile : IMappingProfile, new() 163 | { 164 | var profile = new TProfile(); 165 | var type = profile.EntityType; 166 | var classMapping = GetClassMap(type); 167 | 168 | profile.Register(classMapping); 169 | 170 | return this; 171 | } 172 | 173 | 174 | private ClassMapping GetClassMap(Type type) 175 | { 176 | var classMapping = Configuration.Mapping.GetOrAdd(type, t => 177 | { 178 | var typeAccessor = TypeAccessor.GetAccessor(t); 179 | var mapping = new ClassMapping(typeAccessor); 180 | return mapping; 181 | }); 182 | 183 | return classMapping; 184 | } 185 | 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/DataGenerator/Fluent/ListGeneratorBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator.Fluent 4 | { 5 | /// 6 | /// A fluent builder for list entity generation. 7 | /// 8 | /// The type of the entity. 9 | public class ListGeneratorBuilder : ClassMappingBuilder 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// The class mapping. 15 | public ListGeneratorBuilder(ClassMapping classMapping) : base(classMapping) 16 | { 17 | Random(2, 10); 18 | } 19 | 20 | /// 21 | /// Gets or sets the generate count. 22 | /// 23 | /// 24 | /// The generate count. 25 | /// 26 | public int GenerateCount { get; set; } 27 | 28 | /// 29 | /// Set the number entities to generate. 30 | /// 31 | /// The number of entities to generate.. 32 | /// A fluent builder for class mapping. 33 | public ListGeneratorBuilder Count(int count) 34 | { 35 | GenerateCount = count; 36 | return this; 37 | } 38 | 39 | /// 40 | /// Set the and range for a random number of entities to generate. 41 | /// 42 | /// The minimum value in the random range. 43 | /// The maximum value in the random range. 44 | /// 45 | /// A fluent builder for class mapping. 46 | /// 47 | public ListGeneratorBuilder Random(int min, int max) 48 | { 49 | var count = RandomGenerator.Current.Next(min, max); 50 | GenerateCount = count; 51 | return this; 52 | } 53 | 54 | /// 55 | /// Sets a value indicating whether to automatic map properties of the class. 56 | /// 57 | /// true to automatic map properties; otherwise, false. 58 | /// A fluent builder for class mapping. 59 | public new ListGeneratorBuilder AutoMap(bool value = true) 60 | { 61 | base.AutoMap(value); 62 | return this; 63 | } 64 | 65 | } 66 | } -------------------------------------------------------------------------------- /src/DataGenerator/Fluent/MemberConfigurationBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using DataGenerator.Sources; 4 | 5 | namespace DataGenerator.Fluent 6 | { 7 | /// 8 | /// Fluent builder for an entity property. 9 | /// 10 | /// The type of the entity. 11 | /// The type of the property. 12 | public class MemberConfigurationBuilder 13 | { 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The member mapping. 19 | public MemberConfigurationBuilder(MemberMapping memberMapping) 20 | { 21 | MemberMapping = memberMapping; 22 | } 23 | 24 | /// 25 | /// Gets the current member mapping. 26 | /// 27 | /// 28 | /// The current member mapping. 29 | /// 30 | public MemberMapping MemberMapping { get; } 31 | 32 | 33 | /// 34 | /// Set the properties generation data source to the specified type. 35 | /// 36 | /// The type of the source. 37 | /// Fluent builder for an entity property. 38 | public MemberConfigurationBuilder DataSource() 39 | where TSource : class, IDataSource, new() 40 | { 41 | var source = new TSource(); 42 | MemberMapping.DataSource = source; 43 | 44 | return this; 45 | } 46 | 47 | /// 48 | /// Set the properties generation data source to the specified . 49 | /// 50 | /// The type of the source. 51 | /// The factory delegate used as the data source. 52 | /// Fluent builder for an entity property. 53 | public MemberConfigurationBuilder DataSource(Func factory) 54 | where TSource : class, IDataSource 55 | { 56 | var source = factory(); 57 | MemberMapping.DataSource = source; 58 | 59 | return this; 60 | } 61 | 62 | /// 63 | /// Set the properties generation data source that uses the specified . 64 | /// 65 | /// The values to use as the data source. 66 | /// 67 | /// Fluent builder for an entity property. 68 | /// 69 | public MemberConfigurationBuilder DataSource(IEnumerable values) 70 | { 71 | var source = new ListDataSource(values); 72 | MemberMapping.DataSource = source; 73 | 74 | return this; 75 | } 76 | 77 | /// 78 | /// Set the properties generation data source that uses the specified . 79 | /// 80 | /// The values to use as the data source. 81 | /// The random weight selector delegate. 82 | /// 83 | /// Fluent builder for an entity property. 84 | /// 85 | public MemberConfigurationBuilder DataSource(IEnumerable values, Func weightSelector) 86 | { 87 | var source = new ListDataSource(values); 88 | source.WeightSelector = weightSelector; 89 | 90 | MemberMapping.DataSource = source; 91 | 92 | return this; 93 | } 94 | 95 | 96 | /// 97 | /// Ignore this property during data generation. 98 | /// 99 | /// if set to true this property will be ignored. 100 | /// 101 | /// Fluent builder for an entity property. 102 | /// 103 | public MemberConfigurationBuilder Ignore(bool value = true) 104 | { 105 | MemberMapping.Ignored = value; 106 | return this; 107 | } 108 | 109 | 110 | /// 111 | /// Use the value during data generation. 112 | /// 113 | /// The factory delegate to get a value from. 114 | /// 115 | /// Fluent builder for an entity property. 116 | /// 117 | public MemberConfigurationBuilder Value(Func factory) 118 | { 119 | var source = new FactoryDataSource(factory); 120 | MemberMapping.DataSource = source; 121 | 122 | return this; 123 | } 124 | 125 | /// 126 | /// Use the specified during data generation. 127 | /// 128 | /// The value to use. 129 | /// 130 | /// Fluent builder for an entity property. 131 | /// 132 | public MemberConfigurationBuilder Value(TProperty value) 133 | { 134 | var source = new ValueSource(value); 135 | MemberMapping.DataSource = source; 136 | 137 | return this; 138 | } 139 | 140 | 141 | /// 142 | /// Generates a new instance of type from the current generator context. 143 | /// 144 | /// 145 | public MemberConfigurationBuilder Single() 146 | { 147 | var source = new GenerateSingleSource(); 148 | MemberMapping.DataSource = source; 149 | 150 | return this; 151 | } 152 | 153 | /// 154 | /// Generates a new instance of type from the current generator context. 155 | /// 156 | /// The type to generate. 157 | /// 158 | public MemberConfigurationBuilder Single() 159 | { 160 | var source = new GenerateSingleSource(); 161 | MemberMapping.DataSource = source; 162 | 163 | return this; 164 | } 165 | 166 | /// 167 | /// Generates multiple new instances of type from the current generator context. 168 | /// 169 | /// The type to generate. 170 | /// The number of instances to generate. 171 | /// 172 | public MemberConfigurationBuilder List(int count = 10) 173 | { 174 | var source = new GenerateListSource(count); 175 | MemberMapping.DataSource = source; 176 | 177 | return this; 178 | } 179 | 180 | } 181 | } -------------------------------------------------------------------------------- /src/DataGenerator/GenerateContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator 4 | { 5 | /// 6 | /// Data generation context state 7 | /// 8 | public class GenerateContext : IGenerateContext 9 | { 10 | /// 11 | /// Gets or sets the current generator. 12 | /// 13 | /// 14 | /// The current generator. 15 | /// 16 | public Generator Generator { get; set; } 17 | 18 | /// 19 | /// Gets the type of the class being generated. 20 | /// 21 | /// 22 | /// The type of the class. 23 | /// 24 | public Type ClassType { get; set; } 25 | 26 | /// 27 | /// Gets the type of the member. 28 | /// 29 | /// 30 | /// The type of the member. 31 | /// 32 | public Type MemberType { get; set; } 33 | 34 | /// 35 | /// Gets the name of the member. 36 | /// 37 | /// 38 | /// The name of the member. 39 | /// 40 | public string MemberName { get; set; } 41 | 42 | /// 43 | /// Gets the generation depth. 44 | /// 45 | /// 46 | /// The generation depth. 47 | /// 48 | public int Depth { get; set; } 49 | 50 | /// 51 | /// Gets the current generated instance. 52 | /// 53 | /// 54 | /// The current generated instance. 55 | /// 56 | public object Instance { get; set; } 57 | 58 | } 59 | } -------------------------------------------------------------------------------- /src/DataGenerator/IDataSource.cs: -------------------------------------------------------------------------------- 1 | namespace DataGenerator 2 | { 3 | /// 4 | /// An for generating data from a source 5 | /// 6 | public interface IDataSource 7 | { 8 | /// 9 | /// Get a value from the data source. 10 | /// 11 | /// The generate context. 12 | /// A new value from the data source. 13 | object NextValue(IGenerateContext generateContext); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/DataGenerator/IDataSourceDiscover.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator 4 | { 5 | /// 6 | /// An for discoverint data sources 7 | /// 8 | public interface IDataSourceDiscover : IDataSource 9 | { 10 | /// 11 | /// Gets the priority of the data source. 12 | /// 13 | /// 14 | /// The priority of the data source. 15 | /// 16 | int Priority { get; } 17 | 18 | /// 19 | /// Test if the current can use this data source. 20 | /// 21 | /// The mapping context. 22 | /// true if this data source can be used; otherwise false. 23 | bool TryMap(IMappingContext mappingContext); 24 | } 25 | } -------------------------------------------------------------------------------- /src/DataGenerator/IGenerateContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator 4 | { 5 | /// 6 | /// An defining the current generation state 7 | /// 8 | public interface IGenerateContext 9 | { 10 | /// 11 | /// Gets or sets the current generator. 12 | /// 13 | /// 14 | /// The current generator. 15 | /// 16 | Generator Generator { get; set; } 17 | 18 | /// 19 | /// Gets the type of the class being generated. 20 | /// 21 | /// 22 | /// The type of the class. 23 | /// 24 | Type ClassType { get; } 25 | 26 | /// 27 | /// Gets the type of the member. 28 | /// 29 | /// 30 | /// The type of the member. 31 | /// 32 | Type MemberType { get; } 33 | 34 | /// 35 | /// Gets the name of the member. 36 | /// 37 | /// 38 | /// The name of the member. 39 | /// 40 | string MemberName { get; } 41 | 42 | /// 43 | /// Gets the generation depth. 44 | /// 45 | /// 46 | /// The generation depth. 47 | /// 48 | int Depth { get; } 49 | 50 | /// 51 | /// Gets the current generated instance. 52 | /// 53 | /// 54 | /// The current generated instance. 55 | /// 56 | object Instance { get; } 57 | } 58 | } -------------------------------------------------------------------------------- /src/DataGenerator/IMappingContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator 4 | { 5 | /// 6 | /// An defining the current mapping context. 7 | /// 8 | public interface IMappingContext 9 | { 10 | /// 11 | /// Gets the current class mapping. 12 | /// 13 | /// 14 | /// The current class mapping. 15 | /// 16 | ClassMapping ClassMapping { get; } 17 | 18 | /// 19 | /// Gets the member mapping. 20 | /// 21 | /// 22 | /// The member mapping. 23 | /// 24 | MemberMapping MemberMapping { get; } 25 | } 26 | } -------------------------------------------------------------------------------- /src/DataGenerator/IMappingProfile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator 4 | { 5 | /// 6 | /// An for mapping a class. 7 | /// 8 | public interface IMappingProfile 9 | { 10 | /// 11 | /// Gets the type of the entity. 12 | /// 13 | /// 14 | /// The type of the entity. 15 | /// 16 | Type EntityType { get; } 17 | 18 | /// 19 | /// Registers the specified class mapping. 20 | /// 21 | /// The class mapping. 22 | void Register(ClassMapping classMapping); 23 | } 24 | } -------------------------------------------------------------------------------- /src/DataGenerator/MappingContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator 4 | { 5 | /// 6 | /// Class mapping context 7 | /// 8 | public class MappingContext : IMappingContext 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// The class mapping. 14 | /// The member mapping. 15 | public MappingContext(ClassMapping classMapping, MemberMapping memberMapping) 16 | { 17 | ClassMapping = classMapping; 18 | MemberMapping = memberMapping; 19 | } 20 | 21 | /// 22 | /// Gets the current class mapping. 23 | /// 24 | /// 25 | /// The current class mapping. 26 | /// 27 | public ClassMapping ClassMapping { get; } 28 | 29 | /// 30 | /// Gets the member mapping. 31 | /// 32 | /// 33 | /// The member mapping. 34 | /// 35 | public MemberMapping MemberMapping { get; } 36 | 37 | } 38 | } -------------------------------------------------------------------------------- /src/DataGenerator/MappingProfile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Fluent; 3 | 4 | namespace DataGenerator 5 | { 6 | /// 7 | /// A class for creating mapping profiles 8 | /// 9 | /// The type of the entity. 10 | public abstract class MappingProfile : ClassMappingBuilder, IMappingProfile 11 | where TEntity : class 12 | { 13 | /// 14 | /// Gets or sets the type of the entity. 15 | /// 16 | /// 17 | /// The type of the entity. 18 | /// 19 | Type IMappingProfile.EntityType => typeof(TEntity); 20 | 21 | /// 22 | /// Registers the specified class mapping. 23 | /// 24 | /// The class mapping. 25 | void IMappingProfile.Register(ClassMapping classMapping) 26 | { 27 | ClassMapping = classMapping; 28 | Configure(); 29 | } 30 | 31 | 32 | /// 33 | /// Configure the mapping information. 34 | /// 35 | public abstract void Configure(); 36 | } 37 | } -------------------------------------------------------------------------------- /src/DataGenerator/MemberMapping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using DataGenerator.Reflection; 7 | 8 | namespace DataGenerator 9 | { 10 | /// 11 | /// Mapping information for a class member. 12 | /// 13 | public class MemberMapping 14 | { 15 | /// 16 | /// Gets or sets a value indicating whether the member is ignored. 17 | /// 18 | /// 19 | /// true if ignored; otherwise, false. 20 | /// 21 | public bool Ignored { get; set; } 22 | 23 | /// 24 | /// Gets or sets the member accessor. 25 | /// 26 | /// 27 | /// The member accessor. 28 | /// 29 | public IMemberAccessor MemberAccessor { get; set; } 30 | 31 | /// 32 | /// Gets or sets the data source used for generating values. 33 | /// 34 | /// 35 | /// The data source used for generating values. 36 | /// 37 | public IDataSource DataSource { get; set; } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/DataGenerator/RandomGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Security.Cryptography; 3 | using System.Threading; 4 | using DataGenerator.Extensions; 5 | 6 | namespace DataGenerator 7 | { 8 | /// 9 | /// A shared thread-safe instance of . 10 | /// 11 | public static class RandomGenerator 12 | { 13 | // one random generator per thread 14 | private static readonly RandomNumberGenerator _seed = RandomNumberGenerator.Create(); 15 | private static readonly ThreadLocal _local = new ThreadLocal(() => new Random(_seed.Next())); 16 | 17 | /// 18 | /// Gets the thread-safe instance of . 19 | /// 20 | /// 21 | /// The thread-safe instance of . 22 | /// 23 | public static Random Current => _local.Value; 24 | } 25 | } -------------------------------------------------------------------------------- /src/DataGenerator/Reflection/DelegateFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace DataGenerator.Reflection 5 | { 6 | internal static class DelegateFactory 7 | { 8 | public static Func CreateMethod(MethodInfo methodInfo) 9 | { 10 | #if SILVERLIGHT 11 | return ExpressionFactory.CreateMethod(methodInfo); 12 | #else 13 | return DynamicMethodFactory.CreateMethod(methodInfo); 14 | #endif 15 | } 16 | 17 | public static Func CreateConstructor(Type type) 18 | { 19 | #if SILVERLIGHT 20 | return ExpressionFactory.CreateConstructor(type); 21 | #else 22 | return DynamicMethodFactory.CreateConstructor(type); 23 | #endif 24 | } 25 | 26 | public static Func CreateGet(PropertyInfo propertyInfo) 27 | { 28 | #if SILVERLIGHT 29 | return ExpressionFactory.CreateGet(propertyInfo); 30 | #else 31 | return DynamicMethodFactory.CreateGet(propertyInfo); 32 | #endif 33 | } 34 | 35 | public static Func CreateGet(FieldInfo fieldInfo) 36 | { 37 | #if SILVERLIGHT 38 | return ExpressionFactory.CreateGet(fieldInfo); 39 | #else 40 | return DynamicMethodFactory.CreateGet(fieldInfo); 41 | #endif 42 | } 43 | 44 | public static Action CreateSet(PropertyInfo propertyInfo) 45 | { 46 | #if SILVERLIGHT 47 | return ExpressionFactory.CreateSet(propertyInfo); 48 | #else 49 | return DynamicMethodFactory.CreateSet(propertyInfo); 50 | #endif 51 | } 52 | 53 | public static Action CreateSet(FieldInfo fieldInfo) 54 | { 55 | #if SILVERLIGHT 56 | return ExpressionFactory.CreateSet(fieldInfo); 57 | #else 58 | return DynamicMethodFactory.CreateSet(fieldInfo); 59 | #endif 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /src/DataGenerator/Reflection/ExpressionFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Reflection; 6 | 7 | namespace DataGenerator.Reflection 8 | { 9 | internal static class ExpressionFactory 10 | { 11 | public static Func CreateMethod(MethodInfo methodInfo) 12 | { 13 | if (methodInfo == null) 14 | throw new ArgumentNullException(nameof(methodInfo)); 15 | 16 | // parameters to execute 17 | var instanceParameter = Expression.Parameter(typeof(object), "instance"); 18 | var parametersParameter = Expression.Parameter(typeof(object[]), "parameters"); 19 | 20 | // build parameter list 21 | var parameterExpressions = new List(); 22 | var paramInfos = methodInfo.GetParameters(); 23 | for (int i = 0; i < paramInfos.Length; i++) 24 | { 25 | // (Ti)parameters[i] 26 | var valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i)); 27 | 28 | Type parameterType = paramInfos[i].ParameterType; 29 | if (parameterType.IsByRef) 30 | parameterType = parameterType.GetElementType(); 31 | 32 | var valueCast = Expression.Convert(valueObj, parameterType); 33 | 34 | parameterExpressions.Add(valueCast); 35 | } 36 | 37 | // non-instance for static method, or ((TInstance)instance) 38 | var instanceCast = methodInfo.IsStatic ? null : Expression.Convert(instanceParameter, methodInfo.DeclaringType); 39 | 40 | // static invoke or ((TInstance)instance).Method 41 | var methodCall = Expression.Call(instanceCast, methodInfo, parameterExpressions); 42 | 43 | // ((TInstance)instance).Method((T0)parameters[0], (T1)parameters[1], ...) 44 | if (methodCall.Type == typeof(void)) 45 | { 46 | var lambda = Expression.Lambda>(methodCall, instanceParameter, parametersParameter); 47 | var execute = lambda.Compile(); 48 | 49 | return (instance, parameters) => 50 | { 51 | execute(instance, parameters); 52 | return null; 53 | }; 54 | } 55 | else 56 | { 57 | var castMethodCall = Expression.Convert(methodCall, typeof(object)); 58 | var lambda = Expression.Lambda>(castMethodCall, instanceParameter, parametersParameter); 59 | 60 | return lambda.Compile(); 61 | } 62 | } 63 | 64 | public static Func CreateConstructor(Type type) 65 | { 66 | if (type == null) 67 | throw new ArgumentNullException(nameof(type)); 68 | 69 | var typeInfo = type.GetTypeInfo(); 70 | 71 | #if NETSTANDARD1_3 72 | var constructorInfo = typeInfo.DeclaredConstructors.FirstOrDefault(c => c.GetParameters().Length == 0); 73 | #else 74 | var constructorInfo = typeInfo.GetConstructor(Type.EmptyTypes); 75 | #endif 76 | if (constructorInfo == null) 77 | throw new ArgumentException("Could not find constructor for type.", nameof(type)); 78 | 79 | var instanceCreate = Expression.New(constructorInfo); 80 | 81 | var instanceCreateCast = typeInfo.IsValueType 82 | ? Expression.Convert(instanceCreate, typeof(object)) 83 | : Expression.TypeAs(instanceCreate, typeof(object)); 84 | 85 | var lambda = Expression.Lambda>(instanceCreateCast); 86 | 87 | return lambda.Compile(); 88 | } 89 | 90 | public static Func CreateGet(PropertyInfo propertyInfo) 91 | { 92 | if (propertyInfo == null) 93 | throw new ArgumentNullException(nameof(propertyInfo)); 94 | 95 | if (!propertyInfo.CanRead) 96 | return null; 97 | 98 | var instance = Expression.Parameter(typeof(object), "instance"); 99 | var declaringType = propertyInfo.DeclaringType; 100 | var getMethod = propertyInfo.GetGetMethod(true); 101 | 102 | UnaryExpression instanceCast; 103 | if (getMethod.IsStatic) 104 | instanceCast = null; 105 | else if (declaringType.GetTypeInfo().IsValueType) 106 | instanceCast = Expression.Convert(instance, declaringType); 107 | else 108 | instanceCast = Expression.TypeAs(instance, declaringType); 109 | 110 | var call = Expression.Call(instanceCast, getMethod); 111 | var valueCast = Expression.TypeAs(call, typeof(object)); 112 | 113 | var lambda = Expression.Lambda>(valueCast, instance); 114 | return lambda.Compile(); 115 | } 116 | 117 | public static Func CreateGet(FieldInfo fieldInfo) 118 | { 119 | if (fieldInfo == null) 120 | throw new ArgumentNullException(nameof(fieldInfo)); 121 | 122 | var instance = Expression.Parameter(typeof(object), "instance"); 123 | var declaringType = fieldInfo.DeclaringType; 124 | 125 | // value as T is slightly faster than (T)value, so if it's not a value type, use that 126 | UnaryExpression instanceCast; 127 | if (fieldInfo.IsStatic) 128 | instanceCast = null; 129 | else if (declaringType.GetTypeInfo().IsValueType) 130 | instanceCast = Expression.Convert(instance, declaringType); 131 | else 132 | instanceCast = Expression.TypeAs(instance, declaringType); 133 | 134 | var fieldAccess = Expression.Field(instanceCast, fieldInfo); 135 | var valueCast = Expression.TypeAs(fieldAccess, typeof(object)); 136 | 137 | var lambda = Expression.Lambda>(valueCast, instance); 138 | return lambda.Compile(); 139 | } 140 | 141 | public static Action CreateSet(PropertyInfo propertyInfo) 142 | { 143 | if (propertyInfo == null) 144 | throw new ArgumentNullException(nameof(propertyInfo)); 145 | 146 | if (!propertyInfo.CanWrite) 147 | return null; 148 | 149 | var instance = Expression.Parameter(typeof(object), "instance"); 150 | var value = Expression.Parameter(typeof(object), "value"); 151 | 152 | var declaringType = propertyInfo.DeclaringType; 153 | var propertyType = propertyInfo.PropertyType; 154 | var setMethod = propertyInfo.GetSetMethod(true); 155 | 156 | // value as T is slightly faster than (T)value, so if it's not a value type, use that 157 | UnaryExpression instanceCast; 158 | if (setMethod.IsStatic) 159 | instanceCast = null; 160 | else if (declaringType.GetTypeInfo().IsValueType) 161 | instanceCast = Expression.Convert(instance, declaringType); 162 | else 163 | instanceCast = Expression.TypeAs(instance, declaringType); 164 | 165 | UnaryExpression valueCast; 166 | if (propertyType.GetTypeInfo().IsValueType) 167 | valueCast = Expression.Convert(value, propertyType); 168 | else 169 | valueCast = Expression.TypeAs(value, propertyType); 170 | 171 | var call = Expression.Call(instanceCast, setMethod, valueCast); 172 | var parameters = new[] { instance, value }; 173 | 174 | var lambda = Expression.Lambda>(call, parameters); 175 | return lambda.Compile(); 176 | } 177 | 178 | public static Action CreateSet(FieldInfo fieldInfo) 179 | { 180 | if (fieldInfo == null) 181 | throw new ArgumentNullException(nameof(fieldInfo)); 182 | 183 | var instance = Expression.Parameter(typeof(object), "instance"); 184 | var value = Expression.Parameter(typeof(object), "value"); 185 | 186 | var declaringType = fieldInfo.DeclaringType; 187 | var fieldType = fieldInfo.FieldType; 188 | 189 | // value as T is slightly faster than (T)value, so if it's not a value type, use that 190 | UnaryExpression instanceCast; 191 | if (fieldInfo.IsStatic) 192 | instanceCast = null; 193 | else if (declaringType.GetTypeInfo().IsValueType) 194 | instanceCast = Expression.Convert(instance, declaringType); 195 | else 196 | instanceCast = Expression.TypeAs(instance, declaringType); 197 | 198 | UnaryExpression valueCast; 199 | if (fieldType.GetTypeInfo().IsValueType) 200 | valueCast = Expression.Convert(value, fieldType); 201 | else 202 | valueCast = Expression.TypeAs(value, fieldType); 203 | 204 | 205 | var member = Expression.Field(instanceCast, fieldInfo); 206 | var assign = Expression.Assign(member, valueCast); 207 | 208 | var parameters = new[] { instance, value }; 209 | 210 | var lambda = Expression.Lambda>(assign, parameters); 211 | return lambda.Compile(); 212 | } 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /src/DataGenerator/Reflection/FieldAccessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace DataGenerator.Reflection 5 | { 6 | /// 7 | /// An accessor class for . 8 | /// 9 | public class FieldAccessor : MemberAccessor 10 | { 11 | private readonly FieldInfo _fieldInfo; 12 | private readonly Lazy> _getter; 13 | private readonly Lazy> _setter; 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The instance to use for this accessor. 19 | public FieldAccessor(FieldInfo fieldInfo) 20 | { 21 | if (fieldInfo == null) 22 | throw new ArgumentNullException(nameof(fieldInfo)); 23 | 24 | _fieldInfo = fieldInfo; 25 | Name = fieldInfo.Name; 26 | MemberType = fieldInfo.FieldType; 27 | 28 | _getter = new Lazy>(() => DelegateFactory.CreateGet(_fieldInfo)); 29 | HasGetter = true; 30 | 31 | bool isReadonly = !fieldInfo.IsInitOnly && !fieldInfo.IsLiteral; 32 | if (!isReadonly) 33 | _setter = new Lazy>(() => DelegateFactory.CreateSet(_fieldInfo)); 34 | 35 | HasSetter = !isReadonly; 36 | } 37 | 38 | /// 39 | /// Gets the type of the member. 40 | /// 41 | /// The type of the member. 42 | public override Type MemberType { get; } 43 | 44 | /// 45 | /// Gets the member info. 46 | /// 47 | /// The member info. 48 | public override MemberInfo MemberInfo => _fieldInfo; 49 | 50 | /// 51 | /// Gets the name of the member. 52 | /// 53 | /// The name of the member. 54 | public override string Name { get; } 55 | 56 | /// 57 | /// Gets a value indicating whether this member has getter. 58 | /// 59 | /// true if this member has getter; otherwise, false. 60 | public override bool HasGetter { get; } 61 | 62 | /// 63 | /// Gets a value indicating whether this member has setter. 64 | /// 65 | /// true if this member has setter; otherwise, false. 66 | public override bool HasSetter { get; } 67 | 68 | 69 | /// 70 | /// Returns the value of the member. 71 | /// 72 | /// The object whose member value will be returned. 73 | /// 74 | /// The member value for the instance parameter. 75 | /// 76 | public override object GetValue(object instance) 77 | { 78 | if (instance == null) 79 | throw new ArgumentNullException(nameof(instance)); 80 | 81 | if (_getter == null || !HasGetter) 82 | throw new InvalidOperationException($"Field '{Name}' does not have a getter."); 83 | 84 | var get = _getter.Value; 85 | if (get == null) 86 | throw new InvalidOperationException($"Field '{Name}' does not have a getter."); 87 | 88 | return get(instance); 89 | } 90 | 91 | /// 92 | /// Sets the value of the member. 93 | /// 94 | /// The object whose member value will be set. 95 | /// The new value for this member. 96 | public override void SetValue(object instance, object value) 97 | { 98 | if (instance == null) 99 | throw new ArgumentNullException(nameof(instance)); 100 | 101 | if (_setter == null || !HasSetter) 102 | throw new InvalidOperationException($"Field '{Name}' does not have a setter."); 103 | 104 | var set = _setter.Value; 105 | if (set == null) 106 | throw new InvalidOperationException($"Field '{Name}' does not have a setter."); 107 | 108 | set(instance, value); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/DataGenerator/Reflection/IMemberAccessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator.Reflection 4 | { 5 | /// 6 | /// An for late binding member accessors. 7 | /// 8 | public interface IMemberAccessor : IMemberInfo 9 | { 10 | /// 11 | /// Returns the value of the member. 12 | /// 13 | /// The instance whose member value will be returned. 14 | /// The member value for the instance parameter. 15 | object GetValue(object instance); 16 | 17 | /// 18 | /// Sets the of the member. 19 | /// 20 | /// The instance whose member value will be set. 21 | /// The new value for this member. 22 | void SetValue(object instance, object value); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/DataGenerator/Reflection/IMemberInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace DataGenerator.Reflection 5 | { 6 | /// 7 | /// An interface for member information 8 | /// 9 | public interface IMemberInfo 10 | { 11 | /// 12 | /// Gets the type of the member. 13 | /// 14 | /// The type of the member. 15 | Type MemberType { get; } 16 | 17 | /// 18 | /// Gets the member info. 19 | /// 20 | /// The member info. 21 | MemberInfo MemberInfo { get; } 22 | 23 | /// 24 | /// Gets the name of the member. 25 | /// 26 | /// The name of the member. 27 | string Name { get; } 28 | 29 | /// 30 | /// Gets a value indicating whether this member has getter. 31 | /// 32 | /// 33 | /// true if this member has getter; otherwise, false. 34 | /// 35 | bool HasGetter { get; } 36 | 37 | /// 38 | /// Gets a value indicating whether this member has setter. 39 | /// 40 | /// 41 | /// true if this member has setter; otherwise, false. 42 | /// 43 | bool HasSetter { get; } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/DataGenerator/Reflection/IMethodAccessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace DataGenerator.Reflection 5 | { 6 | /// 7 | /// An interface for method accessor 8 | /// 9 | public interface IMethodAccessor 10 | { 11 | /// 12 | /// Gets the method info. 13 | /// 14 | MethodInfo MethodInfo { get; } 15 | 16 | /// 17 | /// Gets the name of the member. 18 | /// 19 | /// The name of the member. 20 | string Name { get; } 21 | 22 | /// 23 | /// Invokes the method on the specified . 24 | /// 25 | /// The object on which to invoke the method. If a method is static, this argument is ignored. 26 | /// An argument list for the invoked method. 27 | /// An object containing the return value of the invoked method. 28 | object Invoke(object instance, params object[] arguments); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/DataGenerator/Reflection/MemberAccessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Reflection; 4 | 5 | namespace DataGenerator.Reflection 6 | { 7 | /// 8 | /// A class for member accessors. 9 | /// 10 | [DebuggerDisplay("Name: {Name}")] 11 | public abstract class MemberAccessor : IMemberAccessor, IEquatable 12 | { 13 | /// 14 | /// Gets the of the member. 15 | /// 16 | /// The of the member. 17 | public abstract Type MemberType { get; } 18 | 19 | /// 20 | /// Gets the for the accessor. 21 | /// 22 | /// The member info. 23 | public abstract MemberInfo MemberInfo { get; } 24 | 25 | /// 26 | /// Gets the name of the member. 27 | /// 28 | /// The name of the member. 29 | public abstract string Name { get; } 30 | 31 | /// 32 | /// Gets a value indicating whether this member has getter. 33 | /// 34 | /// true if this member has getter; otherwise, false. 35 | public abstract bool HasGetter { get; } 36 | 37 | /// 38 | /// Gets a value indicating whether this member has setter. 39 | /// 40 | /// true if this member has setter; otherwise, false. 41 | public abstract bool HasSetter { get; } 42 | 43 | 44 | /// 45 | /// Returns the value of the member. 46 | /// 47 | /// The object whose member value will be returned. 48 | /// 49 | /// The member value for the instance parameter. 50 | /// 51 | public abstract object GetValue(object instance); 52 | 53 | /// 54 | /// Sets the value of the member. 55 | /// 56 | /// The object whose member value will be set. 57 | /// The new value for this member. 58 | public abstract void SetValue(object instance, object value); 59 | 60 | 61 | /// 62 | /// Determines whether the specified is equal to this instance. 63 | /// 64 | /// The to compare with this instance. 65 | /// 66 | /// true if the specified is equal to this instance; otherwise, false. 67 | /// 68 | public bool Equals(IMemberAccessor other) 69 | { 70 | if (ReferenceEquals(null, other)) 71 | return false; 72 | if (ReferenceEquals(this, other)) 73 | return true; 74 | 75 | return Equals(other.MemberInfo, MemberInfo); 76 | } 77 | 78 | /// 79 | /// Determines whether the specified is equal to this instance. 80 | /// 81 | /// The to compare with this instance. 82 | /// 83 | /// true if the specified is equal to this instance; otherwise, false. 84 | /// 85 | public override bool Equals(object obj) 86 | { 87 | if (ReferenceEquals(null, obj)) 88 | return false; 89 | if (ReferenceEquals(this, obj)) 90 | return true; 91 | if (obj.GetType() != typeof(MemberAccessor)) 92 | return false; 93 | 94 | return Equals((MemberAccessor)obj); 95 | } 96 | 97 | /// 98 | /// Returns a hash code for this instance. 99 | /// 100 | /// 101 | /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 102 | /// 103 | public override int GetHashCode() 104 | { 105 | return MemberInfo.GetHashCode(); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/DataGenerator/Reflection/MethodAccessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Reflection; 6 | 7 | namespace DataGenerator.Reflection 8 | { 9 | /// 10 | /// An accessor class for . 11 | /// 12 | [DebuggerDisplay("Name: {Name}")] 13 | public class MethodAccessor : IMethodAccessor 14 | { 15 | private readonly Lazy> _invoker; 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// The method info. 21 | public MethodAccessor(MethodInfo methodInfo) 22 | { 23 | if (methodInfo == null) 24 | throw new ArgumentNullException(nameof(methodInfo)); 25 | 26 | MethodInfo = methodInfo; 27 | Name = methodInfo.Name; 28 | _invoker = new Lazy>(() => DelegateFactory.CreateMethod(MethodInfo)); 29 | } 30 | 31 | /// 32 | /// Gets the method info. 33 | /// 34 | public MethodInfo MethodInfo { get; } 35 | 36 | /// 37 | /// Gets the name of the member. 38 | /// 39 | /// 40 | /// The name of the member. 41 | /// 42 | public string Name { get; } 43 | 44 | /// 45 | /// Invokes the method on the specified . 46 | /// 47 | /// The object on which to invoke the method. If a method is static, this argument is ignored. 48 | /// An argument list for the invoked method. 49 | /// 50 | /// An object containing the return value of the invoked method. 51 | /// 52 | public object Invoke(object instance, params object[] arguments) 53 | { 54 | return _invoker.Value.Invoke(instance, arguments); 55 | } 56 | 57 | /// 58 | /// Gets the method key using a hash code from the name and paremeter types. 59 | /// 60 | /// The name of the method. 61 | /// The method parameter types. 62 | /// The method key 63 | internal static int GetKey(string name, IEnumerable parameterTypes) 64 | { 65 | unchecked 66 | { 67 | int result = name?.GetHashCode() ?? 0; 68 | result = parameterTypes.Aggregate(result, 69 | (r, p) => (r * 397) ^ (p?.GetHashCode() ?? 0)); 70 | 71 | return result; 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/DataGenerator/Reflection/PropertyAccessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace DataGenerator.Reflection 5 | { 6 | /// 7 | /// An accessor class for . 8 | /// 9 | public class PropertyAccessor : MemberAccessor 10 | { 11 | private readonly PropertyInfo _propertyInfo; 12 | private readonly Lazy> _getter; 13 | private readonly Lazy> _setter; 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The instance to use for this accessor. 19 | public PropertyAccessor(PropertyInfo propertyInfo) 20 | { 21 | if (propertyInfo == null) 22 | throw new ArgumentNullException(nameof(propertyInfo)); 23 | 24 | _propertyInfo = propertyInfo; 25 | Name = _propertyInfo.Name; 26 | MemberType = _propertyInfo.PropertyType; 27 | 28 | HasGetter = _propertyInfo.CanRead; 29 | _getter = new Lazy>(() => DelegateFactory.CreateGet(_propertyInfo)); 30 | 31 | HasSetter = _propertyInfo.CanWrite; 32 | _setter = new Lazy>(() => DelegateFactory.CreateSet(_propertyInfo)); 33 | } 34 | 35 | 36 | /// 37 | /// Gets the type of the member. 38 | /// 39 | /// The type of the member. 40 | public override Type MemberType { get; } 41 | 42 | /// 43 | /// Gets the member info. 44 | /// 45 | /// The member info. 46 | public override MemberInfo MemberInfo => _propertyInfo; 47 | 48 | /// 49 | /// Gets the name of the member. 50 | /// 51 | /// The name of the member. 52 | public override string Name { get; } 53 | 54 | /// 55 | /// Gets a value indicating whether this member has getter. 56 | /// 57 | /// true if this member has getter; otherwise, false. 58 | public override bool HasGetter { get; } 59 | 60 | /// 61 | /// Gets a value indicating whether this member has setter. 62 | /// 63 | /// true if this member has setter; otherwise, false. 64 | public override bool HasSetter { get; } 65 | 66 | 67 | /// 68 | /// Returns the value of the member. 69 | /// 70 | /// The object whose member value will be returned. 71 | /// 72 | /// The member value for the instance parameter. 73 | /// 74 | public override object GetValue(object instance) 75 | { 76 | if (_getter == null || !HasGetter) 77 | throw new InvalidOperationException($"Property '{Name}' does not have a getter."); 78 | 79 | var get = _getter.Value; 80 | if (get == null) 81 | throw new InvalidOperationException($"Property '{Name}' does not have a getter."); 82 | 83 | return get(instance); 84 | } 85 | 86 | /// 87 | /// Sets the value of the member. 88 | /// 89 | /// The object whose member value will be set. 90 | /// The new value for this member. 91 | public override void SetValue(object instance, object value) 92 | { 93 | if (_setter == null || !HasSetter) 94 | throw new InvalidOperationException($"Property '{Name}' does not have a setter."); 95 | 96 | var set = _setter.Value; 97 | if (set == null) 98 | throw new InvalidOperationException($"Property '{Name}' does not have a setter."); 99 | 100 | set(instance, value); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/DataGenerator/Reflection/ReflectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Reflection.Emit; 6 | 7 | namespace DataGenerator.Reflection 8 | { 9 | internal static class ReflectionExtensions 10 | { 11 | public static void PushInstance(this ILGenerator generator, Type type) 12 | { 13 | generator.Emit(OpCodes.Ldarg_0); 14 | if (type.GetTypeInfo().IsValueType) 15 | generator.Emit(OpCodes.Unbox, type); 16 | else 17 | generator.Emit(OpCodes.Castclass, type); 18 | } 19 | 20 | public static void BoxIfNeeded(this ILGenerator generator, Type type) 21 | { 22 | if (type.GetTypeInfo().IsValueType) 23 | generator.Emit(OpCodes.Box, type); 24 | else 25 | generator.Emit(OpCodes.Castclass, type); 26 | } 27 | 28 | public static void UnboxIfNeeded(this ILGenerator generator, Type type) 29 | { 30 | if (type.GetTypeInfo().IsValueType) 31 | generator.Emit(OpCodes.Unbox_Any, type); 32 | else 33 | generator.Emit(OpCodes.Castclass, type); 34 | } 35 | 36 | public static void CallMethod(this ILGenerator generator, MethodInfo methodInfo) 37 | { 38 | if (methodInfo.IsFinal || !methodInfo.IsVirtual) 39 | generator.Emit(OpCodes.Call, methodInfo); 40 | else 41 | generator.Emit(OpCodes.Callvirt, methodInfo); 42 | } 43 | 44 | public static void Return(this ILGenerator generator) 45 | { 46 | generator.Emit(OpCodes.Ret); 47 | } 48 | 49 | public static void FastInt(this ILGenerator il, int value) 50 | { 51 | switch (value) 52 | { 53 | case -1: 54 | il.Emit(OpCodes.Ldc_I4_M1); 55 | return; 56 | case 0: 57 | il.Emit(OpCodes.Ldc_I4_0); 58 | return; 59 | case 1: 60 | il.Emit(OpCodes.Ldc_I4_1); 61 | return; 62 | case 2: 63 | il.Emit(OpCodes.Ldc_I4_2); 64 | return; 65 | case 3: 66 | il.Emit(OpCodes.Ldc_I4_3); 67 | return; 68 | case 4: 69 | il.Emit(OpCodes.Ldc_I4_4); 70 | return; 71 | case 5: 72 | il.Emit(OpCodes.Ldc_I4_5); 73 | return; 74 | case 6: 75 | il.Emit(OpCodes.Ldc_I4_6); 76 | return; 77 | case 7: 78 | il.Emit(OpCodes.Ldc_I4_7); 79 | return; 80 | case 8: 81 | il.Emit(OpCodes.Ldc_I4_8); 82 | return; 83 | } 84 | 85 | if (value > -129 && value < 128) 86 | { 87 | il.Emit(OpCodes.Ldc_I4_S, (SByte)value); 88 | } 89 | else 90 | { 91 | il.Emit(OpCodes.Ldc_I4, value); 92 | } 93 | } 94 | 95 | 96 | #if NET40 97 | public static Type GetTypeInfo(this Type type) 98 | { 99 | return type; 100 | } 101 | #endif 102 | 103 | #if NETSTANDARD1_3 104 | public static Type[] GetInterfaces(this TypeInfo type) 105 | { 106 | var types = new List(); 107 | var t = type.AsType(); 108 | while (t != null) 109 | { 110 | var ti = t.GetTypeInfo(); 111 | types.AddRange(ti.ImplementedInterfaces); 112 | t = ti.BaseType; 113 | } 114 | 115 | return types.ToArray(); 116 | } 117 | 118 | public static Type[] GetGenericArguments(this TypeInfo type) 119 | { 120 | return type.GenericTypeArguments; 121 | } 122 | #endif 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/DataGenerator/Sources/BooleanSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace DataGenerator.Sources 5 | { 6 | /// 7 | /// Data source for boolean values 8 | /// 9 | /// 10 | public class BooleanSource : DataSourcePropertyType 11 | { 12 | 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// 16 | public BooleanSource() 17 | : base(new[] { typeof(bool) }) 18 | { 19 | } 20 | 21 | 22 | /// 23 | /// Get a value from the data source. 24 | /// 25 | /// The generate context. 26 | /// 27 | /// A new value from the data source. 28 | /// 29 | public override object NextValue(IGenerateContext generateContext) 30 | { 31 | return RandomGenerator.Current.Next(2) == 1; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/DataGenerator/Sources/CitySource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace DataGenerator.Sources 5 | { 6 | /// 7 | /// City name data source generator 8 | /// 9 | /// 10 | public class CitySource : DataSourceMatchName 11 | { 12 | private static readonly string[] _names = { "City" }; 13 | private static readonly Type[] _types = { typeof(string) }; 14 | private static readonly string[] _cities = 15 | { 16 | "New York", "Los Angeles", "Chicago", "Houston", "Philadelphia", 17 | "Phoenix", "San Diego", "San Antonio", "Dallas", "Detroit", "San Jose", 18 | "Indianapolis", "Jacksonville", "San Francisco", "Columbus", "Austin", 19 | "Memphis", "Baltimore", "Charlotte", "Fort Worth", "Boston", "Milwaukee", 20 | "El Paso", "Washington", "Nashville-Davidson", "Seattle", "Denver", 21 | "Las Vegas", "Portland", "Oklahoma City", "Tucson", "Albuquerque", 22 | "Atlanta", "Long Beach", "Kansas City", "Fresno", "New Orleans", 23 | "Cleveland", "Sacramento", "Mesa", "Virginia Beach", "Omaha", 24 | "Colorado Springs", "Oakland", "Miami", "Tulsa", "Minneapolis", 25 | "Honolulu", "Arlington", "Wichita", "St. Louis", "Raleigh", "Santa Ana", 26 | "Cincinnati", "Anaheim", "Tampa", "Toledo", "Pittsburgh", "Aurora", 27 | "Bakersfield", "Riverside", "Stockton", "Corpus Christi", 28 | "Lexington-Fayette", "Buffalo", "St. Paul", "Anchorage", "Newark", 29 | "Plano", "Fort Wayne", "St. Petersburg", "Glendale", "Lincoln", 30 | "Norfolk", "Jersey City", "Greensboro", "Chandler", "Birmingham", 31 | "Henderson", "Scottsdale", "North Hempstead", "Madison", "Hialeah", 32 | "Baton Rouge", "Chesapeake", "Orlando", "Lubbock", "Garland", "Akron", 33 | "Rochester", "Chula Vista", "Reno", "Laredo", "Durham", "Modesto", 34 | "Huntington", "Montgomery", "Boise", "Arlington", "San Bernardino" 35 | }; 36 | 37 | /// 38 | /// Initializes a new instance of the class. 39 | /// 40 | public CitySource() : base(_types, _names) 41 | { 42 | } 43 | 44 | /// 45 | /// Get a value from the data source. 46 | /// 47 | /// The generate context. 48 | /// 49 | /// A new value from the data source. 50 | /// 51 | public override object NextValue(IGenerateContext generateContext) 52 | { 53 | var i = RandomGenerator.Current.Next(0, _cities.Length); 54 | return _cities[i]; 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /src/DataGenerator/Sources/CreditCardSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using DataGenerator.Extensions; 7 | 8 | namespace DataGenerator.Sources 9 | { 10 | /// 11 | /// Credit card data source generator 12 | /// 13 | /// 14 | public class CreditCardSource : DataSourceMatchName 15 | { 16 | /// 17 | /// Credit card types 18 | /// 19 | public enum CreditCardType 20 | { 21 | /// Visa credit card 22 | Visa, 23 | /// Mastercard credit card 24 | Mastercard, 25 | /// American Express credit card 26 | AmericanExpress, 27 | /// Discover credit card 28 | Discover 29 | } 30 | 31 | private static readonly string[] _names = { "CreditCard", "CardNumber" }; 32 | private static readonly Type[] _types = { typeof(string) }; 33 | 34 | private static readonly List> _cardTypes = new List> 35 | { 36 | new WeightedValue(CreditCardType.Visa, 3), 37 | new WeightedValue(CreditCardType.Mastercard, 3), 38 | new WeightedValue(CreditCardType.AmericanExpress, 2), 39 | new WeightedValue(CreditCardType.Discover, 1) 40 | }; 41 | 42 | /// 43 | /// Initializes a new instance of the class. 44 | /// 45 | public CreditCardSource() : base(_types, _names) 46 | { 47 | } 48 | 49 | 50 | /// 51 | /// Get a value from the data source. 52 | /// 53 | /// The generate context. 54 | /// 55 | /// A new value from the data source. 56 | /// 57 | public override object NextValue(IGenerateContext generateContext) 58 | { 59 | // random card type 60 | var type = _cardTypes.Random(p => p.Weight); 61 | return GenerateNumber(type); 62 | } 63 | 64 | 65 | /// 66 | /// Generates a random credit card number. 67 | /// 68 | /// Type of the credit card. 69 | /// 70 | public static string GenerateNumber(CreditCardType cardType) 71 | { 72 | int pos = 0; 73 | int[] number = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 74 | int sum = 0; 75 | int finalDigit = 0; 76 | int lenOffset = 0; 77 | int len = 0; 78 | 79 | // Fill in the first values of the string based with the specified bank's prefix. 80 | switch (cardType) 81 | { 82 | case CreditCardType.Visa: 83 | number[0] = 4; 84 | pos = 1; 85 | len = 16; 86 | break; 87 | case CreditCardType.Mastercard: 88 | number[0] = 5; 89 | number[1] = RandomGenerator.Current.Next(1, 5); // Between 1 and 5. 90 | pos = 2; 91 | len = 16; 92 | break; 93 | case CreditCardType.AmericanExpress: 94 | number[0] = 3; 95 | number[1] = RandomGenerator.Current.Next(4, 7); // Between 4 and 7. 96 | pos = 2; 97 | len = 15; 98 | break; 99 | case CreditCardType.Discover: 100 | number[0] = 6; 101 | number[1] = 0; 102 | number[2] = 1; 103 | number[3] = 1; 104 | pos = 4; 105 | len = 16; 106 | break; 107 | } 108 | 109 | // Fill all the remaining numbers except for the last one with random values. 110 | while (pos < len - 1) 111 | number[pos++] = RandomGenerator.Current.Next(0, 9); 112 | 113 | // Calculate the Luhn checksum of the values thus far. 114 | lenOffset = (len + 1) % 2; 115 | for (pos = 0; pos < len - 1; pos++) 116 | { 117 | if ((pos + lenOffset) % 2 != 0) 118 | { 119 | var t = number[pos] * 2; 120 | if (t > 9) 121 | t -= 9; 122 | sum += t; 123 | } 124 | else 125 | { 126 | sum += number[pos]; 127 | } 128 | } 129 | 130 | // Choose the last digit so that it causes the entire string to pass the checksum. 131 | finalDigit = (10 - (sum % 10)) % 10; 132 | number[len - 1] = finalDigit; 133 | 134 | var buffer = new StringBuilder(); 135 | foreach (var n in number) 136 | buffer.Append(n); 137 | 138 | return buffer.ToString(); 139 | } 140 | 141 | /// 142 | /// Determines whether the credit card number is valid. 143 | /// 144 | /// The credit card number. 145 | /// 146 | /// 147 | /// Extremely fast Luhn algorithm implementation, based on 148 | /// pseudo code from Cliff L. Biffle (http://microcoder.livejournal.com/17175.html) 149 | /// Copyleft Thomas @ Orb of Knowledge: 150 | /// http://orb-of-knowledge.blogspot.com/2009/08/extremely-fast-luhn-function-for-c.html 151 | /// 152 | public static bool IsValidNumber(string number) 153 | { 154 | int[] DELTAS = { 0, 1, 2, 3, 4, -4, -3, -2, -1, 0 }; 155 | int checksum = 0; 156 | char[] chars = number.ToCharArray(); 157 | for (int i = chars.Length - 1; i > -1; i--) 158 | { 159 | int j = chars[i] - 48; 160 | checksum += j; 161 | if (((i - chars.Length) % 2) == 0) 162 | checksum += DELTAS[j]; 163 | } 164 | 165 | return ((checksum % 10) == 0); 166 | } 167 | 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/DataGenerator/Sources/DataSourceBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator.Sources 4 | { 5 | /// 6 | /// A base class for data sources. 7 | /// 8 | /// 9 | public abstract class DataSourceBase : IDataSourceDiscover 10 | { 11 | /// 12 | /// The match name priority 13 | /// 14 | public const int MatchNamePriority = 0099; 15 | /// 16 | /// The contain name priority 17 | /// 18 | public const int ContainNamePriority = 0999; 19 | /// 20 | /// The property type priority 21 | /// 22 | public const int PropertyTypePriority = 9999; 23 | 24 | 25 | /// 26 | /// Initializes a new instance of the class. 27 | /// 28 | protected DataSourceBase() : this(int.MaxValue) 29 | { 30 | } 31 | 32 | /// 33 | /// Initializes a new instance of the class. 34 | /// 35 | /// The priority of the data source. 36 | protected DataSourceBase(int priority) 37 | { 38 | Priority = priority; 39 | } 40 | 41 | /// 42 | /// Gets the priority of the data source. 43 | /// 44 | /// 45 | /// The priority of the data source. 46 | /// 47 | public int Priority { get; } 48 | 49 | 50 | /// 51 | /// Test if the current can use this data source. 52 | /// 53 | /// The mapping context. 54 | /// 55 | /// true if this data source can be used; otherwise false. 56 | /// 57 | public abstract bool TryMap(IMappingContext mappingContext); 58 | 59 | /// 60 | /// Get a value from the data source. 61 | /// 62 | /// The generate context. 63 | /// 64 | /// A new value from the data source. 65 | /// 66 | public abstract object NextValue(IGenerateContext generateContext); 67 | } 68 | } -------------------------------------------------------------------------------- /src/DataGenerator/Sources/DataSourceContainName.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace DataGenerator.Sources 6 | { 7 | /// 8 | /// A base class for data source property names pattern match 9 | /// 10 | /// 11 | public abstract class DataSourceContainName : DataSourcePropertyType 12 | { 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// 16 | /// The types. 17 | /// The names. 18 | protected DataSourceContainName(IEnumerable types, IEnumerable names) 19 | : this(DataSourceBase.MatchNamePriority, types, names) 20 | { 21 | } 22 | 23 | /// 24 | /// Initializes a new instance of the class. 25 | /// 26 | /// The priority. 27 | /// The types. 28 | /// The names. 29 | protected DataSourceContainName(int priority, IEnumerable types, IEnumerable names) 30 | : base(priority, types) 31 | { 32 | Names = names; 33 | } 34 | 35 | /// 36 | /// Gets the name patterns this data source will generate values for. 37 | /// 38 | /// 39 | /// The name patterns this data source will generate values for.. 40 | /// 41 | public IEnumerable Names { get; } 42 | 43 | 44 | /// 45 | /// Test if the current can use this data source. 46 | /// 47 | /// The mapping context. 48 | /// 49 | /// true if this data source can be used; otherwise false. 50 | /// 51 | public override bool TryMap(IMappingContext mappingContext) 52 | { 53 | var name = mappingContext?.MemberMapping?.MemberAccessor?.Name ?? string.Empty; 54 | return base.TryMap(mappingContext) 55 | && Names.Any(n => name.IndexOf(n, StringComparison.OrdinalIgnoreCase) >= 0); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /src/DataGenerator/Sources/DataSourceMatchName.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace DataGenerator.Sources 6 | { 7 | /// 8 | /// A base class for data source property names 9 | /// 10 | /// 11 | public abstract class DataSourceMatchName : DataSourcePropertyType 12 | { 13 | 14 | /// 15 | /// Initializes a new instance of the class. 16 | /// 17 | /// The types. 18 | /// The names. 19 | protected DataSourceMatchName(IEnumerable types, IEnumerable names) 20 | : this(DataSourceBase.MatchNamePriority, types, names) 21 | { 22 | } 23 | 24 | /// 25 | /// Initializes a new instance of the class. 26 | /// 27 | /// The priority. 28 | /// The types. 29 | /// The names. 30 | protected DataSourceMatchName(int priority, IEnumerable types, IEnumerable names) 31 | : base(priority, types) 32 | { 33 | Names = names; 34 | } 35 | 36 | /// 37 | /// Gets the names this data source will generate values for. 38 | /// 39 | /// 40 | /// The names this data source will generate values for.. 41 | /// 42 | public IEnumerable Names { get; } 43 | 44 | 45 | /// 46 | /// Test if the current can use this data source. 47 | /// 48 | /// The mapping context. 49 | /// 50 | /// true if this data source can be used; otherwise false. 51 | /// 52 | public override bool TryMap(IMappingContext mappingContext) 53 | { 54 | var name = mappingContext?.MemberMapping?.MemberAccessor?.Name; 55 | return base.TryMap(mappingContext) 56 | && Names.Any(n => string.Equals(name, n, StringComparison.OrdinalIgnoreCase)); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /src/DataGenerator/Sources/DataSourcePropertyType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace DataGenerator.Sources 6 | { 7 | /// 8 | /// A base class for data source property types 9 | /// 10 | /// 11 | public abstract class DataSourcePropertyType : DataSourceBase 12 | { 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// 16 | /// The types. 17 | protected DataSourcePropertyType(IEnumerable types) 18 | : this(DataSourceBase.PropertyTypePriority, types) 19 | { 20 | } 21 | 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// The priority. 26 | /// The types. 27 | /// 28 | protected DataSourcePropertyType(int priority, IEnumerable types) 29 | : base(priority) 30 | { 31 | if (types == null) 32 | throw new ArgumentNullException(nameof(types)); 33 | 34 | Types = types; 35 | } 36 | 37 | /// 38 | /// Gets the types this data source will generate values for. 39 | /// 40 | /// 41 | /// The types this data source will generate values for. 42 | /// 43 | public IEnumerable Types { get; } 44 | 45 | /// 46 | /// Test if the current can use this data source. 47 | /// 48 | /// The mapping context. 49 | /// 50 | /// true if this data source can be used; otherwise false. 51 | /// 52 | public override bool TryMap(IMappingContext mappingContext) 53 | { 54 | var memberType = mappingContext?.MemberMapping?.MemberAccessor?.MemberType; 55 | return Types.Any(t => t == memberType); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /src/DataGenerator/Sources/DateTimeSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator.Sources 4 | { 5 | /// 6 | /// data source generator 7 | /// 8 | /// 9 | public class DateTimeSource : DataSourcePropertyType 10 | { 11 | private readonly DateTime _min; 12 | private readonly DateTime _max; 13 | 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | public DateTimeSource() 19 | : base(new[] { typeof(DateTime), typeof(DateTimeOffset) }) 20 | { 21 | int year = DateTime.Now.Year; 22 | _min = new DateTime(year - 10, 1, 1); 23 | _max = new DateTime(year + 3, 1, 1); 24 | } 25 | 26 | 27 | /// 28 | /// Initializes a new instance of the class. 29 | /// 30 | /// The minimum value. 31 | /// The maximum value. 32 | public DateTimeSource(DateTime min, DateTime max) 33 | : base(new[] { typeof(DateTime), typeof(DateTimeOffset) }) 34 | { 35 | _min = min; 36 | _max = max; 37 | } 38 | 39 | 40 | /// 41 | /// Get a value from the data source. 42 | /// 43 | /// The generate context. 44 | /// 45 | /// A new value from the data source. 46 | /// 47 | public override object NextValue(IGenerateContext generateContext) 48 | { 49 | var range = (_max - _min).Ticks; 50 | var ticks = (long)(RandomGenerator.Current.NextDouble() * range); 51 | 52 | var nextValue = _min.AddTicks(ticks); 53 | 54 | if (generateContext?.MemberType == typeof(DateTimeOffset)) 55 | return new DateTimeOffset(nextValue); 56 | 57 | return nextValue; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/DataGenerator/Sources/DateTimeSourceExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Fluent; 3 | 4 | namespace DataGenerator.Sources 5 | { 6 | /// 7 | /// data source extension methods 8 | /// 9 | /// 10 | public static class DateTimeSourceExtensions 11 | { 12 | /// 13 | /// Use the data source with the specified and values 14 | /// 15 | /// The type of the entity. 16 | /// The member configuration builder. 17 | /// The minimum value. 18 | /// The maximum value. 19 | /// Fluent builder for an entity property. 20 | public static MemberConfigurationBuilder DateTimeSource(this MemberConfigurationBuilder builder, DateTime min, DateTime max) 21 | { 22 | builder.DataSource(() => new DateTimeSource(min, max)); 23 | return builder; 24 | } 25 | 26 | /// 27 | /// Use the data source with the specified and values 28 | /// 29 | /// The type of the entity. 30 | /// The member configuration builder. 31 | /// The minimum value. 32 | /// The maximum value. 33 | /// Fluent builder for an entity property. 34 | public static MemberConfigurationBuilder DateTimeSource(this MemberConfigurationBuilder builder, DateTime min, DateTime max) 35 | { 36 | builder.DataSource(() => new DateTimeSource(min, max)); 37 | return builder; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/DataGenerator/Sources/DecimalSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator.Sources 4 | { 5 | /// 6 | /// data source generator 7 | /// 8 | /// 9 | public class DecimalSource : DataSourcePropertyType 10 | { 11 | private readonly decimal _min; 12 | private readonly decimal _max; 13 | private readonly int? _decimals; 14 | 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | public DecimalSource() 20 | : this(0, 1000000, 2) 21 | { 22 | } 23 | 24 | /// 25 | /// Initializes a new instance of the class. 26 | /// 27 | /// The minimum value. 28 | /// The maximum value. 29 | public DecimalSource(decimal min, decimal max) 30 | : this(min, max, 2) 31 | { 32 | } 33 | 34 | /// 35 | /// Initializes a new instance of the class. 36 | /// 37 | /// The minimum value. 38 | /// The maximum value. 39 | /// The number of decimal places. 40 | public DecimalSource(decimal min, decimal max, int decimals) 41 | : base(new[] { typeof(decimal) }) 42 | { 43 | _min = min; 44 | _max = max; 45 | _decimals = decimals; 46 | } 47 | 48 | 49 | /// 50 | /// Get a value from the data source. 51 | /// 52 | /// The generate context. 53 | /// 54 | /// A new value from the data source. 55 | /// 56 | public override object NextValue(IGenerateContext generateContext) 57 | { 58 | // Perform arithmetic in double type to avoid overflowing 59 | var range = (double)_max - (double)_min; 60 | var sample = RandomGenerator.Current.NextDouble(); 61 | var scaled = (sample * range) + (double)_min; 62 | 63 | return _decimals.HasValue 64 | ? Math.Round((decimal)scaled, _decimals.Value) 65 | : (decimal)scaled; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/DataGenerator/Sources/DecimalSourceExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Fluent; 3 | 4 | namespace DataGenerator.Sources 5 | { 6 | /// 7 | /// data source extension methods 8 | /// 9 | /// 10 | public static class DecimalSourceExtensions 11 | { 12 | /// 13 | /// Use the data source with the specified and values 14 | /// 15 | /// The type of the entity. 16 | /// The member configuration builder. 17 | /// The minimum value. 18 | /// The maximum value. 19 | /// Fluent builder for an entity property. 20 | public static MemberConfigurationBuilder DecimalSource(this MemberConfigurationBuilder builder, decimal min, decimal max) 21 | { 22 | builder.DataSource(() => new DecimalSource(min, max)); 23 | return builder; 24 | } 25 | 26 | /// 27 | /// Use the data source with the specified and values 28 | /// 29 | /// The type of the entity. 30 | /// The member configuration builder. 31 | /// The minimum value. 32 | /// The maximum value. 33 | /// The number of decimal places. 34 | /// Fluent builder for an entity property. 35 | public static MemberConfigurationBuilder DecimalSource(this MemberConfigurationBuilder builder, decimal min, decimal max, int decimals) 36 | { 37 | builder.DataSource(() => new DecimalSource(min, max, decimals)); 38 | return builder; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/DataGenerator/Sources/EmailSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator.Sources 4 | { 5 | /// 6 | /// Email address data source generator 7 | /// 8 | /// 9 | public class EmailSource : DataSourceMatchName 10 | { 11 | private static readonly string[] _names = { "EmailAddress", "Email" }; 12 | private static readonly Type[] _types = { typeof(string) }; 13 | private static readonly string[] _domains = { 14 | "gmail.com", 15 | "msn.com", 16 | "outlook.com", 17 | "hotmail.com", 18 | "aol.com", 19 | "yahoo.com" 20 | }; 21 | 22 | private int _index; 23 | private readonly string _domain = ""; 24 | 25 | /// 26 | /// Initializes a new instance of the class. 27 | /// 28 | public EmailSource() : this(null) 29 | { 30 | } 31 | 32 | 33 | /// 34 | /// Initializes a new instance of the class. 35 | /// 36 | /// The domain. 37 | public EmailSource(string domain) : base(_types, _names) 38 | { 39 | _domain = domain; 40 | } 41 | 42 | /// 43 | /// Get a value from the data source. 44 | /// 45 | /// The generate context. 46 | /// 47 | /// A new value from the data source. 48 | /// 49 | public override object NextValue(IGenerateContext generateContext) 50 | { 51 | int i = RandomGenerator.Current.Next(0, _domains.Length); 52 | string name = PasswordSource.Generate(8); 53 | string domain = string.IsNullOrEmpty(_domain) 54 | ? _domains[i] 55 | : _domain.Trim(); 56 | 57 | return string.Format("{0}{1}@{2}", name, _index++, domain); 58 | } 59 | 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/DataGenerator/Sources/EnumSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using DataGenerator.Reflection; 6 | 7 | namespace DataGenerator.Sources 8 | { 9 | /// 10 | /// Enum value data source 11 | /// 12 | /// 13 | public class EnumSource : DataSourceBase 14 | { 15 | /// 16 | /// Test if the current can use this data source. 17 | /// 18 | /// The mapping context. 19 | /// 20 | /// true if this data source can be used; otherwise false. 21 | /// 22 | public override bool TryMap(IMappingContext mappingContext) 23 | { 24 | var memberType = mappingContext?.MemberMapping?.MemberAccessor?.MemberType; 25 | if (memberType == null) 26 | return false; 27 | 28 | return memberType.GetTypeInfo().IsEnum == true; 29 | } 30 | 31 | /// 32 | /// Get a value from the data source. 33 | /// 34 | /// The generate context. 35 | /// 36 | /// A new value from the data source. 37 | /// 38 | public override object NextValue(IGenerateContext generateContext) 39 | { 40 | var values = Enum.GetValues(generateContext.MemberType); 41 | var index = RandomGenerator.Current.Next(values.Length); 42 | 43 | return values.GetValue(index); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/DataGenerator/Sources/FactoryDataSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator.Sources 4 | { 5 | /// 6 | /// Data source to generate a value with a factory method 7 | /// 8 | /// The type of the instance. 9 | /// Type returned from the factory method 10 | /// 11 | public class FactoryDataSource : IDataSource 12 | { 13 | 14 | /// 15 | /// Initializes a new instance of the class. 16 | /// 17 | /// The factory. 18 | public FactoryDataSource(Func factory) 19 | { 20 | Factory = factory; 21 | } 22 | 23 | /// 24 | /// Gets the factory method to generate a value with. 25 | /// 26 | /// 27 | /// The factory method to generate a value with. 28 | /// 29 | public Func Factory { get; } 30 | 31 | /// 32 | /// Get a value from the data source. 33 | /// 34 | /// The generate context. 35 | /// 36 | /// A new value from the data source. 37 | /// 38 | public object NextValue(IGenerateContext generateContext) 39 | { 40 | var instance = generateContext.Instance is TEntity 41 | ? (TEntity)generateContext.Instance 42 | : default(TEntity); 43 | 44 | return Factory(instance); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /src/DataGenerator/Sources/FloatSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator.Sources 4 | { 5 | /// 6 | /// data source value generator 7 | /// 8 | /// 9 | public class FloatSource : DataSourcePropertyType 10 | { 11 | private readonly float _min; 12 | private readonly float _max; 13 | private readonly int? _decimals; 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | public FloatSource() 19 | : this(0, 1000000, 2) 20 | { 21 | } 22 | 23 | /// 24 | /// Initializes a new instance of the class. 25 | /// 26 | /// The minimum value. 27 | /// The maximum value. 28 | public FloatSource(float min, float max) 29 | : this(min, max, 0) 30 | { 31 | } 32 | 33 | /// 34 | /// Initializes a new instance of the class. 35 | /// 36 | /// The minimum value. 37 | /// The maximum value. 38 | /// The number of decimal places. 39 | public FloatSource(float min, float max, int decimals) 40 | : base(new[] { typeof(float), typeof(double) }) 41 | { 42 | _min = min; 43 | _max = max; 44 | _decimals = decimals; 45 | } 46 | 47 | /// 48 | /// Get a value from the data source. 49 | /// 50 | /// The generate context. 51 | /// 52 | /// A new value from the data source. 53 | /// 54 | public override object NextValue(IGenerateContext generateContext) 55 | { 56 | // Perform arithmetic in double type to avoid overflowing 57 | var range = (double)_max - _min; 58 | var sample = RandomGenerator.Current.NextDouble(); 59 | var scaled = (sample * range) + _min; 60 | 61 | return _decimals == null 62 | ? (float)scaled 63 | : Math.Round(scaled, _decimals.Value); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/DataGenerator/Sources/FloatSourceExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Fluent; 3 | 4 | namespace DataGenerator.Sources 5 | { 6 | /// 7 | /// and data source extension methods 8 | /// 9 | /// 10 | public static class FloatSourceExtensions 11 | { 12 | /// 13 | /// Use the data source with the specified and values 14 | /// 15 | /// The type of the entity. 16 | /// The member configuration builder. 17 | /// The minimum value. 18 | /// The maximum value. 19 | /// Fluent builder for an entity property. 20 | public static MemberConfigurationBuilder FloatSource(this MemberConfigurationBuilder builder, float min, float max) 21 | { 22 | builder.DataSource(() => new FloatSource(min, max)); 23 | return builder; 24 | } 25 | 26 | /// 27 | /// Use the data source with the specified and values 28 | /// 29 | /// The type of the entity. 30 | /// The member configuration builder. 31 | /// The minimum value. 32 | /// The maximum value. 33 | /// The number of decimal places. 34 | /// Fluent builder for an entity property. 35 | public static MemberConfigurationBuilder FloatSource(this MemberConfigurationBuilder builder, float min, float max, int decimals) 36 | { 37 | builder.DataSource(() => new FloatSource(min, max, decimals)); 38 | return builder; 39 | } 40 | 41 | /// 42 | /// Use the data source with the specified and values 43 | /// 44 | /// The type of the entity. 45 | /// The member configuration builder. 46 | /// The minimum value. 47 | /// The maximum value. 48 | /// Fluent builder for an entity property. 49 | public static MemberConfigurationBuilder FloatSource(this MemberConfigurationBuilder builder, float min, float max) 50 | { 51 | builder.DataSource(() => new FloatSource(min, max)); 52 | return builder; 53 | } 54 | 55 | /// 56 | /// Use the data source with the specified and values 57 | /// 58 | /// The type of the entity. 59 | /// The member configuration builder. 60 | /// The minimum value. 61 | /// The maximum value. 62 | /// The number of decimal places. 63 | /// Fluent builder for an entity property. 64 | public static MemberConfigurationBuilder FloatSource(this MemberConfigurationBuilder builder, float min, float max, int decimals) 65 | { 66 | builder.DataSource(() => new FloatSource(min, max, decimals)); 67 | return builder; 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /src/DataGenerator/Sources/GenerateListSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator.Sources 4 | { 5 | /// 6 | /// Generate a list of values data source 7 | /// 8 | /// Type of values 9 | /// 10 | public class GenerateListSource : IDataSource 11 | { 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | /// The number of values to generate. 16 | public GenerateListSource(int count) 17 | { 18 | Count = count; 19 | } 20 | 21 | /// 22 | /// Gets the number of values to generate. 23 | /// 24 | /// 25 | /// The number of values to generate. 26 | /// 27 | public int Count { get; } 28 | 29 | /// 30 | /// Get a value from the data source. 31 | /// 32 | /// The generate context. 33 | /// 34 | /// A new value from the data source. 35 | /// 36 | public object NextValue(IGenerateContext generateContext) 37 | { 38 | return generateContext.Generator.List(Count); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/DataGenerator/Sources/GenerateSingleSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator.Sources 4 | { 5 | /// 6 | /// Generate single value data source 7 | /// 8 | /// Type to generate 9 | /// 10 | public class GenerateSingleSource : IDataSource 11 | { 12 | /// 13 | /// Get a value from the data source. 14 | /// 15 | /// The generate context. 16 | /// 17 | /// A new value from the data source. 18 | /// 19 | public object NextValue(IGenerateContext generateContext) 20 | { 21 | return generateContext.Generator.Single(); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/DataGenerator/Sources/GuidSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator.Sources 4 | { 5 | /// 6 | /// value generator data source 7 | /// 8 | /// 9 | public class GuidSource : DataSourcePropertyType 10 | { 11 | private static readonly Type[] _types = { typeof(Guid) }; 12 | 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// 16 | public GuidSource() : base(_types) 17 | { 18 | } 19 | 20 | /// 21 | /// Get a value from the data source. 22 | /// 23 | /// The generate context. 24 | /// 25 | /// A new value from the data source. 26 | /// 27 | public override object NextValue(IGenerateContext generateContext) 28 | { 29 | return Guid.NewGuid(); 30 | } 31 | 32 | } 33 | } -------------------------------------------------------------------------------- /src/DataGenerator/Sources/IdentifierSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator.Sources 4 | { 5 | /// 6 | /// Identifier value generator data source 7 | /// 8 | /// 9 | public class IdentifierSource : DataSourceMatchName 10 | { 11 | private static readonly string[] _names = { "Id" }; 12 | private static readonly Type[] _types = { typeof(string) }; 13 | 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | public IdentifierSource() : base(_types, _names) 19 | { 20 | } 21 | 22 | /// 23 | /// Get a value from the data source. 24 | /// 25 | /// The generate context. 26 | /// 27 | /// A new value from the data source. 28 | /// 29 | public override object NextValue(IGenerateContext generateContext) 30 | { 31 | return Guid.NewGuid().ToString(); 32 | } 33 | 34 | } 35 | } -------------------------------------------------------------------------------- /src/DataGenerator/Sources/IntegerSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator.Sources 4 | { 5 | /// 6 | /// Integer value generator data source 7 | /// 8 | /// 9 | public class IntegerSource : DataSourcePropertyType 10 | { 11 | private readonly int _min; 12 | private readonly int _max; 13 | 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | public IntegerSource() 19 | : this(0, short.MaxValue) 20 | { 21 | } 22 | 23 | /// 24 | /// Initializes a new instance of the class. 25 | /// 26 | /// The minimum. 27 | /// The maximum. 28 | public IntegerSource(int min, int max) 29 | : base(new[] { typeof(short), typeof(int), typeof(long) }) 30 | { 31 | _min = min; 32 | _max = max; 33 | } 34 | 35 | 36 | /// 37 | /// Get a value from the data source. 38 | /// 39 | /// The generate context. 40 | /// 41 | /// A new value from the data source. 42 | /// 43 | public override object NextValue(IGenerateContext generateContext) 44 | { 45 | return RandomGenerator.Current.Next(_min, _max); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/DataGenerator/Sources/IntegerSourceExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Fluent; 3 | 4 | namespace DataGenerator.Sources 5 | { 6 | /// 7 | /// 8 | /// 9 | /// 10 | public static class IntegerSourceExtensions 11 | { 12 | /// 13 | /// Use the data source with the specified and values 14 | /// 15 | /// The type of the entity. 16 | /// The member configuration builder. 17 | /// The minimum value. 18 | /// The maximum value. 19 | /// Fluent builder for an entity property. 20 | 21 | public static MemberConfigurationBuilder IntegerSource(this MemberConfigurationBuilder builder, short min, short max) 22 | { 23 | builder.DataSource(() => new IntegerSource(min, max)); 24 | return builder; 25 | } 26 | 27 | /// 28 | /// Use the data source with the specified and values 29 | /// 30 | /// The type of the entity. 31 | /// The member configuration builder. 32 | /// The minimum value. 33 | /// The maximum value. 34 | /// Fluent builder for an entity property. 35 | public static MemberConfigurationBuilder IntegerSource(this MemberConfigurationBuilder builder, int min, int max) 36 | { 37 | builder.DataSource(() => new IntegerSource(min, max)); 38 | return builder; 39 | } 40 | 41 | /// 42 | /// Use the data source with the specified and values 43 | /// 44 | /// The type of the entity. 45 | /// The member configuration builder. 46 | /// The minimum value. 47 | /// The maximum value. 48 | /// Fluent builder for an entity property. 49 | public static MemberConfigurationBuilder IntegerSource(this MemberConfigurationBuilder builder, int min, int max) 50 | { 51 | builder.DataSource(() => new IntegerSource(min, max)); 52 | return builder; 53 | } 54 | 55 | /// 56 | /// Use the data source with the specified and values 57 | /// 58 | /// The type of the entity. 59 | /// The member configuration builder. 60 | /// The minimum value. 61 | /// The maximum value. 62 | /// Fluent builder for an entity property. 63 | public static MemberConfigurationBuilder IntegerSource(this MemberConfigurationBuilder builder, int min, int max) 64 | { 65 | builder.DataSource(() => new IntegerSource(min, max)); 66 | return builder; 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /src/DataGenerator/Sources/ListDataSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using DataGenerator.Extensions; 4 | 5 | namespace DataGenerator.Sources 6 | { 7 | /// 8 | /// Generate value from a list data source 9 | /// 10 | /// Type of value in list 11 | /// 12 | public class ListDataSource : IDataSource 13 | { 14 | /// 15 | /// Initializes a new instance of the class. 16 | /// 17 | /// The items to generate from. 18 | public ListDataSource(IEnumerable items) 19 | { 20 | Items = new List(items); 21 | } 22 | 23 | /// 24 | /// Gets the items to generate from. 25 | /// 26 | /// 27 | /// The items to generate from. 28 | /// 29 | public List Items { get; } 30 | 31 | /// 32 | /// Gets or sets the weight selector. 33 | /// 34 | /// 35 | /// The weight selector. 36 | /// 37 | public Func WeightSelector { get; set; } 38 | 39 | 40 | /// 41 | /// Get a value from the data source. 42 | /// 43 | /// The generate context. 44 | /// 45 | /// A new value from the data source. 46 | /// 47 | public object NextValue(IGenerateContext generateContext) 48 | { 49 | if (Items == null || Items.Count == 0) 50 | return default(T); 51 | 52 | 53 | return Items.Random(WeightSelector); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/DataGenerator/Sources/MoneySource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DataGenerator.Sources 9 | { 10 | /// 11 | /// Money data source 12 | /// 13 | /// 14 | public class MoneySource : DataSourceContainName 15 | { 16 | private static readonly string[] _names = { "Amount", "Cost", "Rate" }; 17 | private static readonly Type[] _types = { typeof(decimal), typeof(double) }; 18 | 19 | private readonly decimal _min; 20 | private readonly decimal _max; 21 | private readonly int _decimals; 22 | 23 | 24 | /// 25 | /// Initializes a new instance of the class. 26 | /// 27 | public MoneySource() 28 | : this(0, 10000, 2) 29 | { 30 | } 31 | 32 | /// 33 | /// Initializes a new instance of the class. 34 | /// 35 | /// The minimum value. 36 | /// The maximum value. 37 | public MoneySource(decimal min, decimal max) 38 | : this(min, max, 2) 39 | { 40 | } 41 | 42 | /// 43 | /// Initializes a new instance of the class. 44 | /// 45 | /// The minimum value. 46 | /// The maximum value. 47 | /// The number of decimal places. 48 | public MoneySource(decimal min, decimal max, int decimals) 49 | : base(_types, _names) 50 | { 51 | _min = min; 52 | _max = max; 53 | _decimals = decimals; 54 | } 55 | 56 | 57 | /// 58 | /// Get a value from the data source. 59 | /// 60 | /// The generate context. 61 | /// 62 | /// A new value from the data source. 63 | /// 64 | public override object NextValue(IGenerateContext generateContext) 65 | { 66 | // Perform arithmetic in double type to avoid overflowing 67 | var range = (double)_max - (double)_min; 68 | var sample = RandomGenerator.Current.NextDouble(); 69 | var scaled = (sample * range) + (double)_min; 70 | 71 | return Math.Round((decimal)scaled, _decimals); 72 | } 73 | 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/DataGenerator/Sources/NameSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DataGenerator.Sources 8 | { 9 | /// 10 | /// Name generator data source 11 | /// 12 | /// 13 | public class NameSource : DataSourceMatchName 14 | { 15 | private static readonly string[] _names = { "Name" }; 16 | private static readonly Type[] _types = { typeof(string) }; 17 | 18 | private static readonly string[] _attributes = 19 | { 20 | // Environ 21 | "Desert", "Tundra", "Mountain", "Space", "Field", "Urban", 22 | // Stealth and cunning 23 | "Hidden", "Covert", "Uncanny", "Scheming", "Decisive", 24 | // Volitility 25 | "Rowdy", "Dangerous", "Explosive", "Threatening", "Warring", 26 | // Needs correction 27 | "Bad", "Unnecessary", "Unknown", "Unexpected", "Waning", 28 | // Organic Gems and materials 29 | "Amber", "Bone", "Coral", "Ivory", "Jet", "Nacre", "Pearl", "Obsidian", "Glass", 30 | // Regular Gems 31 | "Agate", "Beryl", "Diamond", "Opal", "Ruby", "Onyx", "Sapphire", "Emerald", "Jade", 32 | // Colors 33 | "Red", "Orange", "Yellow", "Green", "Blue", "Violet", 34 | }; 35 | 36 | private static readonly string[] _objects = 37 | { 38 | // Large cats 39 | "Panther", "Wildcat", "Tiger", "Lion", "Cheetah", "Cougar", "Leopard", 40 | // Snakes 41 | "Viper", "Cottonmouth", "Python", "Boa", "Sidewinder", "Cobra", 42 | // Other predators 43 | "Grizzly", "Jackal", "Falcon", 44 | // Prey 45 | "Wildabeast", "Gazelle", "Zebra", "Elk", "Moose", "Deer", "Stag", "Pony", 46 | // HORSES! 47 | "Horse", "Stallion", "Foal", "Colt", "Mare", "Yearling", "Filly", "Gelding", 48 | // Occupations 49 | "Nomad", "Wizard", "Cleric", "Pilot", 50 | // Technology 51 | "Mainframe", "Device", "Motherboard", "Network", "Transistor", "Packet", "Robot", "Android", "Cyborg", 52 | // Sea life 53 | "Octopus", "Lobster", "Crab", "Barnacle", "Hammerhead", "Orca", "Piranha", 54 | // Weather 55 | "Storm", "Thunder", "Lightning", "Rain", "Hail", "Sun", "Drought", "Snow", 56 | // Other 57 | "Warning", "Presence", "Weapon" 58 | }; 59 | 60 | /// 61 | /// Initializes a new instance of the class. 62 | /// 63 | public NameSource() : base(_types, _names) 64 | { 65 | } 66 | 67 | /// 68 | /// Get a value from the data source. 69 | /// 70 | /// The generate context. 71 | /// 72 | /// A new value from the data source. 73 | /// 74 | public override object NextValue(IGenerateContext generateContext) 75 | { 76 | var a = _attributes[RandomGenerator.Current.Next(0, _attributes.Length)]; 77 | var o = _objects[RandomGenerator.Current.Next(0, _objects.Length)]; 78 | 79 | return $"{a} {o}"; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/DataGenerator/Sources/PasswordSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace DataGenerator.Sources 5 | { 6 | /// 7 | /// Password generator data source 8 | /// 9 | /// 10 | public class PasswordSource : DataSourceMatchName 11 | { 12 | private static readonly string[] _names = { "Password", "UserPassword" }; 13 | private static readonly Type[] _types = { typeof(string) }; 14 | 15 | private static readonly char[] _vowels = { 'a', 'e', 'i', 'o', 'u' }; 16 | private static readonly char[] _consonants = { 'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'r', 's', 't', 'v' }; 17 | private static readonly char[] _doubleConsonants = { 'c', 'd', 'f', 'g', 'l', 'm', 'n', 'p', 'r', 's', 't' }; 18 | 19 | private readonly int _length; 20 | 21 | 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | public PasswordSource() 26 | : this(8) 27 | { 28 | } 29 | 30 | /// 31 | /// Initializes a new instance of the class. 32 | /// 33 | /// The password length. 34 | public PasswordSource(int length) : base(_types, _names) 35 | { 36 | _length = length; 37 | } 38 | 39 | 40 | /// 41 | /// Get a value from the data source. 42 | /// 43 | /// The generate context. 44 | /// 45 | /// A new value from the data source. 46 | /// 47 | public override object NextValue(IGenerateContext generateContext) 48 | { 49 | return Generate(_length); 50 | } 51 | 52 | 53 | /// 54 | /// Generates a password with the specified length. 55 | /// 56 | /// Length of the password. 57 | /// A generated password 58 | public static string Generate(int passwordLength) 59 | { 60 | bool wroteConsonant = false; 61 | int counter; 62 | var password = new StringBuilder(); 63 | 64 | for (counter = 0; counter <= passwordLength; counter++) 65 | { 66 | if (password.Length > 0 & (wroteConsonant == false) & (RandomGenerator.Current.Next(100) < 10)) 67 | { 68 | password.Append(_doubleConsonants[RandomGenerator.Current.Next(_doubleConsonants.Length)], 2); 69 | counter += 1; 70 | wroteConsonant = true; 71 | continue; 72 | } 73 | 74 | if ((wroteConsonant == false) & (RandomGenerator.Current.Next(100) < 90)) 75 | { 76 | password.Append(_consonants[RandomGenerator.Current.Next(_consonants.Length)]); 77 | wroteConsonant = true; 78 | } 79 | else 80 | { 81 | password.Append(_vowels[RandomGenerator.Current.Next(_vowels.Length)]); 82 | wroteConsonant = false; 83 | } 84 | } 85 | 86 | password.Length = passwordLength; 87 | return password.ToString(); 88 | } 89 | 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/DataGenerator/Sources/PhoneSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | 4 | namespace DataGenerator.Sources 5 | { 6 | 7 | /// 8 | /// Phone number data source 9 | /// 10 | /// 11 | public class PhoneSource : DataSourceContainName 12 | { 13 | 14 | /// 15 | /// The default phone number format 16 | /// 17 | public const string DefaultFormat = "({0}) {1}-{2}"; 18 | 19 | private static readonly string[] _names = { "Phone", "Fax", "Mobile" }; 20 | private static readonly Type[] _types = { typeof(string) }; 21 | private readonly string _format; 22 | 23 | 24 | /// 25 | /// Initializes a new instance of the class. 26 | /// 27 | public PhoneSource() : this(DefaultFormat) 28 | { } 29 | 30 | /// 31 | /// Initializes a new instance of the class. 32 | /// 33 | /// The format. 34 | public PhoneSource(string format) : base(_types, _names) 35 | { 36 | _format = format ?? DefaultFormat; 37 | } 38 | 39 | /// 40 | /// Get a value from the data source. 41 | /// 42 | /// The generate context. 43 | /// 44 | /// A new value from the data source. 45 | /// 46 | public override object NextValue(IGenerateContext generateContext) 47 | { 48 | string areaCode = RandomGenerator.Current.Next(100, 999).ToString(CultureInfo.InvariantCulture); 49 | string exchange = RandomGenerator.Current.Next(100, 999).ToString(CultureInfo.InvariantCulture); 50 | string number = RandomGenerator.Current.Next(1, 9999).ToString(CultureInfo.InvariantCulture).PadLeft(4, '0'); 51 | 52 | return string.Format(_format, areaCode, exchange, number); 53 | } 54 | 55 | } 56 | } -------------------------------------------------------------------------------- /src/DataGenerator/Sources/PostalCodeSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator.Sources 4 | { 5 | 6 | /// 7 | /// Postal code data source 8 | /// 9 | /// 10 | public class PostalCodeSource : DataSourceMatchName 11 | { 12 | private static readonly string[] _names = { "PostalCode", "ZipCode", "Zip" }; 13 | private static readonly Type[] _types = { typeof(string) }; 14 | private static readonly string[] _postalCodes = 15 | { 16 | "79936", "90011", "60629", "90650", "90201", "77084", "92335", 17 | "78521", "77449", "78572", "90250", "90280", "11226", "90805", 18 | "91331", "08701", "90044", "92336", "00926", "94565", "10467", 19 | "92683", "75052", "91342", "92704", "30044", "10025", "92503", 20 | "92804", "78577", "75217", "92376", "93307", "10456", "10002", 21 | "91911", "91744", "75070", "77036", "93722", "92345", "60618", 22 | "93033", "93550", "95076", "11230", "11368", "37013", "11373", 23 | "79912", "37211", "30043", "11206", "10453", "92154", "11355", 24 | "95823", "77479", "91706", "10458", "92553", "90706", "23464", 25 | "11212", "60617", "91709", "11214", "11219", "91910", "22193", 26 | "77429", "93535", "66062", "93257", "30349", "60647", "77584", 27 | "10452", "77573", "11377", "11207", "77494", "75211", "11234", 28 | "28269", "11235", "94544", "10029", "60625", "89110", "92509", 29 | "77083", "91335", "85364", "87121", "10468", "90255", "93065", 30 | "91710", "10462" 31 | }; 32 | 33 | 34 | /// 35 | /// Initializes a new instance of the class. 36 | /// 37 | public PostalCodeSource() : base(_types, _names) 38 | { 39 | } 40 | 41 | 42 | /// 43 | /// Get a value from the data source. 44 | /// 45 | /// The generate context. 46 | /// 47 | /// A new value from the data source. 48 | /// 49 | public override object NextValue(IGenerateContext generateContext) 50 | { 51 | return _postalCodes[RandomGenerator.Current.Next(0, _postalCodes.Length)]; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/DataGenerator/Sources/SocialSecuritySource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DataGenerator.Sources 8 | { 9 | 10 | /// 11 | /// Social Security data source 12 | /// 13 | /// 14 | public class SocialSecuritySource : DataSourceMatchName 15 | { 16 | private static readonly string[] _names = { "SocialSecurityNumber", "SocialSecurity", "SSN", "TaxIdentifier" }; 17 | private static readonly Type[] _types = { typeof(string) }; 18 | 19 | /// 20 | /// Initializes a new instance of the class. 21 | /// 22 | public SocialSecuritySource() : base(_types, _names) 23 | { 24 | } 25 | 26 | /// 27 | /// Get a value from the data source. 28 | /// 29 | /// The generate context. 30 | /// 31 | /// A new value from the data source. 32 | /// 33 | public override object NextValue(IGenerateContext generateContext) 34 | { 35 | var area = RandomGenerator.Current.Next(1, 899); 36 | var group = RandomGenerator.Current.Next(1, 99); 37 | var series = RandomGenerator.Current.Next(1, 9999); 38 | 39 | return $"{area:000}-{group:00}-{series:0000}"; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/DataGenerator/Sources/StateSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator.Sources 4 | { 5 | 6 | /// 7 | /// State data source 8 | /// 9 | /// 10 | public class StateSource : DataSourceMatchName 11 | { 12 | private static readonly string[] _names = { "State", "StateProvidence" }; 13 | private static readonly Type[] _types = { typeof(string) }; 14 | private static readonly string[] _states = 15 | { 16 | "AL", "AK", "AS", "AZ", "AR", "CA", "CO", "CT", "DE", "DC", "FM", "FL", 17 | "GA", "GU", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MH", 18 | "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", 19 | "NY", "NC", "ND", "MP", "OH", "OK", "OR", "PW", "PA", "PR", "RI", "SC", 20 | "SD", "TN", "TX", "UT", "VT", "VI", "VA", "WA", "WV", "WI", "WY" 21 | }; 22 | 23 | /// 24 | /// Initializes a new instance of the class. 25 | /// 26 | public StateSource() : base(_types, _names) 27 | { 28 | } 29 | 30 | /// 31 | /// Get a value from the data source. 32 | /// 33 | /// The generate context. 34 | /// 35 | /// A new value from the data source. 36 | /// 37 | public override object NextValue(IGenerateContext generateContext) 38 | { 39 | return _states[RandomGenerator.Current.Next(0, _states.Length)]; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/DataGenerator/Sources/StreetSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | 4 | namespace DataGenerator.Sources 5 | { 6 | /// 7 | /// Street data source 8 | /// 9 | /// 10 | public class StreetSource : DataSourceMatchName 11 | { 12 | private static readonly string[] _names = { "Street", "Street1", "Address", "Address1", "AddressLine1" }; 13 | private static readonly Type[] _types = { typeof(string) }; 14 | 15 | private static readonly string[] _suffix = { "AVE", "BLVD", "CTR", "CIR", "CT", "DR", "HWY", "LN", "PKWY", "ST" }; 16 | private static readonly string[] _streets = 17 | { 18 | "Second", "Third", "First", "Fourth", "Park", "Fifth", "Main", 19 | "Sixth", "Oak", "Seventh", "Pine", "Maple", "Cedar", "Eighth", 20 | "Elm", "View", "Washington", "Ninth", "Lake", "Hill" 21 | }; 22 | 23 | /// 24 | /// Initializes a new instance of the class. 25 | /// 26 | public StreetSource() : base(_types, _names) 27 | { 28 | } 29 | 30 | /// 31 | /// Get a value from the data source. 32 | /// 33 | /// The generate context. 34 | /// 35 | /// A new value from the data source. 36 | /// 37 | public override object NextValue(IGenerateContext generateContext) 38 | { 39 | string street = _streets[RandomGenerator.Current.Next(0, _streets.Length)]; 40 | string number = RandomGenerator.Current.Next(10, 8000).ToString(CultureInfo.InvariantCulture); 41 | string suffix = _suffix[RandomGenerator.Current.Next(0, _suffix.Length)]; 42 | 43 | return $"{number} {street} {suffix}"; 44 | } 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/DataGenerator/Sources/TimeSpanSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator.Sources 4 | { 5 | 6 | /// 7 | /// data source 8 | /// 9 | /// 10 | public class TimeSpanSource : DataSourcePropertyType 11 | { 12 | private readonly TimeSpan _min; 13 | private readonly TimeSpan _max; 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | public TimeSpanSource() 19 | : this(TimeSpan.Zero, TimeSpan.FromDays(1)) 20 | { 21 | } 22 | 23 | /// 24 | /// Initializes a new instance of the class. 25 | /// 26 | /// The minimum value. 27 | /// The maximum value. 28 | public TimeSpanSource(TimeSpan min, TimeSpan max) 29 | : base(new[] { typeof(TimeSpan) }) 30 | { 31 | _min = min; 32 | _max = max; 33 | } 34 | 35 | /// 36 | /// Get a value from the data source. 37 | /// 38 | /// The generate context. 39 | /// 40 | /// A new value from the data source. 41 | /// 42 | public override object NextValue(IGenerateContext generateContext) 43 | { 44 | var range = (_max - _min).Ticks; 45 | var ticks = (long)(RandomGenerator.Current.NextDouble() * range); 46 | return _min.Add(TimeSpan.FromTicks(ticks)); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/DataGenerator/Sources/TimeSpanSourceExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Fluent; 3 | 4 | namespace DataGenerator.Sources 5 | { 6 | /// 7 | /// data source extension methods 8 | /// 9 | /// 10 | public static class TimeSpanSourceExtensions 11 | { 12 | /// 13 | /// Use the data source with the specified and values 14 | /// 15 | /// The type of the entity. 16 | /// The member configuration builder. 17 | /// The minimum value. 18 | /// The maximum value. 19 | /// Fluent builder for an entity property. 20 | public static MemberConfigurationBuilder TimeSpanSource(this MemberConfigurationBuilder builder, TimeSpan min, TimeSpan max) 21 | { 22 | builder.DataSource(() => new TimeSpanSource(min, max)); 23 | return builder; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/DataGenerator/Sources/ValueSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator.Sources 4 | { 5 | 6 | /// 7 | /// Static value data source 8 | /// 9 | /// The value type 10 | /// 11 | public class ValueSource : IDataSource 12 | { 13 | 14 | /// 15 | /// Initializes a new instance of the class. 16 | /// 17 | /// The static value. 18 | public ValueSource(T value) 19 | { 20 | Value = value; 21 | } 22 | 23 | 24 | /// 25 | /// Gets the static value. 26 | /// 27 | /// 28 | /// The value. 29 | /// 30 | public T Value { get; } 31 | 32 | 33 | /// 34 | /// Get a value from the data source. 35 | /// 36 | /// The generate context. 37 | /// 38 | /// A new value from the data source. 39 | /// 40 | public object NextValue(IGenerateContext generateContext) 41 | { 42 | return Value; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/DataGenerator/Sources/WebsiteSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator.Sources 4 | { 5 | 6 | /// 7 | /// Website data source 8 | /// 9 | /// 10 | public class WebsiteSource : DataSourceMatchName 11 | { 12 | private static readonly string[] _names = { "WebSite", "Url" }; 13 | private static readonly Type[] _types = { typeof(string) }; 14 | 15 | private static readonly string[] _domains = { 16 | "google.com", "facebook.com", "youtube.com", "yahoo.com", 17 | "live.com", "blogspot.com", "wikipedia.org", "twitter.com", 18 | "msn.com", "amazon.com", "linkedin.com.", "bing.com", 19 | "wordpress.com", "microsoft.com", "ebay.com", "paypal.com", 20 | "flickr.com", "craigslist.org", "imdb.com", "apple.com", 21 | "go.com", "ask.com", "cnn.com", "aol.com", "tumblr.com", 22 | "godaddy.com", "adobe.com", "about.com", "livejournal.com", 23 | "espn.go.com", 24 | }; 25 | 26 | /// 27 | /// Initializes a new instance of the class. 28 | /// 29 | public WebsiteSource() : base(_types, _names) 30 | { 31 | } 32 | 33 | /// 34 | /// Get a value from the data source. 35 | /// 36 | /// The generate context. 37 | /// 38 | /// A new value from the data source. 39 | /// 40 | public override object NextValue(IGenerateContext generateContext) 41 | { 42 | string domain = _domains[RandomGenerator.Current.Next(0, _domains.Length)]; 43 | return $"http://www.{domain}"; 44 | } 45 | 46 | } 47 | } -------------------------------------------------------------------------------- /src/DataGenerator/WeightedValue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator 4 | { 5 | /// 6 | /// A class for use in a random weighted value 7 | /// 8 | /// The value type. 9 | public class WeightedValue 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// The value. 15 | public WeightedValue(T value) : this(value, 1) 16 | { 17 | 18 | } 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | /// The value. 24 | /// The weight. 25 | public WeightedValue(T value, int weight) 26 | { 27 | Weight = weight; 28 | Value = value; 29 | } 30 | 31 | /// 32 | /// Gets the weight. 33 | /// 34 | /// 35 | /// The weight. 36 | /// 37 | public int Weight { get; } 38 | 39 | /// 40 | /// Gets the value. 41 | /// 42 | /// 43 | /// The value. 44 | /// 45 | public T Value { get; } 46 | 47 | /// 48 | /// Performs an implicit conversion from to . 49 | /// 50 | /// The value. 51 | /// 52 | /// The result of the conversion. 53 | /// 54 | public static implicit operator T(WeightedValue value) 55 | { 56 | return value == null ? default(T) : value.Value; 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/CsvTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Globalization; 4 | using System.IO; 5 | using CsvHelper; 6 | using DataGenerator.Tests.Models; 7 | using FluentAssertions; 8 | using Xunit; 9 | using Xunit.Abstractions; 10 | 11 | namespace DataGenerator.Tests 12 | { 13 | public class CsvTest 14 | { 15 | private readonly ITestOutputHelper _output; 16 | 17 | public CsvTest(ITestOutputHelper output) 18 | { 19 | _output = output; 20 | } 21 | 22 | [Fact] 23 | public void GenerateProfile() 24 | { 25 | var generator = Generator.Create(c => c 26 | .ExcludeName("xunit") 27 | .Profile() 28 | .Entity(e => e.Property(p => p.Note).Ignore()) 29 | ); 30 | 31 | 32 | var count = 10; 33 | 34 | var watch = Stopwatch.StartNew(); 35 | var users = generator.List(count); 36 | watch.Stop(); 37 | 38 | _output.WriteLine("Generate Time: {0} ms", watch.ElapsedMilliseconds); 39 | 40 | users.Should().NotBeNull(); 41 | 42 | string fileName = $"Generated Users ({count}) {DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}.csv"; 43 | 44 | using (var textWriter = File.CreateText(fileName)) 45 | { 46 | var csv = new CsvWriter(textWriter, CultureInfo.InvariantCulture); 47 | csv.WriteRecords(users); 48 | textWriter.Flush(); 49 | } 50 | } 51 | 52 | } 53 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/DataGenerator.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5.0.0.0 5 | net7.0 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers 17 | 18 | 19 | 20 | 21 | 22 | 23 | all 24 | runtime; build; native; contentfiles; analyzers 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Models/Employee.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator.Tests.Models 4 | { 5 | public class Employee : User 6 | { 7 | public string EmployeeNumber { get; set; } 8 | public DateTime? HireDate { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Models/Order.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace DataGenerator.Tests.Models 5 | { 6 | public class Order 7 | { 8 | public Guid Id { get; set; } 9 | 10 | public string Name { get; set; } 11 | 12 | public decimal Total { get; set; } 13 | 14 | public DateTimeOffset Ordered { get; set; } 15 | 16 | public User User { get; set; } 17 | 18 | public List Items { get; set; } 19 | } 20 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Models/OrderLine.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator.Tests.Models 4 | { 5 | public class OrderLine 6 | { 7 | public Guid Id { get; set; } 8 | 9 | public Guid ItemId { get; set; } 10 | 11 | 12 | public string Name { get; set; } 13 | 14 | public string Description { get; set; } 15 | 16 | 17 | public decimal UnitAmount { get; set; } 18 | 19 | public decimal Quantity { get; set; } 20 | 21 | public decimal TotalAmount => UnitAmount * Quantity; 22 | } 23 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Models/User.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DataGenerator.Tests.Models 4 | { 5 | public enum Status 6 | { 7 | New, 8 | Verified 9 | } 10 | 11 | public class User 12 | { 13 | public string Id { get; set; } 14 | 15 | public string FirstName { get; set; } 16 | 17 | public string LastName { get; set; } 18 | 19 | public string FullName { get; set; } 20 | 21 | public string EmailAddress { get; set; } 22 | 23 | public string Address1 { get; set; } 24 | public string City { get; set; } 25 | public string State { get; set; } 26 | public string Zip { get; set; } 27 | 28 | public string Note { get; set; } 29 | public decimal Budget { get; set; } 30 | 31 | public string Password { get; set; } 32 | 33 | public Status Status { get; set; } 34 | 35 | public bool IsActive { get; set; } 36 | 37 | public DateTime Created { get; set; } 38 | public DateTime Updated { get; set; } 39 | 40 | } 41 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Sources/BooleanSourceTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Sources; 3 | using Xunit; 4 | using Xunit.Abstractions; 5 | 6 | namespace DataGenerator.Tests.Sources 7 | { 8 | public class BooleanSourceTest 9 | { 10 | private readonly ITestOutputHelper _output; 11 | 12 | public BooleanSourceTest(ITestOutputHelper output) 13 | { 14 | _output = output; 15 | } 16 | 17 | [Fact] 18 | public void NextValue() 19 | { 20 | var source = new BooleanSource(); 21 | 22 | for (int i = 0; i < 10; i++) 23 | { 24 | var nextValue = source.NextValue(null); 25 | _output.WriteLine($"Value {i}: {nextValue}"); 26 | } 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Sources/CompanySourceTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Sources; 3 | using Xunit; 4 | using Xunit.Abstractions; 5 | 6 | namespace DataGenerator.Tests.Sources 7 | { 8 | public class CompanySourceTest 9 | { 10 | private readonly ITestOutputHelper _output; 11 | 12 | public CompanySourceTest(ITestOutputHelper output) 13 | { 14 | _output = output; 15 | } 16 | 17 | [Fact] 18 | public void NextValue() 19 | { 20 | var source = new CompanySource(); 21 | 22 | for (int i = 0; i < 10; i++) 23 | { 24 | var nextValue = source.NextValue(null); 25 | _output.WriteLine($"Value {i}: {nextValue}"); 26 | } 27 | 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Sources/CreditCardSourceTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using DataGenerator.Sources; 7 | using FluentAssertions; 8 | using Xunit; 9 | 10 | namespace DataGenerator.Tests.Sources 11 | { 12 | public class CreditCardSourceTest 13 | { 14 | [Fact] 15 | public void GenerateAndValidateNumber() 16 | { 17 | for (int i = 0; i < 100; i++) 18 | { 19 | var cardNumber = CreditCardSource.GenerateNumber(CreditCardSource.CreditCardType.Visa); 20 | cardNumber.Should().NotBeNullOrEmpty(); 21 | cardNumber.Length.Should().Be(16); 22 | 23 | var valid = CreditCardSource.IsValidNumber(cardNumber); 24 | valid.Should().BeTrue(); 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Sources/DateTimeSourceTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Sources; 3 | using Xunit; 4 | using Xunit.Abstractions; 5 | 6 | namespace DataGenerator.Tests.Sources 7 | { 8 | public class DateTimeSourceTest 9 | { 10 | private readonly ITestOutputHelper _output; 11 | 12 | public DateTimeSourceTest(ITestOutputHelper output) 13 | { 14 | _output = output; 15 | } 16 | 17 | [Fact] 18 | public void NextValue() 19 | { 20 | var source = new DateTimeSource(); 21 | 22 | for (int i = 0; i < 10; i++) 23 | { 24 | var nextValue = source.NextValue(null); 25 | _output.WriteLine($"Value {i}: {nextValue}"); 26 | } 27 | 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Sources/DecimalSourceTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Sources; 3 | using Xunit; 4 | using Xunit.Abstractions; 5 | 6 | namespace DataGenerator.Tests.Sources 7 | { 8 | public class DecimalSourceTest 9 | { 10 | private readonly ITestOutputHelper _output; 11 | 12 | public DecimalSourceTest(ITestOutputHelper output) 13 | { 14 | _output = output; 15 | } 16 | 17 | [Fact] 18 | public void NextValue() 19 | { 20 | var source = new DecimalSource(); 21 | 22 | for (int i = 0; i < 10; i++) 23 | { 24 | var nextValue = source.NextValue(null); 25 | _output.WriteLine($"Value {i}: {nextValue}"); 26 | } 27 | 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Sources/EmailSourceTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Sources; 3 | using Xunit; 4 | using Xunit.Abstractions; 5 | 6 | namespace DataGenerator.Tests.Sources 7 | { 8 | public class EmailSourceTest 9 | { 10 | private readonly ITestOutputHelper _output; 11 | 12 | public EmailSourceTest(ITestOutputHelper output) 13 | { 14 | _output = output; 15 | } 16 | 17 | [Fact] 18 | public void NextValue() 19 | { 20 | var source = new EmailSource(); 21 | 22 | for (int i = 0; i < 10; i++) 23 | { 24 | var nextValue = source.NextValue(null); 25 | _output.WriteLine($"Value {i}: {nextValue}"); 26 | } 27 | 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Sources/EnumSourceTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Sources; 3 | using DataGenerator.Tests.Models; 4 | using Xunit; 5 | using Xunit.Abstractions; 6 | 7 | namespace DataGenerator.Tests.Sources 8 | { 9 | public class EnumSourceTest 10 | { 11 | private readonly ITestOutputHelper _output; 12 | 13 | public EnumSourceTest(ITestOutputHelper output) 14 | { 15 | _output = output; 16 | } 17 | 18 | [Fact] 19 | public void NextValue() 20 | { 21 | var source = new EnumSource(); 22 | var context = new GenerateContext 23 | { 24 | ClassType = typeof(User), 25 | MemberType = typeof(Status), 26 | MemberName = "Status" 27 | }; 28 | 29 | for (int i = 0; i < 10; i++) 30 | { 31 | var nextValue = source.NextValue(context); 32 | _output.WriteLine($"Value {i}: {nextValue}"); 33 | } 34 | 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Sources/FirstNameSourceTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Sources; 3 | using Xunit; 4 | using Xunit.Abstractions; 5 | 6 | namespace DataGenerator.Tests.Sources 7 | { 8 | public class FirstNameSourceTest 9 | { 10 | private readonly ITestOutputHelper _output; 11 | 12 | public FirstNameSourceTest(ITestOutputHelper output) 13 | { 14 | _output = output; 15 | } 16 | 17 | [Fact] 18 | public void NextValue() 19 | { 20 | var source = new FirstNameSource(); 21 | 22 | for (int i = 0; i < 10; i++) 23 | { 24 | var nextValue = source.NextValue(null); 25 | _output.WriteLine($"Value {i}: {nextValue}"); 26 | } 27 | 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Sources/FloatSourceTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Sources; 3 | using Xunit; 4 | using Xunit.Abstractions; 5 | 6 | namespace DataGenerator.Tests.Sources 7 | { 8 | public class FloatSourceTest 9 | { 10 | private readonly ITestOutputHelper _output; 11 | 12 | public FloatSourceTest(ITestOutputHelper output) 13 | { 14 | _output = output; 15 | } 16 | 17 | [Fact] 18 | public void NextValue() 19 | { 20 | var source = new FloatSource(); 21 | 22 | for (int i = 0; i < 10; i++) 23 | { 24 | var nextValue = source.NextValue(null); 25 | _output.WriteLine($"Value {i}: {nextValue}"); 26 | } 27 | 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Sources/IntegerSourceTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Sources; 3 | using Xunit; 4 | using Xunit.Abstractions; 5 | 6 | namespace DataGenerator.Tests.Sources 7 | { 8 | public class IntegerSourceTest 9 | { 10 | private readonly ITestOutputHelper _output; 11 | 12 | public IntegerSourceTest(ITestOutputHelper output) 13 | { 14 | _output = output; 15 | } 16 | 17 | [Fact] 18 | public void NextValue() 19 | { 20 | var source = new IntegerSource(); 21 | 22 | for (int i = 0; i < 10; i++) 23 | { 24 | var nextValue = source.NextValue(null); 25 | _output.WriteLine($"Value {i}: {nextValue}"); 26 | } 27 | 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Sources/LastNameSourceTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Sources; 3 | using Xunit; 4 | using Xunit.Abstractions; 5 | 6 | namespace DataGenerator.Tests.Sources 7 | { 8 | public class LastNameSourceTest 9 | { 10 | private readonly ITestOutputHelper _output; 11 | 12 | public LastNameSourceTest(ITestOutputHelper output) 13 | { 14 | _output = output; 15 | } 16 | 17 | [Fact] 18 | public void NextValue() 19 | { 20 | var source = new LastNameSource(); 21 | 22 | for (int i = 0; i < 10; i++) 23 | { 24 | var nextValue = source.NextValue(null); 25 | _output.WriteLine($"Value {i}: {nextValue}"); 26 | } 27 | 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Sources/LoremIpsumSourceTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Sources; 3 | using Xunit; 4 | using Xunit.Abstractions; 5 | 6 | namespace DataGenerator.Tests.Sources 7 | { 8 | public class LoremIpsumSourceTest 9 | { 10 | private readonly ITestOutputHelper _output; 11 | 12 | public LoremIpsumSourceTest(ITestOutputHelper output) 13 | { 14 | _output = output; 15 | } 16 | 17 | [Fact] 18 | public void NextValue() 19 | { 20 | var source = new LoremIpsumSource(); 21 | 22 | for (int i = 0; i < 10; i++) 23 | { 24 | var nextValue = source.NextValue(null); 25 | _output.WriteLine($"Value {i}:\r\n{nextValue}\r\n\r\n"); 26 | } 27 | } 28 | 29 | 30 | [Fact] 31 | public void NextValueLong() 32 | { 33 | var source = new LoremIpsumSource(1000); 34 | 35 | var nextValue = source.NextValue(null); 36 | _output.WriteLine($"Text:\r\n{nextValue}\r\n\r\n"); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Sources/PasswordSourceTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Sources; 3 | using Xunit; 4 | using Xunit.Abstractions; 5 | 6 | namespace DataGenerator.Tests.Sources 7 | { 8 | public class PasswordSourceTest 9 | { 10 | private readonly ITestOutputHelper _output; 11 | 12 | public PasswordSourceTest(ITestOutputHelper output) 13 | { 14 | _output = output; 15 | } 16 | 17 | [Fact] 18 | public void NextValue() 19 | { 20 | var source = new PasswordSource(); 21 | 22 | for (int i = 0; i < 10; i++) 23 | { 24 | var nextValue = source.NextValue(null); 25 | _output.WriteLine($"Value {i}: {nextValue}"); 26 | } 27 | 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Sources/PhoneSourceTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Sources; 3 | using Xunit; 4 | using Xunit.Abstractions; 5 | 6 | namespace DataGenerator.Tests.Sources 7 | { 8 | public class PhoneSourceTest 9 | { 10 | private readonly ITestOutputHelper _output; 11 | 12 | public PhoneSourceTest(ITestOutputHelper output) 13 | { 14 | _output = output; 15 | } 16 | 17 | [Fact] 18 | public void NextValue() 19 | { 20 | var source = new PhoneSource(); 21 | 22 | for (int i = 0; i < 10; i++) 23 | { 24 | var nextValue = source.NextValue(null); 25 | _output.WriteLine($"Value {i}: {nextValue}"); 26 | } 27 | 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Sources/PostalCodeSourceTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Sources; 3 | using Xunit; 4 | using Xunit.Abstractions; 5 | 6 | namespace DataGenerator.Tests.Sources 7 | { 8 | public class PostalCodeSourceTest 9 | { 10 | private readonly ITestOutputHelper _output; 11 | 12 | public PostalCodeSourceTest(ITestOutputHelper output) 13 | { 14 | _output = output; 15 | } 16 | 17 | [Fact] 18 | public void NextValue() 19 | { 20 | var source = new PostalCodeSource(); 21 | 22 | for (int i = 0; i < 10; i++) 23 | { 24 | var nextValue = source.NextValue(null); 25 | _output.WriteLine($"Value {i}: {nextValue}"); 26 | } 27 | 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Sources/SocialSecuritySourceTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Sources; 3 | using FluentAssertions; 4 | using Xunit; 5 | 6 | namespace DataGenerator.Tests.Sources 7 | { 8 | public class SocialSecuritySourceTest 9 | { 10 | [Fact] 11 | public void GenerateNextValue() 12 | { 13 | var source = new SocialSecuritySource(); 14 | var ssn = source.NextValue(null); 15 | ssn.Should().NotBeNull(); 16 | ssn.Should().BeOfType(); 17 | } 18 | 19 | } 20 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Sources/StateSourceTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Sources; 3 | using Xunit; 4 | using Xunit.Abstractions; 5 | 6 | namespace DataGenerator.Tests.Sources 7 | { 8 | public class StateSourceTest 9 | { 10 | private readonly ITestOutputHelper _output; 11 | 12 | public StateSourceTest(ITestOutputHelper output) 13 | { 14 | _output = output; 15 | } 16 | 17 | [Fact] 18 | public void NextValue() 19 | { 20 | var source = new StateSource(); 21 | 22 | for (int i = 0; i < 10; i++) 23 | { 24 | var nextValue = source.NextValue(null); 25 | _output.WriteLine($"Value {i}: {nextValue}"); 26 | } 27 | 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Sources/StreetSourceTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Sources; 3 | using Xunit; 4 | using Xunit.Abstractions; 5 | 6 | namespace DataGenerator.Tests.Sources 7 | { 8 | public class StreetSourceTest 9 | { 10 | private readonly ITestOutputHelper _output; 11 | 12 | public StreetSourceTest(ITestOutputHelper output) 13 | { 14 | _output = output; 15 | } 16 | 17 | [Fact] 18 | public void NextValue() 19 | { 20 | var source = new StreetSource(); 21 | 22 | for (int i = 0; i < 10; i++) 23 | { 24 | var nextValue = source.NextValue(null); 25 | _output.WriteLine($"Value {i}: {nextValue}"); 26 | } 27 | 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Sources/TimeSpanSourceTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Sources; 3 | using Xunit; 4 | using Xunit.Abstractions; 5 | 6 | namespace DataGenerator.Tests.Sources 7 | { 8 | public class TimeSpanSourceTest 9 | { 10 | private readonly ITestOutputHelper _output; 11 | 12 | public TimeSpanSourceTest(ITestOutputHelper output) 13 | { 14 | _output = output; 15 | } 16 | 17 | [Fact] 18 | public void NextValue() 19 | { 20 | var source = new TimeSpanSource(); 21 | 22 | for (int i = 0; i < 10; i++) 23 | { 24 | var nextValue = source.NextValue(null); 25 | _output.WriteLine($"Value {i}: {nextValue}"); 26 | } 27 | 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/Sources/WebsiteSourceTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Sources; 3 | using Xunit; 4 | using Xunit.Abstractions; 5 | 6 | namespace DataGenerator.Tests.Sources 7 | { 8 | public class WebsiteSourceTest 9 | { 10 | private readonly ITestOutputHelper _output; 11 | 12 | public WebsiteSourceTest(ITestOutputHelper output) 13 | { 14 | _output = output; 15 | } 16 | 17 | [Fact] 18 | public void NextValue() 19 | { 20 | var source = new WebsiteSource(); 21 | 22 | for (int i = 0; i < 10; i++) 23 | { 24 | var nextValue = source.NextValue(null); 25 | _output.WriteLine($"Value {i}: {nextValue}"); 26 | } 27 | 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/DataGenerator.Tests/UserProfile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DataGenerator.Fluent; 3 | using DataGenerator.Sources; 4 | using DataGenerator.Tests.Models; 5 | 6 | namespace DataGenerator.Tests 7 | { 8 | public class UserProfile : MappingProfile 9 | { 10 | public override void Configure() 11 | { 12 | Property(p => p.FirstName).DataSource(); 13 | Property(p => p.LastName).DataSource(); 14 | Property(p => p.FullName).Value(u => $"{u.FirstName} {u.LastName}"); 15 | Property(p => p.Address1).DataSource(); 16 | Property(p => p.City).DataSource(); 17 | Property(p => p.State).DataSource(); 18 | Property(p => p.Zip).DataSource(); 19 | Property(p => p.EmailAddress).Value(u => $"{u.FirstName}.{u.LastName}@mailinator.com"); 20 | Property(p => p.Note).DataSource(); 21 | Property(p => p.Password).DataSource(); 22 | 23 | // array of values 24 | Property(p => p.Status).DataSource(new[] { Status.New, Status.Verified }); 25 | 26 | 27 | // don't generate 28 | Property(p => p.Budget).Ignore(); 29 | 30 | // static value 31 | Property(p => p.IsActive).Value(true); 32 | 33 | // delegate value 34 | Property(p => p.Created).Value(u => DateTime.UtcNow); 35 | } 36 | } 37 | } --------------------------------------------------------------------------------