diff --git a/src/Faker.NET.Files/Csv/CsvFaker.cs b/src/Faker.NET.Files/Csv/CsvFaker.cs index 7775a4b..b9713b8 100644 --- a/src/Faker.NET.Files/Csv/CsvFaker.cs +++ b/src/Faker.NET.Files/Csv/CsvFaker.cs @@ -1,222 +1,133 @@ -using System.Collections.Concurrent; +using System; using Faker.NET.Attributes; +using Faker.NET.Common.Exceptions; -namespace Faker.NET.Files.Csv +namespace Faker.NET.Files.Csv; + +public class CsvFaker : IDisposable { - public class CsvFaker + public static CsvFaker ToFile(string path) { - /// - /// Constructor - /// - public CsvFaker() - { - BaseStream = new MemoryStream(); - } - - /// - /// Constructor - /// - /// Opens stream to write to - public CsvFaker(string outputFile) - { - BaseStream = File.Open(outputFile, new FileStreamOptions - { - Mode = FileMode.OpenOrCreate, - Access = FileAccess.ReadWrite, - }); - } - - /// - /// Stream that can be written to for output - /// - /// The stream (must have write permissions) - /// - public CsvFaker(Stream stream) - { - if (!stream.CanWrite) - { - throw new Exception("Unable to write to stream"); - } - - BaseStream = stream; - } - - public Stream BaseStream { get; private set; } + ThrowHelper.IfNullOrEmpty(path, $"{nameof(CsvFaker)} file path cannot be null or empty."); - /// - /// Change the delimiter to whatever best suits your uses - /// - /// - /// - public CsvFaker UpdateDelimiter(char delimiter) + return new CsvFaker(System.IO.File.Open(path, new FileStreamOptions { - _delimiter = delimiter; - return this; - } + Mode = FileMode.OpenOrCreate, + Access = FileAccess.ReadWrite, + })); + } - /// - /// Builder way to add columns and functions to perform based on headers - /// - /// - /// - /// - public CsvFaker AddColumn(string columnName, Func func) - { + public static CsvFaker ToStream(Stream stream) + { + return new CsvFaker(stream); + } - _headers.Add(columnName, func); - return this; - } + private CsvFaker(Stream stream) + { + ThrowHelper.IfNotWritable(stream); + _stream = new StreamWriter(stream); + } - /// - /// Adds a column header and the static value that will be put in the rows - /// - /// - /// - /// - public CsvFaker AddColumn(string columnName, string value) - { - _headers.Add(columnName, () => value); - return this; - } + /// + /// Change the delimiter to whatever best suits your uses + /// + /// + /// + public CsvFaker WithDelimiter(char delimiter) + { + _delimiter = delimiter; + return this; + } - /// - /// Amount of rows to be generated when or are called - /// - /// - public uint GetRowCount() - { - return _rowsCountToGenerate; - } + /// + /// Generate a csv based on a type. Properties to have data generated must use an attribute that extends + /// + /// Type to generate csv from + /// + public CsvFaker FromClass() + { + var type = typeof(T); - /// - /// Generate a csv based on a type. Properties to have data generated must use an attribute that extends - /// - /// Type to generate csv from - /// - public IEnumerable Generate() + foreach (var prop in type.GetProperties()) { - var type = typeof(T); + var attrs = prop.GetCustomAttributes(typeof(FakerAttribute), true) as FakerAttribute[] ?? + throw new Exception(); - foreach (var prop in type.GetProperties()) + foreach (var attr in attrs) { - var attrs = prop.GetCustomAttributes(typeof(FakerAttribute), true) as FakerAttribute[] ?? - throw new Exception(); - - foreach (var attr in attrs) - { - _headers.Add(prop.Name, () => attr.GetPropertyValue().ToString() ?? string.Empty); - } + _columnMetadata.Add(prop.Name, () => attr.GetPropertyValue().ToString() ?? string.Empty); } - - return Generate(); } - /// - /// Defaults to 10 can update to any uint value - /// - /// - /// - public CsvFaker Iterations(uint count) - { - _rowsCountToGenerate = count; - return this; - } + return this; + } - /// - /// Generate a single row with no headers - /// - /// - public string GenerateRow() + public CsvFaker WithColumns(Dictionary> columns) + { + foreach (var key in columns.Keys) { - var output = new List(); - - foreach ((var header, var func) in _headers) - { - var val = func(); - if (val.Contains(',')) - { - output.Add($"\"{val}\""); - } - else - { - output.Add(val); - } - } - - return JoinColumns(output); + _columnMetadata[key] = columns[key]; } + return this; + } - /// - /// Generates the entire csv (headers and rows). - /// - /// - public IEnumerable Generate() - { - yield return JoinColumns(_headers.Keys); - - var count = 0; + public CsvFaker WithRowCount(uint rowCount) + { + _rowCount = rowCount; + return this; + } - while (count++ < _rowsCountToGenerate) - { - yield return GenerateRow(); - } - } + public void Write(bool keepStreamOpen = false) + { + var headers = _columnMetadata.Keys.ToArray(); + var headerCount = headers.Length - 1; + var row = new string[headerCount]; + WriteRow(headers); - public string[] GenerateParallel(int batchSize = 1000) + for (var i = 0; i < _rowCount; i++) { - var arr = new string[_rowsCountToGenerate]; - arr[0] = JoinColumns(_headers.Keys); - - Parallel.ForEach(Partitioner.Create(1, arr.Length, batchSize), range => + for (var j = 0; j < headerCount; j++) { - for (int i = range.Item1; i < range.Item2; i++) - { - arr[i] = GenerateRow(); - } - }); + row[j] = _columnMetadata[headers[j]](); + } - return arr; + WriteRow(row); } - /// - /// Outputs the data to the . - /// Writes to a if a file is not given. - /// - public void WriteRows() + if (keepStreamOpen) { - using (var streamWriter = new StreamWriter(BaseStream)) - { - foreach (var line in Generate()) - { - streamWriter.WriteLine(line); - } - } + _stream.Flush(); } - - /// - /// Clears the headers and value creating funcs. Allows to start fresh. - /// - /// - public bool Clear() + else { - _headers = new(); - - return _headers.Count == 0; + _stream.Close(); } + } - private string JoinColumns(IEnumerable input) + public void Dispose() + { + try { - return string.Join(_delimiter, input); + _stream.Dispose(); } - - ~CsvFaker() + finally { - BaseStream?.Dispose(); + GC.SuppressFinalize(this); } + } - private Dictionary> _headers = new(); - private uint _rowsCountToGenerate = 10; - private char _delimiter = ','; + ~CsvFaker() + { + _stream?.Dispose(); } -} + private void WriteRow(string[] values) + { + _stream.WriteLine(string.Join(_delimiter, values)); + } + + private char _delimiter = ','; + private uint _rowCount = 500; + private readonly StreamWriter _stream; + private readonly Dictionary> _columnMetadata = new Dictionary>(); +} diff --git a/src/Faker.NET/Attributes/FakerPersonAttributes.cs b/src/Faker.NET/Attributes/FakerPersonAttributes.cs index b2f710e..08deacd 100644 --- a/src/Faker.NET/Attributes/FakerPersonAttributes.cs +++ b/src/Faker.NET/Attributes/FakerPersonAttributes.cs @@ -11,13 +11,16 @@ public class FakerPersonBioAttribute : FakerAttribute public class FakerPersonFirstNameAttribute : FakerAttribute { public Sex? Sex { get; set; } = null; + public override object GetPropertyValue() => Faker.Person.FirstName(Sex); } public class FakerPersonFullNameAttribute : FakerAttribute { public string? FirstName { get; set; } = null; + public string? LastName { get; set; } = null; + public Sex? Sex { get; set; } = null; public override object GetPropertyValue() => Faker.Person.FullName(FirstName, LastName, Sex); @@ -50,18 +53,21 @@ public class FakerPersonJobTypeAttribute : FakerAttribute public class FakerPersonLastNameAttribute : FakerAttribute { public Sex? Sex { get; set; } = null; + public override object GetPropertyValue() => Faker.Person.LastName(Sex); } public class FakerPersonMiddleNameAttribute : FakerAttribute { public Sex? Sex { get; set; } = null; + public override object GetPropertyValue() => Faker.Person.MiddleName(Sex); } public class FakerPersonPrefixAttribute : FakerAttribute { public Sex? Sex { get; set; } = null; + public override object GetPropertyValue() => Faker.Person.Prefix(Sex); } diff --git a/src/Faker.NET/Common/Exceptions/ThrowHelper.cs b/src/Faker.NET/Common/Exceptions/ThrowHelper.cs index 64e3009..952aacf 100644 --- a/src/Faker.NET/Common/Exceptions/ThrowHelper.cs +++ b/src/Faker.NET/Common/Exceptions/ThrowHelper.cs @@ -2,6 +2,22 @@ namespace Faker.NET.Common.Exceptions; public static class ThrowHelper { + public static void IfNullOrEmpty(string value, string message) + { + if (string.IsNullOrEmpty(value)) + { + throw new NullReferenceException(message); + } + } + + public static void IfNotWritable(Stream stream, string message = "Unable to write to stream") + { + if (!stream.CanWrite) + { + throw new Exception(message); + } + } + public static void NotImplementedException() { throw new NotImplementedException(); diff --git a/tests/Faker.NET.Tests/Attributes/Computer.cs b/tests/Faker.NET.Tests/Attributes/Computer.cs index 48cc73f..3bba66d 100644 --- a/tests/Faker.NET.Tests/Attributes/Computer.cs +++ b/tests/Faker.NET.Tests/Attributes/Computer.cs @@ -8,25 +8,16 @@ public class Computer : DeterministicTestClass public void ClassAttributesCsv() { string[] expected = { - "DisplayName,DomainName,DomainSuffix,DomainWord,Email,Emoji,HttpMethod,HttpStatusCode,IPv4,IPv6,JWT,Mac,Password,Port,Protocol,Url,UserAgent,Username", -"johanj,ripe-boring.toys,.limited,shadowy-precious,zvolkman@uniform-burly.okinawa,🪝,DELETE,504 Gateway Timeout,139.99.188.167,d661:ab44:dc89:ed19:a4b1:77f9:32fd:b90f,,6B9D8C6F97E7,2aatY!E0>8jT8a&,9821,http,https://bustling-dull.lawyer,\"Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36\",jschmeler", -"rbarrows,neat-happy-go-lucky.am,.fish,enchanting-powerless,madelynnh@flimsy-easy.dentist,🔝,GET,300 Multiple Choices,214.73.235.20,d083:4092:acc3:1e02:fd9e:2e1d:c6d3:c119,,F8C1F202EAE6,67/#54;7?1rH9l3,44138,http,https://concerned-true.moe,\"Mozilla/5.0 (Linux; Android 13; SM-G991U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36\",halle.tremblay", -"theron.turner,jagged-broken.consulting,.cooking,red-wasteful,blick.obie@forsaken-energetic.stream,👨‍🍳,POST,404 Not Found,243.73.124.209,c924:e90f:23be:d5eb:6ba3:3cc7:e3ae:f0da,,BB85A841CB8C,#P4818>37H42$r2,44880,https,https://lighthearted-first.lighting,\"Mozilla/5.0 (iPhone13,2; U; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/15E148 Safari/602.1\",letitia.rohan", -"devanted,right-scaly.media,.supplies,excited-vengeful,dach.dimitri@confused-unhealthy.lease,🐅,GET,413 Content Too Large,129.227.72.105,d0b:4fba:a3d3:a40f:7416:3033:a2a9:ef0,,0C6376B7E241,g2)Re4bByyy8\"0i,11298,http,https://intent-bare.la,\"Mozilla/5.0 (Linux; Android 12; 2201116SG) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36\",drake.cruickshank", -"greggz,colorful-ideal.us.com,.pet,huge-vivacious,aemmerich@excellent-stained.hosting,👨🏿‍🎤,PUT,422 Unprocessable Content (WebDAV),252.190.28.12,4e82:7d:b18:ac83:19f4:c658:ebd4:876d,,F3F105B0FEDD,32#80CLBD8b88fS,27620,https,https://buttery-ajar.reviews,\"Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36\",ostanton", +"DisplayName,DomainName,DomainSuffix,DomainWord,Email,Emoji,HttpMethod,HttpStatusCode,IPv4,IPv6,JWT,Mac,Password,Port,Protocol,Url,UserAgent,Username", +"johanj,ripe-boring.toys,.limited,shadowy-precious,zvolkman@uniform-burly.okinawa,🪝,DELETE,504 Gateway Timeout,139.99.188.167,d661:ab44:dc89:ed19:a4b1:77f9:32fd:b90f,,6B9D8C6F97E7,2aatY!E0>8jT8a&,9821,http,https://bustling-dull.lawyer,Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", +"jschmeler,super-well-lit.gs,.asia,oddball-neat,ffarrell@quarterly-winding.dance,🪰,POST,226 IM Used (HTTP Delta encoding),70.229.54.14,5932:73cb:ead0:8340:92ac:c31e:2fd:9e2e,,35C05F8C1F20,x37H,65166,https,https://soft-elliptical.qpon,Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1", +"cgoodwin,quarrelsome-lighthearted.dental,.lighting,avaricious-plump,dicki.philip@sure-footed-married.coach,📏,DELETE,415 Unsupported Media Type,217.62.236.67,7052:b385:e719:afec:da9b:f51b:faa:640d,,ED12B2BB40E6,Ca3lSWheYNH!s$l,3446,http,https://wise-celebrated.xyz,Mozilla/5.0 (iPhone14,6; U; CPU iPhone OS 15_4 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/19E241 Safari/602.1", +"wilmer.labadie,well-groomed-actual.claims,.family,decisive-affectionate,kirlin.hester@short-idolized.click,🥳,GET,502 Bad Gateway,253.216.31.97,2317:e8ea:a6fd:4e70:eca2:aef4:b368:40ae,,FB1080C59FD9,555m21h\"8732#80,22545,http,https://lavish-juicy.diet,Mozilla/5.0 (iPhone12,1; U; CPU iPhone OS 13_0 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/15E148 Safari/602.1" }; - var csvFaker = CsvUtils.ToCsvRows(); - - Assert.That(csvFaker.Count, Is.EqualTo(expected.Length)); - - Assert.Multiple(() => - { - for (int i = 0; i < csvFaker.Count; i++) - { - Asserts.IsEqual(csvFaker[i], expected[i]); - } - }); + var csvFaker = CsvUtils.ToCsvRows().ToArray(); + Assert.That(csvFaker.ToArray(), Is.EquivalentTo(expected)); } } diff --git a/tests/Faker.NET.Tests/Attributes/Lorem.cs b/tests/Faker.NET.Tests/Attributes/Lorem.cs index 5c55542..f77aa48 100644 --- a/tests/Faker.NET.Tests/Attributes/Lorem.cs +++ b/tests/Faker.NET.Tests/Attributes/Lorem.cs @@ -9,17 +9,17 @@ public class Lorem : DeterministicTestClass public void ClassAttributesCsv() { var csvFaker = CsvUtils.ToCsvRows(); - - Assert.That(csvFaker.Count, Is.EqualTo(6)); + var count = 0; Assert.Multiple(() => { - for (int i = 0; i < csvFaker.Count; i++) + foreach (var line in csvFaker) { - var line = csvFaker[i].Replace(",", string.Empty); - Assert.That(line, Is.Not.WhiteSpace.Or.Null.Or.Empty); + count++; + Assert.That(line.Replace(",", string.Empty), Is.Not.WhiteSpace.Or.Null.Or.Empty); } }); + Assert.That(count, Is.EqualTo(6)); } } diff --git a/tests/Faker.NET.Tests/Attributes/PhoneNumbers.cs b/tests/Faker.NET.Tests/Attributes/PhoneNumbers.cs index e5f6dbc..49a7cb0 100644 --- a/tests/Faker.NET.Tests/Attributes/PhoneNumbers.cs +++ b/tests/Faker.NET.Tests/Attributes/PhoneNumbers.cs @@ -11,25 +11,15 @@ public void ClassAttributesCsv() { string[] expected = { "PhoneNumber,CountryCode,WithAreaCode", - "253-860-8565 x8848,805-776-8436 x5711,885.314.1177 x5336", - "(747) 485-4746 x2001,273-860-2160,878.234.7781 x0611", - "1-114-741-8757 x840,(530) 325-5823 x7212,1-202-728-0584 x50023", - "1-162-360-3846 x181,286-836-6565,607.655.6787 x488", - "1-262-347-1473,1-317-563-0580 x8428,1-401-268-6610", + "253-860-8565 x8848,805-776-8436 x5711", + "885.314.1177 x5336,(747) 485-4746 x2001", + "273-860-2160,878.234.7781 x0611", + "1-114-741-8757 x840,(530) 325-5823 x7212", + "1-202-728-0584 x50023,1-162-360-3846 x181" }; - var csvFaker = CsvUtils.ToCsvRows(); - - Assert.That(csvFaker.Count, Is.EqualTo(expected.Length)); - - Assert.Multiple(() => - { - for (int i = 0; i < csvFaker.Count; i++) - { - Console.WriteLine(csvFaker[i]); - Assert.That(csvFaker[i], Is.EqualTo(expected[i])); - } - }); + var csvFaker = CsvUtils.ToCsvRows().ToArray(); + Assert.That(csvFaker, Is.EquivalentTo(expected)); } } diff --git a/tests/Faker.NET.Tests/Files/Csv.cs b/tests/Faker.NET.Tests/Files/Csv.cs index af1f159..a5e1f95 100644 --- a/tests/Faker.NET.Tests/Files/Csv.cs +++ b/tests/Faker.NET.Tests/Files/Csv.cs @@ -1,189 +1,83 @@ using Faker.NET.Attributes; using Faker.NET.Files.Csv; +using Faker.NET.Tests.Utils; namespace Faker.NET.Tests.Files { - public class Csv + public class Csv : FileBasedTestClass { - [Test] - public void GenerateCsv() - { - // using the static first name here will generate the same same for every row - // use () => Name.FirstName to turn this into a func. - var faker = CreateCsvFaker(); - - // Generate a single row - var value = faker.GenerateRow(); - - // default 10 rows - var values = faker.Generate(); - - // 10 rows and 1 header row - Assert.That(values.Count(), Is.EqualTo(11)); - - values = faker.Iterations(25).Generate(); - - // 25 rows and 1 header row - Assert.That(values.Count(), Is.EqualTo(26)); - } - [Test] [TestCase(100_000)] [TestCase(200_000)] [TestCase(500_000)] + [TestCase(1_000_000)] public void GenerateMassiveRows(int rowCount) { // more of a proof of concept rather than testing because Generate() returns an IEnumerable // at time of writing will generate 3,000,000 values in about 2.5 seconds - var faker = CreateCsvFaker().Iterations((uint)rowCount); - faker.Generate().ToArray(); - } - - [Test] - [TestCase(100_000)] - [TestCase(200_000)] - [TestCase(500_000)] - public void GenerateParallelMassiveRows(int rowCount) - { - var faker = CreateCsvFaker().Iterations((uint)rowCount); - faker.GenerateParallel(); + var path = IO.GetRandomTempFilePath(); + var faker = CsvFaker.ToFile(path) + .AddTestColumns() + .WithRowCount((uint)rowCount); + faker.Write(); } [Test] public void GenerateFileFromPath() { - var tempPath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); - - var faker = CreateCsvFaker(tempPath); - faker.WriteRows(); - - ICollection lines = new List(); - - using (var file = File.OpenRead(tempPath)) - using (var reader = new StreamReader(file)) - { - while (!reader.EndOfStream) - { - var line = reader.ReadLine(); - if (line is not null) - { - lines.Add(line); - } - } - } - - Assert.That(lines.Count, Is.EqualTo(11)); - - File.Delete(tempPath); + var tempPath = IO.GetRandomTempFilePath(); + var faker = CsvFaker.ToFile(tempPath).AddTestColumns(); + faker.Write(); + CheckFile(tempPath, 501); } [Test] public void GenerateFileFromStreamReadError() { - var tempPath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); + var tempPath = IO.GetRandomTempFilePath(); - using (var stream = File.OpenRead(tempPath)) - { - Assert.Throws(() => CreateCsvFaker(stream)); - } - - if (File.Exists(tempPath)) - { - File.Delete(tempPath); - } + using var stream = File.Open(tempPath, FileMode.OpenOrCreate, FileAccess.Read); + Assert.Throws(() => CsvFaker.ToStream(stream)); } [Test] public void GenerateFileFromStream() { - var tempPath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); + var tempPath = IO.GetRandomTempFilePath(); using var writeStream = File.OpenWrite(tempPath); - - var faker = CreateCsvFaker(writeStream); - - faker.WriteRows(); - - ICollection lines = new List(); - - using (var file = File.OpenRead(tempPath)) - using (var reader = new StreamReader(file)) - { - while (!reader.EndOfStream) - { - lines.Add(reader.ReadLine() ?? string.Empty); - } - } - - Assert.That(lines.Count, Is.EqualTo(11)); - - File.Delete(tempPath); - } - - [Test] - [TestCase(100_000)] - public void GenerateFile(int rowCount) - { - var tempPath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); - var lines = CreateFileGetLineCount(tempPath, (uint)rowCount); - - // amount of lines plus the header - Assert.That(lines, Is.EqualTo(rowCount + 1)); + var faker = CsvFaker.ToStream(writeStream).AddTestColumns(); + faker.Write(); + CheckFile(tempPath, 501); } [Test] public void GenerateTypeCsv() { - var csvFaker = new CsvFaker() - .Iterations(100) - .Generate(); + var path = IO.GetRandomTempFilePath(); + CsvFaker.ToFile(path) + .WithRowCount(100) + .FromClass() + .Write(); - foreach (var line in csvFaker) - { - // make sure there is actually data there - var lines = line.Split(',', StringSplitOptions.RemoveEmptyEntries); - Assert.That(lines.Length, Is.GreaterThanOrEqualTo(3)); - } - - Assert.That(csvFaker.Count(), Is.EqualTo(101)); + CheckFile(path, 101); } - private int CreateFileGetLineCount(string tempPath, uint rowCount = 10) + private static void CheckFile(string path, uint expectedRows) { - using var stream = File.OpenWrite(tempPath); - - var faker = CreateCsvFaker(stream).Iterations(rowCount); - faker.WriteRows(); - - var lines = 0; - - using (var file = File.OpenRead(tempPath)) + var actualLines = 0; + using (var file = File.OpenRead(path)) using (var reader = new StreamReader(file)) { while (!reader.EndOfStream) { - reader.ReadLine(); - lines++; + if (reader.ReadLine() is not null) + { + actualLines += 1; + } } } - File.Delete(tempPath); - - return lines; - } - - private CsvFaker CreateCsvFaker() - { - return new CsvFaker().AddTestColumns(); - } - - private CsvFaker CreateCsvFaker(string tempPath) - { - return new CsvFaker(tempPath).AddTestColumns(); - } - - private CsvFaker CreateCsvFaker(Stream stream) - { - return new CsvFaker(stream).AddTestColumns(); + Assert.That(expectedRows, Is.EqualTo(actualLines)); } public class FakeClass @@ -202,17 +96,3 @@ public class FakeClass } } } - -internal static class CsvFakerExtensions -{ - public static CsvFaker AddTestColumns(this CsvFaker faker) - { - return faker - .AddColumn("name", () => Faker.NET.Faker.Person.FirstName()) - .AddColumn("date", () => Faker.NET.Faker.Date.Anytime().ToString()) - .AddColumn("update_date", () => DateTime.Now.ToString("dddd, dd MMMM yyyy HH:mm:ss")) - .AddColumn("text", () => Faker.NET.Faker.Lorem.Words(35, 35)) - .AddColumn("ip", () => Faker.NET.Faker.Internet.IPv4()) - .AddColumn("small_variable_message", () => Faker.NET.Faker.Lorem.Words(5, 10)); - } -} diff --git a/tests/Faker.NET.Tests/Files/Sql.cs b/tests/Faker.NET.Tests/Files/Sql.cs index d5f4073..e7e560f 100644 --- a/tests/Faker.NET.Tests/Files/Sql.cs +++ b/tests/Faker.NET.Tests/Files/Sql.cs @@ -1,14 +1,15 @@ using Faker.NET.Files.Sql; +using Faker.NET.Tests.Utils; using System.Data; namespace Faker.NET.Tests.Files { - internal class Sql + internal class Sql : FileBasedTestClass { [Test] public void GenerateInsert() { - var tempPath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); + var tempPath = IO.GetRandomTempFilePath(); using var writeStream = File.OpenWrite(tempPath); var faker = new SqlFaker(writeStream) diff --git a/tests/Faker.NET.Tests/Utils/CsvUtils.cs b/tests/Faker.NET.Tests/Utils/CsvUtils.cs index e005a0f..c301393 100644 --- a/tests/Faker.NET.Tests/Utils/CsvUtils.cs +++ b/tests/Faker.NET.Tests/Utils/CsvUtils.cs @@ -4,11 +4,36 @@ namespace Faker.NET.Tests.Utils; public static class CsvUtils { - public static List ToCsvRows() + public static IEnumerable ToCsvRows() { - return new CsvFaker() - .Iterations(5) - .Generate() - .ToList(); + using var memStream = new MemoryStream(); + var faker = CsvFaker.ToStream(memStream) + .WithRowCount(5) + .FromClass(); + faker.Write(keepStreamOpen: true); + + memStream.Position = 0; + using var streamReader = new StreamReader(memStream); + while (!streamReader.EndOfStream) + { + var line = streamReader.ReadLine(); + if (line is not null) + { + yield return line; + } + } + } + + public static CsvFaker AddTestColumns(this CsvFaker faker) + { + return faker.WithColumns(new() + { + { "name", () => Faker.Person.FirstName() }, + { "date", () => Faker.Date.Anytime().ToString() }, + { "update_date", () => DateTime.Now.ToString("dddd, dd MMMM yyyy HH:mm:ss") }, + { "text", () => Faker.Lorem.Words(35, 35) }, + { "ip", () => Faker.Internet.IPv4() }, + { "small_variable_message", () => Faker.Lorem.Words(5, 10) } + }); } } diff --git a/tests/Faker.NET.Tests/Utils/FileBasedTestClass.cs b/tests/Faker.NET.Tests/Utils/FileBasedTestClass.cs new file mode 100644 index 0000000..51a52d4 --- /dev/null +++ b/tests/Faker.NET.Tests/Utils/FileBasedTestClass.cs @@ -0,0 +1,12 @@ +using System; + +namespace Faker.NET.Tests.Utils; + +public abstract class FileBasedTestClass +{ + [TearDown] + public void CleanUp() + { + IO.CleanTempDirectory(); + } +} diff --git a/tests/Faker.NET.Tests/Utils/IO.cs b/tests/Faker.NET.Tests/Utils/IO.cs new file mode 100644 index 0000000..bc7078b --- /dev/null +++ b/tests/Faker.NET.Tests/Utils/IO.cs @@ -0,0 +1,19 @@ +using System; + +namespace Faker.NET.Tests.Utils; + +public static class IO +{ + public static string GetRandomTempFilePath() + { + return Path.Combine(Path.GetTempPath(), $"fakernet_{Path.GetRandomFileName()}"); + } + + public static void CleanTempDirectory() + { + foreach (var file in Directory.GetFiles(Path.GetTempPath(), "fakernet_*")) + { + File.Delete(file); + } + } +}