Skip to content

Commit

Permalink
writing in an existing/new file respects the previous encoding
Browse files Browse the repository at this point in the history
respects bom
  • Loading branch information
manne committed Jan 25, 2015
1 parent ad67f04 commit 2335601
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 60 deletions.
113 changes: 87 additions & 26 deletions TestHelpers.Tests/MockFileTests.cs
Expand Up @@ -32,6 +32,27 @@ public void MockFile_AppendAllText_ShouldPersistNewText()
file.ReadAllText(path));
}

[Test]
public void MockFile_AppendAllText_ShouldPersistNewTextWithDifferentEncoding()
{
// Arrange
const string Path = @"c:\something\demo.txt";
var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
{
{ Path, new MockFileData("AA", Encoding.UTF32) }
});

var file = new MockFile(fileSystem);

// Act
file.AppendAllText(Path, "BB", Encoding.UTF8);

// Assert
CollectionAssert.AreEqual(
new byte[] { 255, 254, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 66, 66 },
fileSystem.GetFile(Path).Contents);
}

[Test]
public void MockFile_AppendAllText_ShouldCreateIfNotExist()
{
Expand All @@ -43,18 +64,29 @@ public void MockFile_AppendAllText_ShouldCreateIfNotExist()
});

// Act
var path2 = XFS.Path(@"c:\something\demo2.txt");
fileSystem.File.AppendAllText(path2, "some text");
var path3 = XFS.Path(@"c:\something\demo3.txt");
fileSystem.File.AppendAllText(path3, "some text", Encoding.Unicode);
fileSystem.File.AppendAllText(path, " some text");

// Assert
Assert.AreEqual(
"some text",
fileSystem.File.ReadAllText(path2));
Assert.AreEqual(
"some text",
fileSystem.File.ReadAllText(path3, Encoding.Unicode));
"Demo text content some text",
fileSystem.File.ReadAllText(path));
}

[Test]
public void MockFile_AppendAllText_ShouldCreateIfNotExistWithBom()
{
// Arrange
var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>());
const string path = @"c:\something\demo3.txt";
fileSystem.AddDirectory(@"c:\something\");

// Act
fileSystem.File.AppendAllText(path, "AA", Encoding.UTF32);

// Assert
CollectionAssert.AreEqual(
new byte[] { 255, 254, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0 },
fileSystem.GetFile(path).Contents);
}

[Test]
Expand Down Expand Up @@ -98,7 +130,7 @@ public void MockFile_AppendAllText_ShouldPersistNewTextWithCustomEncoding()
var expected = new byte[]
{
68, 101, 109, 111, 32, 116, 101, 120, 116, 32, 99, 111, 110, 116,
101, 110, 255, 253, 0, 43, 0, 32, 0, 115, 0, 111, 0, 109, 0, 101,
101, 110, 116, 0, 43, 0, 32, 0, 115, 0, 111, 0, 109, 0, 101,
0, 32, 0, 116, 0, 101, 0, 120, 0, 116
};

Expand Down Expand Up @@ -638,35 +670,64 @@ public void MockFile_WriteAllText_ShouldThrowAnUnauthorizedAccessExceptionIfFile
Assert.Throws<UnauthorizedAccessException>(action, "Access to the path '{0}' is denied.", path);
}

