diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/FileStreamWrapper.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/FileStreamWrapper.cs
deleted file mode 100644
index 74297a42..00000000
--- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/FileStreamWrapper.cs
+++ /dev/null
@@ -1,273 +0,0 @@
-//
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-//
-
-using System;
-using System.Diagnostics;
-using System.IO;
-using Microsoft.SqlTools.ServiceLayer.Utility;
-
-namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
-{
- ///
- /// Wrapper for a file stream, providing simplified creation, deletion, read, and write
- /// functionality.
- ///
- public class FileStreamWrapper : IFileStreamWrapper
- {
- #region Member Variables
-
- private byte[] buffer;
- private int bufferDataSize;
- private FileStream fileStream;
- private long startOffset;
- private long currentOffset;
-
- #endregion
-
- ///
- /// Constructs a new FileStreamWrapper and initializes its state.
- ///
- public FileStreamWrapper()
- {
- // Initialize the internal state
- bufferDataSize = 0;
- startOffset = 0;
- currentOffset = 0;
- }
-
- #region IFileStreamWrapper Implementation
-
- ///
- /// Initializes the wrapper by creating the internal buffer and opening the requested file.
- /// If the file does not already exist, it will be created.
- ///
- /// Name of the file to open/create
- /// The length of the internal buffer
- ///
- /// Whether or not the wrapper will be used for reading. If true, any calls to a
- /// method that writes will cause an InvalidOperationException
- ///
- public void Init(string fileName, int bufferLength, FileAccess accessMethod)
- {
- // Sanity check for valid buffer length, fileName, and accessMethod
- Validate.IsGreaterThan(nameof(bufferLength), bufferLength, 0);
- Validate.IsNotNullOrWhitespaceString(nameof(fileName), fileName);
- if (accessMethod == FileAccess.Write)
- {
- throw new ArgumentException(SR.QueryServiceFileWrapperWriteOnly, nameof(fileName));
- }
-
- // Setup the buffer
- buffer = new byte[bufferLength];
-
- // Open the requested file for reading/writing, creating one if it doesn't exist
- fileStream = new FileStream(fileName, FileMode.OpenOrCreate, accessMethod, FileShare.ReadWrite,
- bufferLength, false /*don't use asyncio*/);
- }
-
- ///
- /// Reads data into a buffer from the current offset into the file
- ///
- /// The buffer to output the read data to
- /// The number of bytes to read into the buffer
- /// The number of bytes read
- public int ReadData(byte[] buf, int bytes)
- {
- return ReadData(buf, bytes, currentOffset);
- }
-
- ///
- /// Reads data into a buffer from the specified offset into the file
- ///
- /// The buffer to output the read data to
- /// The number of bytes to read into the buffer
- /// The offset into the file to start reading bytes from
- /// The number of bytes read
- public int ReadData(byte[] buf, int bytes, long offset)
- {
- // Make sure that we're initialized before performing operations
- if (buffer == null)
- {
- throw new InvalidOperationException(SR.QueryServiceFileWrapperNotInitialized);
- }
-
- MoveTo(offset);
-
- int bytesCopied = 0;
- while (bytesCopied < bytes)
- {
- int bufferOffset, bytesToCopy;
- GetByteCounts(bytes, bytesCopied, out bufferOffset, out bytesToCopy);
- Buffer.BlockCopy(buffer, bufferOffset, buf, bytesCopied, bytesToCopy);
- bytesCopied += bytesToCopy;
-
- if (bytesCopied < bytes && // did not get all the bytes yet
- bufferDataSize == buffer.Length) // since current data buffer is full we should continue reading the file
- {
- // move forward one full length of the buffer
- MoveTo(startOffset + buffer.Length);
- }
- else
- {
- // copied all the bytes requested or possible, adjust the current buffer pointer
- currentOffset += bytesToCopy;
- break;
- }
- }
- return bytesCopied;
- }
-
- ///
- /// Writes data to the underlying filestream, with buffering.
- ///
- /// The buffer of bytes to write to the filestream
- /// The number of bytes to write
- /// The number of bytes written
- public int WriteData(byte[] buf, int bytes)
- {
- // Make sure that we're initialized before performing operations
- if (buffer == null)
- {
- throw new InvalidOperationException(SR.QueryServiceFileWrapperNotInitialized);
- }
- if (!fileStream.CanWrite)
- {
- throw new InvalidOperationException(SR.QueryServiceFileWrapperReadOnly);
- }
-
- int bytesCopied = 0;
- while (bytesCopied < bytes)
- {
- int bufferOffset, bytesToCopy;
- GetByteCounts(bytes, bytesCopied, out bufferOffset, out bytesToCopy);
- Buffer.BlockCopy(buf, bytesCopied, buffer, bufferOffset, bytesToCopy);
- bytesCopied += bytesToCopy;
-
- // adjust the current buffer pointer
- currentOffset += bytesToCopy;
-
- if (bytesCopied < bytes) // did not get all the bytes yet
- {
- Debug.Assert((int)(currentOffset - startOffset) == buffer.Length);
- // flush buffer
- Flush();
- }
- }
- Debug.Assert(bytesCopied == bytes);
- return bytesCopied;
- }
-
- ///
- /// Flushes the internal buffer to the filestream
- ///
- public void Flush()
- {
- // Make sure that we're initialized before performing operations
- if (buffer == null)
- {
- throw new InvalidOperationException(SR.QueryServiceFileWrapperNotInitialized);
- }
- if (!fileStream.CanWrite)
- {
- throw new InvalidOperationException(SR.QueryServiceFileWrapperReadOnly);
- }
-
- // Make sure we are at the right place in the file
- Debug.Assert(fileStream.Position == startOffset);
-
- int bytesToWrite = (int)(currentOffset - startOffset);
- fileStream.Write(buffer, 0, bytesToWrite);
- startOffset += bytesToWrite;
- fileStream.Flush();
-
- Debug.Assert(startOffset == currentOffset);
- }
-
- ///
- /// Deletes the given file (ideally, created with this wrapper) from the filesystem
- ///
- /// The path to the file to delete
- public static void DeleteFile(string fileName)
- {
- File.Delete(fileName);
- }
-
- #endregion
-
- ///
- /// Perform calculations to determine how many bytes to copy and what the new buffer offset
- /// will be for copying.
- ///
- /// Number of bytes requested to copy
- /// Number of bytes copied so far
- /// New offset to start copying from/to
- /// Number of bytes to copy in this iteration
- private void GetByteCounts(int bytes, int bytesCopied, out int bufferOffset, out int bytesToCopy)
- {
- bufferOffset = (int) (currentOffset - startOffset);
- bytesToCopy = bytes - bytesCopied;
- if (bytesToCopy > buffer.Length - bufferOffset)
- {
- bytesToCopy = buffer.Length - bufferOffset;
- }
- }
-
- ///
- /// Moves the internal buffer to the specified offset into the file
- ///
- /// Offset into the file to move to
- private void MoveTo(long offset)
- {
- if (buffer.Length > bufferDataSize || // buffer is not completely filled
- offset < startOffset || // before current buffer start
- offset >= (startOffset + buffer.Length)) // beyond current buffer end
- {
- // init the offset
- startOffset = offset;
-
- // position file pointer
- fileStream.Seek(startOffset, SeekOrigin.Begin);
-
- // fill in the buffer
- bufferDataSize = fileStream.Read(buffer, 0, buffer.Length);
- }
- // make sure to record where we are
- currentOffset = offset;
- }
-
- #region IDisposable Implementation
-
- private bool disposed;
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (disposed)
- {
- return;
- }
-
- if (disposing && fileStream != null)
- {
- if(fileStream.CanWrite) { Flush(); }
- fileStream.Dispose();
- }
-
- disposed = true;
- }
-
- ~FileStreamWrapper()
- {
- Dispose(false);
- }
-
- #endregion
- }
-}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/IFileStreamWrapper.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/IFileStreamWrapper.cs
deleted file mode 100644
index 38c283c5..00000000
--- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/IFileStreamWrapper.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-//
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-//
-
-using System;
-using System.IO;
-
-namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
-{
- ///
- /// Interface for a wrapper around a filesystem reader/writer, mainly for unit testing purposes
- ///
- public interface IFileStreamWrapper : IDisposable
- {
- void Init(string fileName, int bufferSize, FileAccess fileAccessMode);
- int ReadData(byte[] buffer, int bytes);
- int ReadData(byte[] buffer, int bytes, long fileOffset);
- int WriteData(byte[] buffer, int bytes);
- void Flush();
- }
-}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamFactory.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamFactory.cs
index c06a13ac..573a62d4 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamFactory.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamFactory.cs
@@ -29,7 +29,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
/// A
public IFileStreamReader GetReader(string fileName)
{
- return new ServiceBufferFileStreamReader(new FileStreamWrapper(), fileName);
+ return new ServiceBufferFileStreamReader(new FileStream(fileName, FileMode.Open, FileAccess.Read));
}
///
@@ -42,7 +42,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
/// A
public IFileStreamWriter GetWriter(string fileName, int maxCharsToStore, int maxXmlCharsToStore)
{
- return new ServiceBufferFileStreamWriter(new FileStreamWrapper(), fileName, maxCharsToStore, maxXmlCharsToStore);
+ return new ServiceBufferFileStreamWriter(new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite), maxCharsToStore, maxXmlCharsToStore);
}
///
@@ -51,14 +51,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
/// The file to dispose of
public void DisposeFile(string fileName)
{
- try
- {
- FileStreamWrapper.DeleteFile(fileName);
- }
- catch
- {
- // If we have problems deleting the file from a temp location, we don't really care
- }
+ FileUtils.SafeFileDelete(fileName);
}
}
}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamReader.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamReader.cs
index 8547999b..5df33596 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamReader.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamReader.cs
@@ -23,22 +23,24 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
private byte[] buffer;
- private readonly IFileStreamWrapper fileStream;
+ private readonly Stream fileStream;
- private Dictionary> readMethods;
+ private readonly Dictionary> readMethods;
#endregion
///
/// Constructs a new ServiceBufferFileStreamReader and initializes its state
///
- /// The filestream wrapper to read from
- /// The name of the file to read from
- public ServiceBufferFileStreamReader(IFileStreamWrapper fileWrapper, string fileName)
+ /// The filestream to read from
+ public ServiceBufferFileStreamReader(Stream stream)
{
// Open file for reading/writing
- fileStream = fileWrapper;
- fileStream.Init(fileName, DefaultBufferSize, FileAccess.Read);
+ if (!stream.CanRead || !stream.CanSeek)
+ {
+ throw new InvalidOperationException("Stream must be readable and seekable");
+ }
+ fileStream = stream;
// Create internal buffer
buffer = new byte[DefaultBufferSize];
@@ -372,7 +374,8 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
{
// read in length information
int lengthValue;
- int lengthLength = fileStream.ReadData(buffer, 1, offset);
+ fileStream.Seek(offset, SeekOrigin.Begin);
+ int lengthLength = fileStream.Read(buffer, 0, 1);
if (buffer[0] != 0xFF)
{
// one byte is enough
@@ -381,7 +384,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
else
{
// read in next 4 bytes
- lengthLength += fileStream.ReadData(buffer, 4);
+ lengthLength += fileStream.Read(buffer, 0, 4);
// reconstruct the length
lengthValue = BitConverter.ToInt32(buffer, 0);
@@ -433,7 +436,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
else
{
AssureBufferLength(length.ValueLength);
- fileStream.ReadData(buffer, length.ValueLength);
+ fileStream.Read(buffer, 0, length.ValueLength);
T resultObject = convertFunc(length.ValueLength);
result.RawObject = resultObject;
result.DisplayValue = toStringFunc == null ? result.RawObject.ToString() : toStringFunc(resultObject);
diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamWriter.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamWriter.cs
index 2e4360d2..bb7167e9 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamWriter.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamWriter.cs
@@ -23,7 +23,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
#region Member Variables
- private readonly IFileStreamWrapper fileStream;
+ private readonly Stream fileStream;
private readonly int maxCharsToStore;
private readonly int maxXmlCharsToStore;
@@ -45,15 +45,17 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
///
/// Constructs a new writer
///
- /// The file wrapper to use as the underlying file stream
- /// Name of the file to write to
+ /// The file wrapper to use as the underlying file stream
/// Maximum number of characters to store for long text fields
/// Maximum number of characters to store for XML fields
- public ServiceBufferFileStreamWriter(IFileStreamWrapper fileWrapper, string fileName, int maxCharsToStore, int maxXmlCharsToStore)
+ public ServiceBufferFileStreamWriter(Stream stream, int maxCharsToStore, int maxXmlCharsToStore)
{
// open file for reading/writing
- fileStream = fileWrapper;
- fileStream.Init(fileName, DefaultBufferLength, FileAccess.ReadWrite);
+ if (!stream.CanWrite || !stream.CanSeek)
+ {
+ throw new InvalidOperationException("Stream must be writable and seekable.");
+ }
+ fileStream = stream;
// create internal buffer
byteBuffer = new byte[DefaultBufferLength];
@@ -212,7 +214,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
public int WriteNull()
{
byteBuffer[0] = 0x00;
- return fileStream.WriteData(byteBuffer, 1);
+ return WriteHelper(byteBuffer, 1);
}
///
@@ -224,7 +226,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
byteBuffer[0] = 0x02; // length
shortBuffer[0] = val;
Buffer.BlockCopy(shortBuffer, 0, byteBuffer, 1, 2);
- return fileStream.WriteData(byteBuffer, 3);
+ return WriteHelper(byteBuffer, 3);
}
///
@@ -236,7 +238,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
byteBuffer[0] = 0x04; // length
intBuffer[0] = val;
Buffer.BlockCopy(intBuffer, 0, byteBuffer, 1, 4);
- return fileStream.WriteData(byteBuffer, 5);
+ return WriteHelper(byteBuffer, 5);
}
///
@@ -248,7 +250,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
byteBuffer[0] = 0x08; // length
longBuffer[0] = val;
Buffer.BlockCopy(longBuffer, 0, byteBuffer, 1, 8);
- return fileStream.WriteData(byteBuffer, 9);
+ return WriteHelper(byteBuffer, 9);
}
///
@@ -260,7 +262,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
byteBuffer[0] = 0x02; // length
charBuffer[0] = val;
Buffer.BlockCopy(charBuffer, 0, byteBuffer, 1, 2);
- return fileStream.WriteData(byteBuffer, 3);
+ return WriteHelper(byteBuffer, 3);
}
///
@@ -271,7 +273,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
{
byteBuffer[0] = 0x01; // length
byteBuffer[1] = (byte) (val ? 0x01 : 0x00);
- return fileStream.WriteData(byteBuffer, 2);
+ return WriteHelper(byteBuffer, 2);
}
///
@@ -282,7 +284,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
{
byteBuffer[0] = 0x01; // length
byteBuffer[1] = val;
- return fileStream.WriteData(byteBuffer, 2);
+ return WriteHelper(byteBuffer, 2);
}
///
@@ -294,7 +296,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
byteBuffer[0] = 0x04; // length
floatBuffer[0] = val;
Buffer.BlockCopy(floatBuffer, 0, byteBuffer, 1, 4);
- return fileStream.WriteData(byteBuffer, 5);
+ return WriteHelper(byteBuffer, 5);
}
///
@@ -306,7 +308,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
byteBuffer[0] = 0x08; // length
doubleBuffer[0] = val;
Buffer.BlockCopy(doubleBuffer, 0, byteBuffer, 1, 8);
- return fileStream.WriteData(byteBuffer, 9);
+ return WriteHelper(byteBuffer, 9);
}
///
@@ -330,7 +332,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
// data value
Buffer.BlockCopy(arrInt32, 0, byteBuffer, 3, iLen - 3);
- iTotalLen += fileStream.WriteData(byteBuffer, iLen);
+ iTotalLen += WriteHelper(byteBuffer, iLen);
return iTotalLen; // len+data
}
@@ -346,7 +348,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
int iTotalLen = WriteLength(iLen); // length
Buffer.BlockCopy(arrInt32, 0, byteBuffer, 0, iLen);
- iTotalLen += fileStream.WriteData(byteBuffer, iLen);
+ iTotalLen += WriteHelper(byteBuffer, iLen);
return iTotalLen; // len+data
}
@@ -374,7 +376,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
longBufferOffset[0] = dtoVal.Ticks;
longBufferOffset[1] = dtoVal.Offset.Ticks;
Buffer.BlockCopy(longBufferOffset, 0, byteBuffer, 1, 16);
- return fileStream.WriteData(byteBuffer, 17);
+ return WriteHelper(byteBuffer, 17);
}
///
@@ -406,7 +408,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
byteBuffer[3] = 0x00;
byteBuffer[4] = 0x00;
- iTotalLen = fileStream.WriteData(byteBuffer, 5);
+ iTotalLen = WriteHelper(byteBuffer, 5);
}
else
{
@@ -415,7 +417,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
// convert char array into byte array and write it out
iTotalLen = WriteLength(bytes.Length);
- iTotalLen += fileStream.WriteData(bytes, bytes.Length);
+ iTotalLen += WriteHelper(bytes, bytes.Length);
}
return iTotalLen; // len+data
}
@@ -438,12 +440,12 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
byteBuffer[3] = 0x00;
byteBuffer[4] = 0x00;
- iTotalLen = fileStream.WriteData(byteBuffer, 5);
+ iTotalLen = WriteHelper(byteBuffer, 5);
}
else
{
iTotalLen = WriteLength(bytesVal.Length);
- iTotalLen += fileStream.WriteData(bytesVal, bytesVal.Length);
+ iTotalLen += WriteHelper(bytesVal, bytesVal.Length);
}
return iTotalLen; // len+data
}
@@ -507,7 +509,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
int iTmp = iLen & 0x000000FF;
byteBuffer[0] = Convert.ToByte(iTmp);
- return fileStream.WriteData(byteBuffer, 1);
+ return WriteHelper(byteBuffer, 1);
}
// The length won't fit in 1 byte, so we need to use 1 byte to signify that the length
// is a full 4 bytes.
@@ -516,7 +518,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
// convert int32 into array of bytes
intBuffer[0] = iLen;
Buffer.BlockCopy(intBuffer, 0, byteBuffer, 1, 4);
- return fileStream.WriteData(byteBuffer, 5);
+ return WriteHelper(byteBuffer, 5);
}
///
@@ -532,6 +534,12 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
return val.IsNull ? WriteNull() : valueWriteFunc(val);
}
+ private int WriteHelper(byte[] buffer, int length)
+ {
+ fileStream.Write(buffer, 0, length);
+ return length;
+ }
+
#endregion
#region IDisposable Implementation
diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/FileUtils.cs b/src/Microsoft.SqlTools.ServiceLayer/Utility/FileUtils.cs
similarity index 100%
rename from src/Microsoft.SqlTools.ServiceLayer/QueryExecution/FileUtils.cs
rename to src/Microsoft.SqlTools.ServiceLayer/Utility/FileUtils.cs
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Common.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Common.cs
index c8f8c15f..c136b2ba 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Common.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Common.cs
@@ -122,64 +122,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
return fileName;
});
mock.Setup(fsf => fsf.GetReader(It.IsAny()))
- .Returns(output => new ServiceBufferFileStreamReader(new InMemoryWrapper(storage[output]), output));
+ .Returns(output => new ServiceBufferFileStreamReader(new MemoryStream(storage[output])));
mock.Setup(fsf => fsf.GetWriter(It.IsAny(), It.IsAny(), It.IsAny()))
.Returns((output, chars, xml) => new ServiceBufferFileStreamWriter(
- new InMemoryWrapper(storage[output]), output, chars, xml));
+ new MemoryStream(storage[output]), chars, xml));
return mock.Object;
}
- public class InMemoryWrapper : IFileStreamWrapper
- {
- private readonly MemoryStream memoryStream;
- private bool readingOnly;
-
- public InMemoryWrapper(byte[] storage)
- {
- memoryStream = new MemoryStream(storage);
- }
-
- public void Close()
- {
- memoryStream.Dispose();
- }
-
- public void Dispose()
- {
- // We'll dispose this via a special method
- }
-
- public void Flush()
- {
- if (readingOnly) { throw new InvalidOperationException(); }
- }
-
- public void Init(string fileName, int bufferSize, FileAccess fAccess)
- {
- readingOnly = fAccess == FileAccess.Read;
- }
-
- public int ReadData(byte[] buffer, int bytes)
- {
- return ReadData(buffer, bytes, memoryStream.Position);
- }
-
- public int ReadData(byte[] buffer, int bytes, long fileOffset)
- {
- memoryStream.Seek(fileOffset, SeekOrigin.Begin);
- return memoryStream.Read(buffer, 0, bytes);
- }
-
- public int WriteData(byte[] buffer, int bytes)
- {
- if (readingOnly) { throw new InvalidOperationException(); }
- memoryStream.Write(buffer, 0, bytes);
- memoryStream.Flush();
- return bytes;
- }
- }
-
#endregion
#region DbConnection Mocking
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/DataStorage/FileStreamWrapperTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/DataStorage/FileStreamWrapperTests.cs
deleted file mode 100644
index 1ee471fd..00000000
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/DataStorage/FileStreamWrapperTests.cs
+++ /dev/null
@@ -1,218 +0,0 @@
-//
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-//
-
-using System;
-using System.IO;
-using System.Linq;
-using System.Text;
-using Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage;
-using Xunit;
-
-namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.DataStorage
-{
- public class FileStreamWrapperTests
- {
- [Theory]
- [InlineData(null)]
- [InlineData("")]
- [InlineData(" ")]
- public void InitInvalidFilenameParameter(string fileName)
- {
- // If:
- // ... I have a file stream wrapper that is initialized with invalid fileName
- // Then:
- // ... It should throw an argument null exception
- using (FileStreamWrapper fsw = new FileStreamWrapper())
- {
- Assert.Throws(() => fsw.Init(fileName, 8192, FileAccess.Read));
- }
- }
-
- [Theory]
- [InlineData(0)]
- [InlineData(-1)]
- public void InitInvalidBufferLength(int bufferLength)
- {
- // If:
- // ... I have a file stream wrapper that is initialized with an invalid buffer length
- // Then:
- // ... I should throw an argument out of range exception
- using (FileStreamWrapper fsw = new FileStreamWrapper())
- {
- Assert.Throws(() => fsw.Init("validFileName", bufferLength, FileAccess.Read));
- }
- }
-
- [Fact]
- public void InitInvalidFileAccessMode()
- {
- // If:
- // ... I attempt to open a file stream wrapper that is initialized with an invalid file
- // access mode
- // Then:
- // ... I should get an invalid argument exception
- using (FileStreamWrapper fsw = new FileStreamWrapper())
- {
- Assert.Throws(() => fsw.Init("validFileName", 8192, FileAccess.Write));
- }
- }
-
- [Fact]
- public void InitSuccessful()
- {
- string fileName = Path.GetTempFileName();
-
- try
- {
- using (FileStreamWrapper fsw = new FileStreamWrapper())
- {
- // If:
- // ... I have a file stream wrapper that is initialized with valid parameters
- fsw.Init(fileName, 8192, FileAccess.ReadWrite);
-
- // Then:
- // ... The file should exist
- FileInfo fileInfo = new FileInfo(fileName);
- Assert.True(fileInfo.Exists);
- }
- }
- finally
- {
- // Cleanup:
- // ... Delete the file that was created
- try { File.Delete(fileName); } catch { /* Don't care */ }
- }
- }
-
- [Fact]
- public void PerformOpWithoutInit()
- {
- byte[] buf = new byte[10];
-
- using (FileStreamWrapper fsw = new FileStreamWrapper())
- {
- // If:
- // ... I have a file stream wrapper that hasn't been initialized
- // Then:
- // ... Attempting to perform any operation will result in an exception
- Assert.Throws(() => fsw.ReadData(buf, 1));
- Assert.Throws(() => fsw.ReadData(buf, 1, 0));
- Assert.Throws(() => fsw.WriteData(buf, 1));
- Assert.Throws(() => fsw.Flush());
- }
- }
-
- [Fact]
- public void PerformWriteOpOnReadOnlyWrapper()
- {
- byte[] buf = new byte[10];
-
- using (FileStreamWrapper fsw = new FileStreamWrapper())
- {
- // If:
- // ... I have a readonly file stream wrapper
- // Then:
- // ... Attempting to perform any write operation should result in an exception
- Assert.Throws(() => fsw.WriteData(buf, 1));
- Assert.Throws(() => fsw.Flush());
- }
- }
-
- [Theory]
- [InlineData(1024, 20, 10)] // Standard scenario
- [InlineData(1024, 100, 100)] // Requested more bytes than there are
- [InlineData(5, 20, 10)] // Internal buffer too small, force a move-to operation
- public void ReadData(int internalBufferLength, int outBufferLength, int requestedBytes)
- {
- // Setup:
- // ... I have a file that has a handful of bytes in it
- string fileName = Path.GetTempFileName();
- const string stringToWrite = "hello";
- CreateTestFile(fileName, stringToWrite);
- byte[] targetBytes = Encoding.Unicode.GetBytes(stringToWrite);
-
- try
- {
- // If:
- // ... I have a file stream wrapper that has been initialized to an existing file
- // ... And I read some bytes from it
- int bytesRead;
- byte[] buf = new byte[outBufferLength];
- using (FileStreamWrapper fsw = new FileStreamWrapper())
- {
- fsw.Init(fileName, internalBufferLength, FileAccess.Read);
- bytesRead = fsw.ReadData(buf, targetBytes.Length);
- }
-
- // Then:
- // ... I should get those bytes back
- Assert.Equal(targetBytes.Length, bytesRead);
- Assert.True(targetBytes.Take(targetBytes.Length).SequenceEqual(buf.Take(targetBytes.Length)));
-
- }
- finally
- {
- // Cleanup:
- // ... Delete the test file
- CleanupTestFile(fileName);
- }
- }
-
- [Theory]
- [InlineData(1024)] // Standard scenario
- [InlineData(10)] // Internal buffer too small, forces a flush
- public void WriteData(int internalBufferLength)
- {
- string fileName = Path.GetTempFileName();
- byte[] bytesToWrite = Encoding.Unicode.GetBytes("hello");
-
- try
- {
- // If:
- // ... I have a file stream that has been initialized
- // ... And I write some bytes to it
- using (FileStreamWrapper fsw = new FileStreamWrapper())
- {
- fsw.Init(fileName, internalBufferLength, FileAccess.ReadWrite);
- int bytesWritten = fsw.WriteData(bytesToWrite, bytesToWrite.Length);
-
- Assert.Equal(bytesToWrite.Length, bytesWritten);
- }
-
- // Then:
- // ... The file I wrote to should contain only the bytes I wrote out
- using (FileStream fs = File.OpenRead(fileName))
- {
- byte[] readBackBytes = new byte[1024];
- int bytesRead = fs.Read(readBackBytes, 0, readBackBytes.Length);
-
- Assert.Equal(bytesToWrite.Length, bytesRead); // If bytes read is not equal, then more or less of the original string was written to the file
- Assert.True(bytesToWrite.SequenceEqual(readBackBytes.Take(bytesRead)));
- }
- }
- finally
- {
- // Cleanup:
- // ... Delete the test file
- CleanupTestFile(fileName);
- }
- }
-
- private static void CreateTestFile(string fileName, string value)
- {
- using (FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
- {
- byte[] bytesToWrite = Encoding.Unicode.GetBytes(value);
- fs.Write(bytesToWrite, 0, bytesToWrite.Length);
- fs.Flush();
- }
- }
-
- private static void CleanupTestFile(string fileName)
- {
- try { File.Delete(fileName); } catch { /* Don't Care */}
- }
- }
-}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/DataStorage/ServiceBufferFileStreamReaderWriterTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/DataStorage/ServiceBufferFileStreamReaderWriterTests.cs
index 80ca7fbc..b454eafb 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/DataStorage/ServiceBufferFileStreamReaderWriterTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/DataStorage/ServiceBufferFileStreamReaderWriterTests.cs
@@ -6,45 +6,100 @@
using System;
using System.Collections.Generic;
using System.Data.SqlTypes;
+using System.IO;
using System.Text;
using Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage;
+using Moq;
using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.DataStorage
{
public class ReaderWriterPairTest
{
+ [Fact]
+ public void ReaderInvalidStreamCannotRead()
+ {
+ // If: I create a service buffer file stream reader with a stream that cannot be read
+ // Then: I should get an exception
+ var invalidStream = new Mock();
+ invalidStream.SetupGet(s => s.CanRead).Returns(false);
+ invalidStream.SetupGet(s => s.CanSeek).Returns(true);
+ Assert.Throws(() =>
+ {
+ ServiceBufferFileStreamReader obj = new ServiceBufferFileStreamReader(invalidStream.Object);
+ obj.Dispose();
+ });
+ }
+
+ [Fact]
+ public void ReaderInvalidStreamCannotSeek()
+ {
+ // If: I create a service buffer file stream reader with a stream that cannot seek
+ // Then: I should get an exception
+ var invalidStream = new Mock();
+ invalidStream.SetupGet(s => s.CanRead).Returns(true);
+ invalidStream.SetupGet(s => s.CanSeek).Returns(false);
+ Assert.Throws(() =>
+ {
+ ServiceBufferFileStreamReader obj = new ServiceBufferFileStreamReader(invalidStream.Object);
+ obj.Dispose();
+ });
+ }
+
+ [Fact]
+ public void WriterInvalidStreamCannotWrite()
+ {
+ // If: I create a service buffer file stream writer with a stream that cannot be read
+ // Then: I should get an exception
+ var invalidStream = new Mock();
+ invalidStream.SetupGet(s => s.CanWrite).Returns(false);
+ invalidStream.SetupGet(s => s.CanSeek).Returns(true);
+ Assert.Throws(() =>
+ {
+ ServiceBufferFileStreamWriter obj = new ServiceBufferFileStreamWriter(invalidStream.Object, 1024, 1024);
+ obj.Dispose();
+ });
+ }
+
+ [Fact]
+ public void WriterInvalidStreamCannotSeek()
+ {
+ // If: I create a service buffer file stream writer with a stream that cannot seek
+ // Then: I should get an exception
+ var invalidStream = new Mock();
+ invalidStream.SetupGet(s => s.CanWrite).Returns(true);
+ invalidStream.SetupGet(s => s.CanSeek).Returns(false);
+ Assert.Throws(() =>
+ {
+ ServiceBufferFileStreamWriter obj = new ServiceBufferFileStreamWriter(invalidStream.Object, 1024, 1024);
+ obj.Dispose();
+ });
+ }
+
private static void VerifyReadWrite(int valueLength, T value, Func writeFunc, Func readFunc)
{
- // Setup: Create a mock file stream wrapper
- Common.InMemoryWrapper mockWrapper = new Common.InMemoryWrapper(new byte[8192]);
- try
+ // Setup: Create a mock file stream
+ byte[] storage = new byte[8192];
+
+ // If:
+ // ... I write a type T to the writer
+ using (ServiceBufferFileStreamWriter writer = new ServiceBufferFileStreamWriter(new MemoryStream(storage), 10, 10))
{
- // If:
- // ... I write a type T to the writer
- using (ServiceBufferFileStreamWriter writer = new ServiceBufferFileStreamWriter(mockWrapper, "abc", 10, 10))
- {
- int writtenBytes = writeFunc(writer, value);
- Assert.Equal(valueLength, writtenBytes);
- }
-
- // ... And read the type T back
- FileStreamReadResult outValue;
- using (ServiceBufferFileStreamReader reader = new ServiceBufferFileStreamReader(mockWrapper, "abc"))
- {
- outValue = readFunc(reader);
- }
-
- // Then:
- Assert.Equal(value, outValue.Value.RawObject);
- Assert.Equal(valueLength, outValue.TotalLength);
- Assert.NotNull(outValue.Value);
+ int writtenBytes = writeFunc(writer, value);
+ Assert.Equal(valueLength, writtenBytes);
}
- finally
+
+ // ... And read the type T back
+ FileStreamReadResult outValue;
+ using (ServiceBufferFileStreamReader reader = new ServiceBufferFileStreamReader(new MemoryStream(storage)))
{
- // Cleanup: Close the wrapper
- mockWrapper.Close();
+ outValue = readFunc(reader);
}
+
+ // Then:
+ Assert.Equal(value, outValue.Value.RawObject);
+ Assert.Equal(valueLength, outValue.TotalLength);
+ Assert.NotNull(outValue.Value);
}
[Theory]
@@ -222,16 +277,17 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.DataStorage
[Fact]
public void StringNullTest()
{
- // Setup: Create a mock file stream wrapper
- Common.InMemoryWrapper mockWrapper = new Common.InMemoryWrapper(new byte[8192]);
-
- // If:
- // ... I write null as a string to the writer
- using (ServiceBufferFileStreamWriter writer = new ServiceBufferFileStreamWriter(mockWrapper, "abc", 10, 10))
+ // Setup: Create a mock file stream
+ using (MemoryStream stream = new MemoryStream(new byte[8192]))
{
- // Then:
- // ... I should get an argument null exception
- Assert.Throws(() => writer.WriteString(null));
+ // If:
+ // ... I write null as a string to the writer
+ using (ServiceBufferFileStreamWriter writer = new ServiceBufferFileStreamWriter(stream, 10, 10))
+ {
+ // Then:
+ // ... I should get an argument null exception
+ Assert.Throws(() => writer.WriteString(null));
+ }
}
}
@@ -259,15 +315,16 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.DataStorage
public void BytesNullTest()
{
// Setup: Create a mock file stream wrapper
- Common.InMemoryWrapper mockWrapper = new Common.InMemoryWrapper(new byte[8192]);
-
- // If:
- // ... I write null as a string to the writer
- using (ServiceBufferFileStreamWriter writer = new ServiceBufferFileStreamWriter(mockWrapper, "abc", 10, 10))
+ using (MemoryStream stream = new MemoryStream(new byte[8192]))
{
- // Then:
- // ... I should get an argument null exception
- Assert.Throws(() => writer.WriteBytes(null));
+ // If:
+ // ... I write null as a string to the writer
+ using (ServiceBufferFileStreamWriter writer = new ServiceBufferFileStreamWriter(stream, 10, 10))
+ {
+ // Then:
+ // ... I should get an argument null exception
+ Assert.Throws(() => writer.WriteBytes(null));
+ }
}
}