1+ namespace QuickbaseNet . UnitTests . Utility ;
2+
3+ using System ;
4+ using System . Collections . Generic ;
5+ using System . Diagnostics . CodeAnalysis ;
6+ using System . Linq ;
7+ using System . Reflection ;
8+
9+ using AutoBogus ;
10+
11+ using Bogus ;
12+
13+ [ ExcludeFromCodeCoverage ]
14+ public class Builder
15+ {
16+ public T Build < T > ( ) where T : class
17+ {
18+ var binder = new AutoBinder ( ) ;
19+
20+ Faker < T > model = new AutoFaker < T > ( binder )
21+ . RuleForType ( typeof ( uint ) , rule => rule . Random . UInt ( 1 , int . MaxValue ) )
22+ . RuleForType ( typeof ( uint ? ) , rule => ( uint ? ) rule . Random . UInt ( 1 , int . MaxValue ) )
23+ . RuleForType ( typeof ( int ) , rule => rule . Random . Int ( ) )
24+ . RuleForType ( typeof ( int ? ) , rule => ( int ? ) rule . Random . Int ( ) )
25+ . RuleForType ( typeof ( DateTime ) , rule =>
26+ {
27+ DateTime date = rule . Date . Recent ( ) ;
28+ return new DateTime (
29+ date . Year ,
30+ date . Month ,
31+ date . Day
32+ ) ;
33+ } )
34+ . RuleForType ( typeof ( DateTime ? ) , rule =>
35+ {
36+ DateTime date = rule . Date . Recent ( ) ;
37+ return ( DateTime ? ) new DateTime (
38+ date . Year ,
39+ date . Month ,
40+ date . Day
41+ ) ;
42+ } )
43+ . RuleForType ( typeof ( DateTimeOffset ? ) , rule =>
44+ {
45+ DateTimeOffset date = rule . Date . Recent ( ) ;
46+ return ( DateTimeOffset ? ) new DateTime (
47+ date . Year ,
48+ date . Month ,
49+ date . Day
50+ ) ;
51+ } )
52+ . RuleForType ( typeof ( byte ) , rule => rule . Random . Byte ( ) )
53+ . RuleForType ( typeof ( byte ? ) , rule => ( byte ? ) rule . Random . Byte ( ) )
54+ . RuleForType ( typeof ( sbyte ) , rule => rule . Random . SByte ( ) )
55+ . RuleForType ( typeof ( string ) , rule => rule . Random . AlphaNumeric ( 10 ) )
56+ . RuleForType ( typeof ( decimal ) , rule => rule . Finance . Amount ( min : 0.01M , max : 99999.99M , decimals : 2 ) )
57+ . RuleForType ( typeof ( decimal ? ) , rule => ( decimal ? ) rule . Finance . Amount ( min : 0.01M , max : 99999.99M , decimals : 2 ) )
58+ . RuleForType ( typeof ( ushort ) , rule => rule . Random . UShort ( ) )
59+ . RuleForType ( typeof ( short ) , rule => rule . Random . Short ( ) )
60+ . RuleForType ( typeof ( long ) , rule => rule . Random . Long ( ) )
61+ . RuleForType ( typeof ( ulong ) , rule => rule . Random . ULong ( ) )
62+ . RuleForType ( typeof ( bool ) , rule => rule . Random . Bool ( ) )
63+ . RuleForType ( typeof ( bool ? ) , rule => ( bool ? ) rule . Random . Bool ( ) ) ;
64+
65+ model = AddEnumRules ( model , binder ) ;
66+
67+ //int seed = DateTime.UtcNow.Millisecond;
68+ //return model.UseSeed(seed).Generate();
69+ return model . Generate ( ) ;
70+ }
71+
72+ /// <summary>
73+ /// Adds the ability to generate random valid enum values
74+ /// </summary>
75+ /// <remarks>
76+ /// Bogus currently doesn't appear to have a way to create rules for types that aren't well known at compile time. To generate random values for enum properties
77+ /// we have to find properties on <typeparamref name="T"/> that are enum and get a list of valid values for that enum and pick one of those randomly.
78+ ///
79+ /// Bogus appears to do similar things when creating rules for well known types too, so this is at least similar.
80+ ///
81+ /// This also excludes enum members whose name is "None" when it is the first member of the enum as that is usually not a valid value.
82+ /// This follows the convention for other nubmer types not generating zeroes
83+ /// </remarks>
84+ private Faker < T > AddEnumRules < T > ( Faker < T > faker , IBinder binder ) where T : class
85+ {
86+ // find enum properties using the binder
87+ IEnumerable < PropertyInfo > enumProperties = binder . GetMembers ( typeof ( T ) )
88+ . Select ( item => item . Value )
89+ . OfType < PropertyInfo > ( )
90+ . Where ( item => item . PropertyType . IsEnum ) ;
91+
92+ Faker < T > result = faker ;
93+ if ( enumProperties . Any ( ) )
94+ {
95+ result = result . FinishWith ( ( fk , target ) =>
96+ {
97+ foreach ( PropertyInfo enumProperty in enumProperties )
98+ {
99+ // None = 0 is typically not a valid value, so for the sake of generating sane values it will be skipped
100+ var minIndex = 0 ;
101+ string [ ] enumNames = Enum . GetNames ( enumProperty . PropertyType ) ;
102+ if ( enumNames [ 0 ] . ToLower ( ) == "none" )
103+ {
104+ minIndex = 1 ;
105+ }
106+
107+ Array enumValues = Enum . GetValues ( enumProperty . PropertyType ) ;
108+ var randomIndex = fk . Random . Int ( minIndex , enumValues . Length - 1 ) ;
109+ object randomEnumValue = enumValues . GetValue ( randomIndex ) ;
110+
111+ enumProperty . SetValue ( target , randomEnumValue ) ;
112+ }
113+ } ) ;
114+ }
115+
116+ return result ;
117+ }
118+
119+ public IEnumerable < T > Build < T > ( int howMany ) where T : class
120+ {
121+ var models = new List < T > ( ) ;
122+ for ( int i = 0 ; i < howMany ; i ++ )
123+ {
124+ T model = Build < T > ( ) ;
125+ models . Add ( model ) ;
126+ }
127+
128+ return models ;
129+ }
130+ }
0 commit comments