private IEnumerable<Encoding> GetEncodings()
private IEnumerable<KeyValuePair<Encoding, byte[]>> GetEncodingsWithExpectedBytes()
{
return new List<Encoding>()
Encoding utf8WithoutBom = new UTF8Encoding(false, true);
return new Dictionary<Encoding, byte[]>
{
Encoding.ASCII,
Encoding.BigEndianUnicode,
Encoding.Default,
Encoding.UTF32,
Encoding.UTF7,
Encoding.UTF8,
Encoding.Unicode
// ASCII does not need a BOM
{ Encoding.ASCII, new byte[] { 72, 101, 108, 108, 111, 32, 116,
104, 101, 114, 101, 33, 32, 68, 122, 105, 63, 107, 105, 46 } },

// BigEndianUnicode needs a BOM, the BOM is the first two bytes
{ Encoding.BigEndianUnicode, new byte [] { 254, 255, 0, 72, 0, 101,
0, 108, 0, 108, 0, 111, 0, 32, 0, 116, 0, 104, 0, 101, 0, 114,
0, 101, 0, 33, 0, 32, 0, 68, 0, 122, 0, 105, 1, 25, 0, 107, 0, 105, 0, 46 } },

// Default encoding does not need a BOM
{ Encoding.Default, new byte [] { 72, 101, 108, 108, 111, 32, 116,
104, 101, 114, 101, 33, 32, 68, 122, 105, 101, 107, 105, 46 } },

// UTF-32 needs a BOM, the BOM is the first four bytes
{ Encoding.UTF32, new byte [] {255, 254, 0, 0, 72, 0, 0, 0, 101,
0, 0, 0, 108, 0, 0, 0, 108, 0, 0, 0, 111, 0, 0, 0, 32, 0, 0,
0, 116, 0, 0, 0, 104, 0, 0, 0, 101, 0, 0, 0, 114, 0, 0, 0,
101, 0, 0, 0, 33, 0, 0, 0, 32, 0, 0, 0, 68, 0, 0, 0, 122, 0,
0, 0, 105, 0, 0, 0, 25, 1, 0, 0, 107, 0, 0, 0, 105, 0, 0, 0, 46, 0, 0, 0 } },

// UTF-7 does not need a BOM
{ Encoding.UTF7, new byte [] {72, 101, 108, 108, 111, 32, 116,
104, 101, 114, 101, 43, 65, 67, 69, 45, 32, 68, 122, 105,
43, 65, 82, 107, 45, 107, 105, 46 } },

// The default encoding does not need a BOM
{ utf8WithoutBom, new byte [] { 72, 101, 108, 108, 111, 32, 116,
104, 101, 114, 101, 33, 32, 68, 122, 105, 196, 153, 107, 105, 46 } },

// Unicode needs a BOM, the BOM is the first two bytes
{ Encoding.Unicode, new byte [] { 255, 254, 72, 0, 101, 0, 108,
0, 108, 0, 111, 0, 32, 0, 116, 0, 104, 0, 101, 0, 114, 0,
101, 0, 33, 0, 32, 0, 68, 0, 122, 0, 105, 0, 25, 1, 107, 0,
105, 0, 46, 0 } }
};
}

[TestCaseSource("GetEncodings")]
public void MockFile_WriteAllText_Encoding_ShouldWriteTextFileToMemoryFileSystem(Encoding encoding)
[TestCaseSource("GetEncodingsWithExpectedBytes")]
public void MockFile_WriteAllText_Encoding_ShouldWriteTextFileToMemoryFileSystem(KeyValuePair<Encoding, byte[]> encodingsWithContents)
{
// Arrange
const string FileContent = "Hello there! Dzięki.";
string path = XFS.Path(@"c:\something\demo.txt");
string fileContent = "Hello there! Dzięki.";
byte[] expectedBytes = encodingsWithContents.Value;
Encoding encoding = encodingsWithContents.Key;
var fileSystem = new MockFileSystem();

// Act
fileSystem.File.WriteAllText(path, fileContent, encoding);
fileSystem.File.WriteAllText(path, FileContent, encoding);

// Assert
Assert.AreEqual(
encoding.GetString(encoding.GetBytes(fileContent)),
fileSystem.GetFile(path).TextContents);
var actualBytes = fileSystem.GetFile(path).Contents;
Assert.AreEqual(expectedBytes, actualBytes);
}

[Test]
Expand Down
33 changes: 14 additions & 19 deletions TestingHelpers/MockFile.cs
@@ -1,10 +1,12 @@
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Security.AccessControl;
using System.Text;

