public void StringGenerationStabilityTest() { // Arrange var testingGen1 = _factory.CreateStringGenerator(_seed); var testingGen2 = _factory.CreateStringGenerator(_seed); // Act var value1 = testingGen1.GetNext(); var value2 = testingGen2.GetNext(); value1.Should().Be(value2); }
private void InitializeGenerators() { _randomLengthGenerator = _generatorFactory.CreateCollectionSizeGenerator(_seed); if (TypeCheckExtensions.IsTypeNumericOrChar(_typeParameter)) { _randomValueGenerator = _generatorFactory.CreateNumericGenerator(_seed); } else if (_typeParameter == typeof(string)) { _randomValueGenerator = _generatorFactory.CreateStringGenerator(_seed); } else if (_typeParameter == typeof(bool)) { _randomValueGenerator = _generatorFactory.CreateBooleanGenerator(_seed); } else if (_typeParameter == typeof(DateTime)) { _randomValueGenerator = _generatorFactory.CreateDateTimeGenerator(_seed); } // Just for sake of not making this too complicated let's assume that if a type // implements IEnumerable then it's a collection // We've also already checked if the type is string, so it's safe to just check IEnumerable else if (_depthLimit >= 0 && _typeParameter.GetInterface(nameof(IEnumerable)) != null) { _randomValueGenerator = _generatorFactory.CreateCollectionGenerator(_typeParameter, (int)(_seed + _depthLimit), _depthLimit); } else if (_depthLimit > 0 && _typeParameter.IsClass && !(typeof(Delegate).IsAssignableFrom(_typeParameter)) && _typeParameter.GetConstructor(Type.EmptyTypes) != null) { _randomValueGenerator = _generatorFactory.CreateObjectGenerator(_typeParameter, _seed, _depthLimit - 1); } // We can't assign value types other than we know about or types without a parameterless constructor else { _randomValueGenerator = null; } }
private void InitializeGenerators() { // 1. Filter out all read only props, we cannot assign them anyway props = props.Where(p => p.CanWrite); #region Navigation props generators navigationPropertiesGenerators = new Dictionary <PropertyInfo, RandomValueGenerator>(); // 2. Try to find navigation properties (properties with a foreign key navigationPropertiesWithFk = new Dictionary <PropertyInfo, PropertyInfo>(); if (_depthLimit > 0) { List <PropertyInfo> foreignKeyProps; // Method A: via ForeignKeyAttribute foreignKeyProps = props.Where(p => p.GetCustomAttribute <ForeignKeyAttribute>() != null).ToList(); foreach (var prop in foreignKeyProps) { var attr = prop.GetCustomAttribute <ForeignKeyAttribute>(); var navigationProp = foreignKeyProps.FirstOrDefault(p => p.Name == attr.Name); // If the navigation property wasn't found // (which can happen since it's not checked compile-time) // we remove it from the list of props that are foreign key ID if (navigationProp != null) { // Check if the type of navigation property really contains the field "ID" (case insensitive) var idProp = navigationProp.PropertyType.GetProperties().FirstOrDefault(p => p.Name.ToLower() == "id"); if (idProp != null) { var generatorType = typeof(RandomObjectGenerator <>).MakeGenericType(typeof(T)); var generator = (RandomValueGenerator)Activator.CreateInstance(generatorType, _masterSeed + GetAdditionalSeed <T>(navigationProp), _depthLimit - 1); navigationPropertiesGenerators.Add(navigationProp, generator); navigationPropertiesWithFk.Add(navigationProp, prop); } else { foreignKeyProps.Remove(prop); } } else { foreignKeyProps.Remove(prop); } } props = props.Except(navigationPropertiesWithFk.Keys); props = props.Except(navigationPropertiesWithFk.Values); // Method B: via checking the names // Get properties, types of which are classes (excluding string) var classProps = props.Where(p => p.PropertyType != typeof(string) && p.PropertyType.IsClass); foreach (var prop in classProps) { var fkProp = props.FirstOrDefault(p => $"{prop.Name}Id".ToLower() == p.Name.ToLower()); if (fkProp != null && (prop.PropertyType .GetProperties() .FirstOrDefault(p => p.Name.ToLower() == "id") != null)) { var generatorType = typeof(RandomObjectGenerator <>).MakeGenericType(prop.PropertyType); var generator = (RandomValueGenerator)Activator.CreateInstance(generatorType, _masterSeed + GetAdditionalSeed <T>(prop), _depthLimit - 1); navigationPropertiesGenerators.Add(prop, generator); navigationPropertiesWithFk.Add(prop, fkProp); } } props = props.Except(navigationPropertiesWithFk.Keys); props = props.Except(navigationPropertiesWithFk.Values); } #endregion #region Collection navigation props generators #endregion #region Primitive props generators // 3. Assign generators to properties with "primitive" types // 3.1 Numeric props numericValueGenerators = new Dictionary <PropertyInfo, RandomValueGenerator <double> >(); var numericProps = props.Where(p => TypeCheckExtensions.IsTypeNumericOrChar(p.PropertyType)); foreach (var prop in numericProps) { var additionalSeed = GetAdditionalSeed <T>(prop); numericValueGenerators.Add(prop, _factory.CreateNumericGenerator(_masterSeed + additionalSeed)); } // 3.2 String props stringValueGenerators = new Dictionary <PropertyInfo, RandomValueGenerator <string> >(); var stringProps = props.Where(p => p.PropertyType == typeof(string)); foreach (var prop in stringProps) { var additionalSeed = GetAdditionalSeed <T>(prop); stringValueGenerators.Add(prop, _factory.CreateStringGenerator(_masterSeed + additionalSeed)); } props = props.Except(stringProps).ToList(); // 3.3 Boolean props booleanValueGenerators = new Dictionary <PropertyInfo, RandomValueGenerator <bool> >(); var booleanProps = props.Where(p => p.PropertyType == typeof(bool)); foreach (var prop in booleanProps) { var additionalSeed = GetAdditionalSeed <T>(prop); booleanValueGenerators.Add(prop, _factory.CreateBooleanGenerator(_masterSeed + additionalSeed)); } props = props.Except(booleanProps).ToList(); // 3.4 DateTime props dateTimeValueGenerators = new Dictionary <PropertyInfo, RandomValueGenerator <DateTime> >(); var dateTimeProps = props.Where(p => p.PropertyType == typeof(DateTime)); foreach (var prop in dateTimeProps) { var additionalSeed = GetAdditionalSeed <T>(prop); dateTimeValueGenerators.Add(prop, _factory.CreateDateTimeGenerator(_masterSeed + additionalSeed)); } props = props.Except(dateTimeProps).ToList(); #endregion #region Collection props generators // 4. Assign generators to collection props collectionValueGenerators = new Dictionary <PropertyInfo, RandomValueGenerator>(); if (_depthLimit >= 0) { // We already excluded all props of type string, so we can safely // check only for IEnumerable var collectionProps = props.Where(p => p.PropertyType.GetInterface(nameof(IEnumerable)) != null); foreach (var prop in collectionProps) { var additionalSeed = GetAdditionalSeed <T>(prop); var generatorType = typeof(RandomCollectionGenerator <>).MakeGenericType(prop.PropertyType); var generator = (RandomValueGenerator)Activator.CreateInstance(generatorType, _masterSeed + additionalSeed, _depthLimit - 1); collectionValueGenerators.Add(prop, generator); } } #endregion #region Other props generators // 5. Leave all props that we can easily assign at runtime - which have a constructor with no parameters objectValueGenerators = new Dictionary <PropertyInfo, RandomValueGenerator>(); if (_depthLimit >= 1) { props = props.Where(p => p.PropertyType.GetConstructor(Type.EmptyTypes) != null); foreach (var prop in props) { var additionalSeed = GetAdditionalSeed <T>(prop); var generatorType = typeof(RandomObjectGenerator <>).MakeGenericType(prop.PropertyType); var generator = (RandomValueGenerator)Activator.CreateInstance(generatorType, additionalSeed, _depthLimit - 1); objectValueGenerators.Add(prop, generator); } } #endregion }