diff --git a/src/System.IO.Abstractions.Extensions/IFileInfoExtensions.cs b/src/System.IO.Abstractions.Extensions/IFileInfoExtensions.cs index f01ec0a..56b5f4a 100644 --- a/src/System.IO.Abstractions.Extensions/IFileInfoExtensions.cs +++ b/src/System.IO.Abstractions.Extensions/IFileInfoExtensions.cs @@ -1,5 +1,4 @@ -using System.Collections; -using System.Collections.Generic; +using System.Collections.Generic; using System.Text; namespace System.IO.Abstractions @@ -7,35 +6,125 @@ namespace System.IO.Abstractions public static class IFileInfoExtensions { /// - /// Throws an exception if the file doesn't exists + /// Throws an exception if the doesn't exists /// - /// File that will be checked for existance + /// File that will be checked for existance /// Exception thrown if the file is not found - public static void ThrowIfNotFound(this IFileInfo info) + public static void ThrowIfNotFound(this IFileInfo file) { - if (!info.Exists) - throw new FileNotFoundException(StringResources.Format("COULD_NOT_FIND_FILE_EXCEPTION", info.FullName)); + if (!file.Exists) + throw new FileNotFoundException(StringResources.Format("COULD_NOT_FIND_FILE_EXCEPTION", file.FullName)); } /// - /// Creates an that can enumerate the lines of text in the file + /// Creates an that can enumerate the lines of text in the /// - /// File to enumerate content + /// File to enumerate content /// Returns an to enumerate the content of the file - public static IEnumerable EnumerateLines(this IFileInfo info) + public static IEnumerable EnumerateLines(this IFileInfo file) { - return new LineEnumerable(info, null); + return new LineEnumerable(file, null); } /// - /// Creates an that can enumerate the lines of text in the file + /// Creates an that can enumerate the lines of text in the specified /// using the specified /// - /// File to enumerate content + /// File to enumerate content /// Returns an to enumerate the content of the file - public static IEnumerable EnumerateLines(this IFileInfo info, Encoding encoding) + public static IEnumerable EnumerateLines(this IFileInfo file, Encoding encoding) { - return new LineEnumerable(info, encoding); + return new LineEnumerable(file, encoding); + } + + /// + /// Opens a for the in the specified + /// + /// File to open stream on + /// Mode to use when opening the file + /// A that can read or write data to the specified + public static FileSystemStream OpenFileStream(this IFileInfo file, FileMode mode) + { + return file.FileSystem.FileStream.New(file.FullName, mode); + } + + /// + /// Creates a new empty . + /// If the file already exists, the file is truncated. + /// + /// File to create + /// The original so that methods calls can be chained + public static IFileInfo Truncate(this IFileInfo file) + { + using(var stream = file.OpenFileStream(FileMode.Create)) + { + stream.Dispose(); + } + + return file; + } + + /// + /// Writes the specified to the specified using the UTF-8 encoding. + /// If the file already exists and the flag is set to true, the file will be truncated. + /// + /// File to write to + /// Lines to write to file as text + /// Flag that specifies if the file can be overwritten if it exists + /// Exception thrown if the file already exists and the flag is set to + public static void WriteLines(this IFileInfo file, IEnumerable lines, bool overwrite = false) + { + using (var stream = file.OpenFileStream(GetWriteFileMode(file, overwrite))) + using (var writer = new StreamWriter(stream)) + foreach(var line in lines) + { + writer.WriteLine(line); + } + } + + /// + /// Writes the specified to the specified + /// using the specified . + /// If the file already exists and the flag is set to true, the file will be truncated. + /// + /// File to write to + /// Lines to write to file as text + /// Encoding to use when writing the to the text file + /// Flag that specifies if the file can be overwritten if it exists + /// Exception thrown if the file already exists and the flag is set to + public static void WriteLines(this IFileInfo file, IEnumerable lines, Encoding encoding, bool overwrite = false) + { + using (var stream = file.OpenFileStream(GetWriteFileMode(file, overwrite))) + using (var writer = new StreamWriter(stream, encoding)) + foreach (var line in lines) + { + writer.WriteLine(line); + } + } + + /// + /// Appends the specified to the specified + /// + /// File to append to + /// Lines to append to file as text + public static void AppendLines(this IFileInfo file, IEnumerable lines) + { + using (var writer = file.AppendText()) + foreach (var line in lines) + { + writer.WriteLine(line); + } + } + + private static FileMode GetWriteFileMode(IFileInfo info, bool overwrite) + { + if (!overwrite && info.Exists) + { + throw new IOException(StringResources.Format("CANNOT_OVERWRITE", info.FullName)); + } + + //if the file already exists it will be truncated + return FileMode.Create; } } } diff --git a/src/System.IO.Abstractions.Extensions/Resources.Designer.cs b/src/System.IO.Abstractions.Extensions/Resources.Designer.cs index 941a55d..d24f193 100644 --- a/src/System.IO.Abstractions.Extensions/Resources.Designer.cs +++ b/src/System.IO.Abstractions.Extensions/Resources.Designer.cs @@ -60,6 +60,15 @@ internal Resources() { } } + /// + /// Looks up a localized string similar to The file '{0}' already exists.. + /// + internal static string CANNOT_OVERWRITE { + get { + return ResourceManager.GetString("CANNOT_OVERWRITE", resourceCulture); + } + } + /// /// Looks up a localized string similar to Could not find file '{0}'.. /// @@ -79,7 +88,7 @@ internal static string COULD_NOT_FIND_PART_OF_PATH_EXCEPTION { } /// - /// Looks up a localized string similar to '{0}' is not an ancestor of '{1}'. + /// Looks up a localized string similar to '{0}' is not an ancestor of '{1}'.. /// internal static string NOT_AN_ANCESTOR { get { diff --git a/src/System.IO.Abstractions.Extensions/Resources.resx b/src/System.IO.Abstractions.Extensions/Resources.resx index b031282..3293806 100644 --- a/src/System.IO.Abstractions.Extensions/Resources.resx +++ b/src/System.IO.Abstractions.Extensions/Resources.resx @@ -117,6 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + The file '{0}' already exists. + Could not find file '{0}'. @@ -124,6 +127,6 @@ Could not find a part of the path '{0}'. - '{0}' is not an ancestor of '{1}' + '{0}' is not an ancestor of '{1}'. \ No newline at end of file diff --git a/tests/System.IO.Abstractions.Extensions.Tests/FileInfoExtensionsTests.cs b/tests/System.IO.Abstractions.Extensions.Tests/FileInfoExtensionsTests.cs index 43ff25c..57aacf3 100644 --- a/tests/System.IO.Abstractions.Extensions.Tests/FileInfoExtensionsTests.cs +++ b/tests/System.IO.Abstractions.Extensions.Tests/FileInfoExtensionsTests.cs @@ -1,5 +1,4 @@ using NUnit.Framework; -using System.Collections.Generic; using System.Linq; using System.Text; @@ -34,10 +33,7 @@ public void ThrowIfNotFound_IfFileExists_DoesNotThrowException() var file = current.File(guid); //act - using (var stream = file.Create()) - { - stream.Dispose(); - } + file.Truncate(); file.ThrowIfNotFound(); //assert @@ -47,6 +43,50 @@ public void ThrowIfNotFound_IfFileExists_DoesNotThrowException() file.Delete(); } + [Test] + public void Truncate_AnExistingFileWithContent_FileExistsAndIsEmpty() + { + //arrange + var fs = new FileSystem(); + var current = fs.DirectoryInfo.New(fs.Directory.GetCurrentDirectory()); + var guid = Guid.NewGuid().ToString(); + var file = current.File(guid); + //create file + using (var stream = file.OpenWrite()) + using (var writer = new StreamWriter(stream, Encoding.UTF8)) + { + writer.WriteLine("test"); + } + file.Refresh(); + Assert.IsTrue(file.Exists); + Assert.IsTrue(file.Length >= 4); + + //act + file.Truncate(); + + //assert + file.Refresh(); + Assert.AreEqual(0, file.Length); + } + + [Test] + public void Truncate_ANewFile_FileExistsAndIsEmpty() + { + //arrange + var fs = new FileSystem(); + var current = fs.DirectoryInfo.New(fs.Directory.GetCurrentDirectory()); + var guid = Guid.NewGuid().ToString(); + var file = current.File(guid); + Assert.IsFalse(file.Exists); + + //act + file.Truncate(); + + //assert + file.Refresh(); + Assert.AreEqual(0, file.Length); + } + [TestCase("line1", "line2", "line3")] [TestCase("line1", "", "line3")] public void EnumerateLines_ReadFromExistingFile_ReturnsLines(params string[] content) @@ -60,7 +100,7 @@ public void EnumerateLines_ReadFromExistingFile_ReturnsLines(params string[] con using (var stream = file.OpenWrite()) using (var writer = new StreamWriter(stream, Encoding.UTF8)) { - foreach(var line in content) + foreach (var line in content) writer.WriteLine(line); } @@ -69,10 +109,186 @@ public void EnumerateLines_ReadFromExistingFile_ReturnsLines(params string[] con //assert Assert.AreEqual(content.Length, actual.Length); - for(int i=0; i(() => file.WriteLines(content)); + var ex2 = Assert.Throws(() => file.WriteLines(content, false)); + + Assert.IsTrue(ex1.Message.Contains(file.FullName)); + Assert.IsTrue(ex2.Message.Contains(file.FullName)); + } + + [TestCase("line1", "line2", "line3")] + [TestCase("line1", "", "line3")] + public void WriteLines_WriteLinesToExistingFileWithOverwriteEnabled_FileIsTruncatedAndLinesAreWritten(params string[] content) + { + //arrange + var fs = new FileSystem(); + var current = fs.DirectoryInfo.New(fs.Directory.GetCurrentDirectory()); + var guid = Guid.NewGuid().ToString(); + var file = current.File(guid); + + //create file with long content + var data = Encoding.UTF8.GetBytes("line5 line4 line3 line2 line1"); + using (var stream = file.OpenWrite()) + { + stream.Write(data, 0, data.Length); + stream.Dispose(); + } + + //act + Assert.IsTrue(file.Exists); + file.WriteLines(content, overwrite: true); + var actual = file.EnumerateLines().ToArray(); + + //assert + Assert.AreEqual(content.Length, actual.Length); + for (int i = 0; i < content.Length; i++) + { + Assert.AreEqual(content[i], actual[i]); + } + } + + [TestCase("line1", "line2", "line3")] + [TestCase("line1", "", "line3")] + public void WriteLinesWithUTF16Encoding_WriteLinesToNewFile_LinesAreWritten(params string[] content) + { + //arrange + var fs = new FileSystem(); + var current = fs.DirectoryInfo.New(fs.Directory.GetCurrentDirectory()); + var guid = Guid.NewGuid().ToString(); + var file = current.File(guid); + + //act + Assert.IsFalse(file.Exists); + file.WriteLines(content, Encoding.Unicode); + var actual = file.EnumerateLines(Encoding.Unicode).ToArray(); + + //assert + Assert.AreEqual(content.Length, actual.Length); + for (int i = 0; i < content.Length; i++) + { + Assert.AreEqual(content[i], actual[i]); + } + } + + [TestCase("line1", "line2", "line3")] + [TestCase("line1", "", "line3")] + public void WriteLinesWithUTF16Encoding_WriteLinesToExistingFileWithOverwriteDisabled_ThrowsIOException(params string[] content) + { + //arrange + var fs = new FileSystem(); + var current = fs.DirectoryInfo.New(fs.Directory.GetCurrentDirectory()); + var guid = Guid.NewGuid().ToString(); + var file = current.File(guid); + file.Truncate(); + + //act & assert + Assert.IsTrue(file.Exists); + //call WriteLines with both overwrite parameter ommitted or set to false + var ex1 = Assert.Throws(() => file.WriteLines(content, Encoding.Unicode)); + var ex2 = Assert.Throws(() => file.WriteLines(content, Encoding.Unicode, false)); + + Assert.IsTrue(ex1.Message.Contains(file.FullName)); + Assert.IsTrue(ex2.Message.Contains(file.FullName)); + } + + [TestCase("line1", "line2", "line3")] + [TestCase("line1", "", "line3")] + public void WriteLinesWithUTF16Encoding_WriteLinesToExistingFileWithOverwriteEnabled_FileIsTruncatedAndLinesAreWritten(params string[] content) + { + //arrange + var fs = new FileSystem(); + var current = fs.DirectoryInfo.New(fs.Directory.GetCurrentDirectory()); + var guid = Guid.NewGuid().ToString(); + var file = current.File(guid); + + //create file with long content + var data = Encoding.Unicode.GetBytes("line5 line4 line3 line2 line1"); + using (var stream = file.OpenWrite()) + { + stream.Write(data, 0, data.Length); + stream.Dispose(); + } + + //act + Assert.IsTrue(file.Exists); + file.WriteLines(content, Encoding.Unicode, overwrite: true); + var actual = file.EnumerateLines(Encoding.Unicode).ToArray(); + + //assert + Assert.AreEqual(content.Length, actual.Length); + for (int i = 0; i < content.Length; i++) + { + Assert.AreEqual(content[i], actual[i]); + } + } + + [TestCase("line1", "line2", "line3")] + [TestCase("line1", "", "line3")] + public void AppendText_FileExistsAndHasText_LinesAreAppended(params string[] append) + { + //arrange + var initial = new[] { "test1", "test2", "test3" }; + var fs = new FileSystem(); + var current = fs.DirectoryInfo.New(fs.Directory.GetCurrentDirectory()); + var guid = Guid.NewGuid().ToString(); + var file = current.File(guid); + file.WriteLines(initial); + + //act + file.AppendLines(append); + + //assert + var expected = initial.Concat(append).ToArray(); + var actual = file.EnumerateLines().ToArray(); + + Assert.AreEqual(expected.Length, actual.Length); + for (int i = 0; i < expected.Length; i++) + { + Assert.AreEqual(expected[i], actual[i]); + } + } } -} +} \ No newline at end of file