namespace System.IO.Abstractions.TestingHelpers
{

[Serializable]
public class MockFile : FileBase
{
Expand All @@ -19,40 +21,33 @@ public MockFile(IMockFileDataAccessor mockFileDataAccessor)

public override void AppendAllText(string path, string contents)
{
if (!mockFileDataAccessor.FileExists(path))
{
var dir = mockFileDataAccessor.Path.GetDirectoryName(path);
if (!mockFileDataAccessor.Directory.Exists(dir))
{
throw new DirectoryNotFoundException(String.Format(CultureInfo.InvariantCulture, "Could not find a part of the path '{0}'.", path));
}
mockFileDataAccessor.AddFile(path, new MockFileData(contents));
}
else
{
mockFileDataAccessor
.GetFile(path)
.TextContents += contents;
}
AppendAllText(path, contents, MockFileData.DefaultEncoding);
}

public override void AppendAllText(string path, string contents, Encoding encoding)
{
ValidateParameter(path, "path");

if (encoding == null)
{
throw new ArgumentNullException("encoding");
}

if (!mockFileDataAccessor.FileExists(path))
{
var dir = mockFileDataAccessor.Path.GetDirectoryName(path);
if (!mockFileDataAccessor.Directory.Exists(dir))
{
throw new DirectoryNotFoundException(String.Format(CultureInfo.InvariantCulture, "Could not find a part of the path '{0}'.", path));
}
mockFileDataAccessor.AddFile(path, new MockFileData(encoding.GetBytes(contents)));

mockFileDataAccessor.AddFile(path, new MockFileData(contents, encoding));
}
else
{
var file = mockFileDataAccessor.GetFile(path);
var originalText = encoding.GetString(file.Contents);
var newText = originalText + contents;
file.Contents = encoding.GetBytes(newText);
var bytesToAppend = encoding.GetBytes(contents);
file.Contents = file.Contents.Concat(bytesToAppend).ToArray();
}
}

Expand Down
33 changes: 18 additions & 15 deletions TestingHelpers/MockFileData.cs
Expand Up @@ -2,10 +2,12 @@

namespace System.IO.Abstractions.TestingHelpers
{
using System.Linq;

[Serializable]
public class MockFileData
{
static readonly Encoding defaultEncoding = Encoding.UTF8;
public static readonly Encoding DefaultEncoding = new UTF8Encoding(false, true);

public static readonly MockFileData NullObject = new MockFileData(string.Empty) {
LastWriteTime = new DateTime(1601, 01, 01, 00, 00, 00, DateTimeKind.Utc),
Expand All @@ -14,35 +16,36 @@ public class MockFileData
};

byte[] contents;
Encoding encoding;
DateTimeOffset creationTime = new DateTimeOffset(2010, 01, 02, 00, 00, 00, TimeSpan.FromHours(4));
DateTimeOffset lastAccessTime = new DateTimeOffset(2010, 02, 04, 00, 00, 00, TimeSpan.FromHours(4));
DateTimeOffset lastWriteTime = new DateTimeOffset(2010, 01, 04, 00, 00, 00, TimeSpan.FromHours(4));

private FileAttributes attributes = FileAttributes.Normal;

public virtual bool IsDirectory { get { return false; } }


private MockFileData()
{
// empty
}

public MockFileData(string textContents)
: this(defaultEncoding.GetBytes(textContents))
: this(DefaultEncoding.GetBytes(textContents))
{}

public MockFileData(string textContents, Encoding encoding)
: this(encoding.GetBytes(textContents), encoding)
{ }
: this()
{
contents = encoding.GetPreamble().Concat(encoding.GetBytes(textContents)).ToArray();
}

public MockFileData(byte[] contents)
: this(contents, defaultEncoding)
{ }

public MockFileData(byte[] contents, Encoding encoding)
{
if (encoding == null)
if (contents == null)
{
throw new ArgumentNullException("encoding");
throw new ArgumentNullException("contents");
}

this.encoding = encoding;
this.contents = contents;
}

Expand All @@ -54,8 +57,8 @@ public byte[] Contents

public string TextContents
{
get { return encoding.GetString(contents); }
set { contents = encoding.GetBytes(value); }
get { return DefaultEncoding.GetString(contents); }
set { contents = DefaultEncoding.GetBytes(value); }
}

public DateTimeOffset CreationTime
Expand Down

0 comments on commit 2335601

Please sign in to comment.