mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-16 10:58:30 -05:00
Removing the FileStreamWrapper as it is unecessary (#156)
This commit is contained in:
@@ -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
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Wrapper for a file stream, providing simplified creation, deletion, read, and write
|
|
||||||
/// functionality.
|
|
||||||
/// </summary>
|
|
||||||
public class FileStreamWrapper : IFileStreamWrapper
|
|
||||||
{
|
|
||||||
#region Member Variables
|
|
||||||
|
|
||||||
private byte[] buffer;
|
|
||||||
private int bufferDataSize;
|
|
||||||
private FileStream fileStream;
|
|
||||||
private long startOffset;
|
|
||||||
private long currentOffset;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs a new FileStreamWrapper and initializes its state.
|
|
||||||
/// </summary>
|
|
||||||
public FileStreamWrapper()
|
|
||||||
{
|
|
||||||
// Initialize the internal state
|
|
||||||
bufferDataSize = 0;
|
|
||||||
startOffset = 0;
|
|
||||||
currentOffset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region IFileStreamWrapper Implementation
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the wrapper by creating the internal buffer and opening the requested file.
|
|
||||||
/// If the file does not already exist, it will be created.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fileName">Name of the file to open/create</param>
|
|
||||||
/// <param name="bufferLength">The length of the internal buffer</param>
|
|
||||||
/// <param name="accessMethod">
|
|
||||||
/// Whether or not the wrapper will be used for reading. If <c>true</c>, any calls to a
|
|
||||||
/// method that writes will cause an InvalidOperationException
|
|
||||||
/// </param>
|
|
||||||
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*/);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reads data into a buffer from the current offset into the file
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="buf">The buffer to output the read data to</param>
|
|
||||||
/// <param name="bytes">The number of bytes to read into the buffer</param>
|
|
||||||
/// <returns>The number of bytes read</returns>
|
|
||||||
public int ReadData(byte[] buf, int bytes)
|
|
||||||
{
|
|
||||||
return ReadData(buf, bytes, currentOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reads data into a buffer from the specified offset into the file
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="buf">The buffer to output the read data to</param>
|
|
||||||
/// <param name="bytes">The number of bytes to read into the buffer</param>
|
|
||||||
/// <param name="offset">The offset into the file to start reading bytes from</param>
|
|
||||||
/// <returns>The number of bytes read</returns>
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Writes data to the underlying filestream, with buffering.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="buf">The buffer of bytes to write to the filestream</param>
|
|
||||||
/// <param name="bytes">The number of bytes to write</param>
|
|
||||||
/// <returns>The number of bytes written</returns>
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Flushes the internal buffer to the filestream
|
|
||||||
/// </summary>
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Deletes the given file (ideally, created with this wrapper) from the filesystem
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fileName">The path to the file to delete</param>
|
|
||||||
public static void DeleteFile(string fileName)
|
|
||||||
{
|
|
||||||
File.Delete(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Perform calculations to determine how many bytes to copy and what the new buffer offset
|
|
||||||
/// will be for copying.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="bytes">Number of bytes requested to copy</param>
|
|
||||||
/// <param name="bytesCopied">Number of bytes copied so far</param>
|
|
||||||
/// <param name="bufferOffset">New offset to start copying from/to</param>
|
|
||||||
/// <param name="bytesToCopy">Number of bytes to copy in this iteration</param>
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Moves the internal buffer to the specified offset into the file
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="offset">Offset into the file to move to</param>
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Interface for a wrapper around a filesystem reader/writer, mainly for unit testing purposes
|
|
||||||
/// </summary>
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -29,7 +29,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
/// <returns>A <see cref="ServiceBufferFileStreamReader"/></returns>
|
/// <returns>A <see cref="ServiceBufferFileStreamReader"/></returns>
|
||||||
public IFileStreamReader GetReader(string fileName)
|
public IFileStreamReader GetReader(string fileName)
|
||||||
{
|
{
|
||||||
return new ServiceBufferFileStreamReader(new FileStreamWrapper(), fileName);
|
return new ServiceBufferFileStreamReader(new FileStream(fileName, FileMode.Open, FileAccess.Read));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -42,7 +42,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
/// <returns>A <see cref="ServiceBufferFileStreamWriter"/></returns>
|
/// <returns>A <see cref="ServiceBufferFileStreamWriter"/></returns>
|
||||||
public IFileStreamWriter GetWriter(string fileName, int maxCharsToStore, int maxXmlCharsToStore)
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -51,14 +51,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
/// <param name="fileName">The file to dispose of</param>
|
/// <param name="fileName">The file to dispose of</param>
|
||||||
public void DisposeFile(string fileName)
|
public void DisposeFile(string fileName)
|
||||||
{
|
{
|
||||||
try
|
FileUtils.SafeFileDelete(fileName);
|
||||||
{
|
|
||||||
FileStreamWrapper.DeleteFile(fileName);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// If we have problems deleting the file from a temp location, we don't really care
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,22 +23,24 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
|
|
||||||
private byte[] buffer;
|
private byte[] buffer;
|
||||||
|
|
||||||
private readonly IFileStreamWrapper fileStream;
|
private readonly Stream fileStream;
|
||||||
|
|
||||||
private Dictionary<Type, Func<long, FileStreamReadResult>> readMethods;
|
private readonly Dictionary<Type, Func<long, FileStreamReadResult>> readMethods;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a new ServiceBufferFileStreamReader and initializes its state
|
/// Constructs a new ServiceBufferFileStreamReader and initializes its state
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="fileWrapper">The filestream wrapper to read from</param>
|
/// <param name="stream">The filestream to read from</param>
|
||||||
/// <param name="fileName">The name of the file to read from</param>
|
public ServiceBufferFileStreamReader(Stream stream)
|
||||||
public ServiceBufferFileStreamReader(IFileStreamWrapper fileWrapper, string fileName)
|
|
||||||
{
|
{
|
||||||
// Open file for reading/writing
|
// Open file for reading/writing
|
||||||
fileStream = fileWrapper;
|
if (!stream.CanRead || !stream.CanSeek)
|
||||||
fileStream.Init(fileName, DefaultBufferSize, FileAccess.Read);
|
{
|
||||||
|
throw new InvalidOperationException("Stream must be readable and seekable");
|
||||||
|
}
|
||||||
|
fileStream = stream;
|
||||||
|
|
||||||
// Create internal buffer
|
// Create internal buffer
|
||||||
buffer = new byte[DefaultBufferSize];
|
buffer = new byte[DefaultBufferSize];
|
||||||
@@ -372,7 +374,8 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
{
|
{
|
||||||
// read in length information
|
// read in length information
|
||||||
int lengthValue;
|
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)
|
if (buffer[0] != 0xFF)
|
||||||
{
|
{
|
||||||
// one byte is enough
|
// one byte is enough
|
||||||
@@ -381,7 +384,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// read in next 4 bytes
|
// read in next 4 bytes
|
||||||
lengthLength += fileStream.ReadData(buffer, 4);
|
lengthLength += fileStream.Read(buffer, 0, 4);
|
||||||
|
|
||||||
// reconstruct the length
|
// reconstruct the length
|
||||||
lengthValue = BitConverter.ToInt32(buffer, 0);
|
lengthValue = BitConverter.ToInt32(buffer, 0);
|
||||||
@@ -433,7 +436,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
AssureBufferLength(length.ValueLength);
|
AssureBufferLength(length.ValueLength);
|
||||||
fileStream.ReadData(buffer, length.ValueLength);
|
fileStream.Read(buffer, 0, length.ValueLength);
|
||||||
T resultObject = convertFunc(length.ValueLength);
|
T resultObject = convertFunc(length.ValueLength);
|
||||||
result.RawObject = resultObject;
|
result.RawObject = resultObject;
|
||||||
result.DisplayValue = toStringFunc == null ? result.RawObject.ToString() : toStringFunc(resultObject);
|
result.DisplayValue = toStringFunc == null ? result.RawObject.ToString() : toStringFunc(resultObject);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
|
|
||||||
#region Member Variables
|
#region Member Variables
|
||||||
|
|
||||||
private readonly IFileStreamWrapper fileStream;
|
private readonly Stream fileStream;
|
||||||
private readonly int maxCharsToStore;
|
private readonly int maxCharsToStore;
|
||||||
private readonly int maxXmlCharsToStore;
|
private readonly int maxXmlCharsToStore;
|
||||||
|
|
||||||
@@ -45,15 +45,17 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a new writer
|
/// Constructs a new writer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="fileWrapper">The file wrapper to use as the underlying file stream</param>
|
/// <param name="stream">The file wrapper to use as the underlying file stream</param>
|
||||||
/// <param name="fileName">Name of the file to write to</param>
|
|
||||||
/// <param name="maxCharsToStore">Maximum number of characters to store for long text fields</param>
|
/// <param name="maxCharsToStore">Maximum number of characters to store for long text fields</param>
|
||||||
/// <param name="maxXmlCharsToStore">Maximum number of characters to store for XML fields</param>
|
/// <param name="maxXmlCharsToStore">Maximum number of characters to store for XML fields</param>
|
||||||
public ServiceBufferFileStreamWriter(IFileStreamWrapper fileWrapper, string fileName, int maxCharsToStore, int maxXmlCharsToStore)
|
public ServiceBufferFileStreamWriter(Stream stream, int maxCharsToStore, int maxXmlCharsToStore)
|
||||||
{
|
{
|
||||||
// open file for reading/writing
|
// open file for reading/writing
|
||||||
fileStream = fileWrapper;
|
if (!stream.CanWrite || !stream.CanSeek)
|
||||||
fileStream.Init(fileName, DefaultBufferLength, FileAccess.ReadWrite);
|
{
|
||||||
|
throw new InvalidOperationException("Stream must be writable and seekable.");
|
||||||
|
}
|
||||||
|
fileStream = stream;
|
||||||
|
|
||||||
// create internal buffer
|
// create internal buffer
|
||||||
byteBuffer = new byte[DefaultBufferLength];
|
byteBuffer = new byte[DefaultBufferLength];
|
||||||
@@ -212,7 +214,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
public int WriteNull()
|
public int WriteNull()
|
||||||
{
|
{
|
||||||
byteBuffer[0] = 0x00;
|
byteBuffer[0] = 0x00;
|
||||||
return fileStream.WriteData(byteBuffer, 1);
|
return WriteHelper(byteBuffer, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -224,7 +226,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
byteBuffer[0] = 0x02; // length
|
byteBuffer[0] = 0x02; // length
|
||||||
shortBuffer[0] = val;
|
shortBuffer[0] = val;
|
||||||
Buffer.BlockCopy(shortBuffer, 0, byteBuffer, 1, 2);
|
Buffer.BlockCopy(shortBuffer, 0, byteBuffer, 1, 2);
|
||||||
return fileStream.WriteData(byteBuffer, 3);
|
return WriteHelper(byteBuffer, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -236,7 +238,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
byteBuffer[0] = 0x04; // length
|
byteBuffer[0] = 0x04; // length
|
||||||
intBuffer[0] = val;
|
intBuffer[0] = val;
|
||||||
Buffer.BlockCopy(intBuffer, 0, byteBuffer, 1, 4);
|
Buffer.BlockCopy(intBuffer, 0, byteBuffer, 1, 4);
|
||||||
return fileStream.WriteData(byteBuffer, 5);
|
return WriteHelper(byteBuffer, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -248,7 +250,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
byteBuffer[0] = 0x08; // length
|
byteBuffer[0] = 0x08; // length
|
||||||
longBuffer[0] = val;
|
longBuffer[0] = val;
|
||||||
Buffer.BlockCopy(longBuffer, 0, byteBuffer, 1, 8);
|
Buffer.BlockCopy(longBuffer, 0, byteBuffer, 1, 8);
|
||||||
return fileStream.WriteData(byteBuffer, 9);
|
return WriteHelper(byteBuffer, 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -260,7 +262,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
byteBuffer[0] = 0x02; // length
|
byteBuffer[0] = 0x02; // length
|
||||||
charBuffer[0] = val;
|
charBuffer[0] = val;
|
||||||
Buffer.BlockCopy(charBuffer, 0, byteBuffer, 1, 2);
|
Buffer.BlockCopy(charBuffer, 0, byteBuffer, 1, 2);
|
||||||
return fileStream.WriteData(byteBuffer, 3);
|
return WriteHelper(byteBuffer, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -271,7 +273,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
{
|
{
|
||||||
byteBuffer[0] = 0x01; // length
|
byteBuffer[0] = 0x01; // length
|
||||||
byteBuffer[1] = (byte) (val ? 0x01 : 0x00);
|
byteBuffer[1] = (byte) (val ? 0x01 : 0x00);
|
||||||
return fileStream.WriteData(byteBuffer, 2);
|
return WriteHelper(byteBuffer, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -282,7 +284,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
{
|
{
|
||||||
byteBuffer[0] = 0x01; // length
|
byteBuffer[0] = 0x01; // length
|
||||||
byteBuffer[1] = val;
|
byteBuffer[1] = val;
|
||||||
return fileStream.WriteData(byteBuffer, 2);
|
return WriteHelper(byteBuffer, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -294,7 +296,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
byteBuffer[0] = 0x04; // length
|
byteBuffer[0] = 0x04; // length
|
||||||
floatBuffer[0] = val;
|
floatBuffer[0] = val;
|
||||||
Buffer.BlockCopy(floatBuffer, 0, byteBuffer, 1, 4);
|
Buffer.BlockCopy(floatBuffer, 0, byteBuffer, 1, 4);
|
||||||
return fileStream.WriteData(byteBuffer, 5);
|
return WriteHelper(byteBuffer, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -306,7 +308,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
byteBuffer[0] = 0x08; // length
|
byteBuffer[0] = 0x08; // length
|
||||||
doubleBuffer[0] = val;
|
doubleBuffer[0] = val;
|
||||||
Buffer.BlockCopy(doubleBuffer, 0, byteBuffer, 1, 8);
|
Buffer.BlockCopy(doubleBuffer, 0, byteBuffer, 1, 8);
|
||||||
return fileStream.WriteData(byteBuffer, 9);
|
return WriteHelper(byteBuffer, 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -330,7 +332,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
|
|
||||||
// data value
|
// data value
|
||||||
Buffer.BlockCopy(arrInt32, 0, byteBuffer, 3, iLen - 3);
|
Buffer.BlockCopy(arrInt32, 0, byteBuffer, 3, iLen - 3);
|
||||||
iTotalLen += fileStream.WriteData(byteBuffer, iLen);
|
iTotalLen += WriteHelper(byteBuffer, iLen);
|
||||||
return iTotalLen; // len+data
|
return iTotalLen; // len+data
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,7 +348,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
int iTotalLen = WriteLength(iLen); // length
|
int iTotalLen = WriteLength(iLen); // length
|
||||||
|
|
||||||
Buffer.BlockCopy(arrInt32, 0, byteBuffer, 0, iLen);
|
Buffer.BlockCopy(arrInt32, 0, byteBuffer, 0, iLen);
|
||||||
iTotalLen += fileStream.WriteData(byteBuffer, iLen);
|
iTotalLen += WriteHelper(byteBuffer, iLen);
|
||||||
|
|
||||||
return iTotalLen; // len+data
|
return iTotalLen; // len+data
|
||||||
}
|
}
|
||||||
@@ -374,7 +376,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
longBufferOffset[0] = dtoVal.Ticks;
|
longBufferOffset[0] = dtoVal.Ticks;
|
||||||
longBufferOffset[1] = dtoVal.Offset.Ticks;
|
longBufferOffset[1] = dtoVal.Offset.Ticks;
|
||||||
Buffer.BlockCopy(longBufferOffset, 0, byteBuffer, 1, 16);
|
Buffer.BlockCopy(longBufferOffset, 0, byteBuffer, 1, 16);
|
||||||
return fileStream.WriteData(byteBuffer, 17);
|
return WriteHelper(byteBuffer, 17);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -406,7 +408,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
byteBuffer[3] = 0x00;
|
byteBuffer[3] = 0x00;
|
||||||
byteBuffer[4] = 0x00;
|
byteBuffer[4] = 0x00;
|
||||||
|
|
||||||
iTotalLen = fileStream.WriteData(byteBuffer, 5);
|
iTotalLen = WriteHelper(byteBuffer, 5);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -415,7 +417,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
|
|
||||||
// convert char array into byte array and write it out
|
// convert char array into byte array and write it out
|
||||||
iTotalLen = WriteLength(bytes.Length);
|
iTotalLen = WriteLength(bytes.Length);
|
||||||
iTotalLen += fileStream.WriteData(bytes, bytes.Length);
|
iTotalLen += WriteHelper(bytes, bytes.Length);
|
||||||
}
|
}
|
||||||
return iTotalLen; // len+data
|
return iTotalLen; // len+data
|
||||||
}
|
}
|
||||||
@@ -438,12 +440,12 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
byteBuffer[3] = 0x00;
|
byteBuffer[3] = 0x00;
|
||||||
byteBuffer[4] = 0x00;
|
byteBuffer[4] = 0x00;
|
||||||
|
|
||||||
iTotalLen = fileStream.WriteData(byteBuffer, 5);
|
iTotalLen = WriteHelper(byteBuffer, 5);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
iTotalLen = WriteLength(bytesVal.Length);
|
iTotalLen = WriteLength(bytesVal.Length);
|
||||||
iTotalLen += fileStream.WriteData(bytesVal, bytesVal.Length);
|
iTotalLen += WriteHelper(bytesVal, bytesVal.Length);
|
||||||
}
|
}
|
||||||
return iTotalLen; // len+data
|
return iTotalLen; // len+data
|
||||||
}
|
}
|
||||||
@@ -507,7 +509,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
int iTmp = iLen & 0x000000FF;
|
int iTmp = iLen & 0x000000FF;
|
||||||
|
|
||||||
byteBuffer[0] = Convert.ToByte(iTmp);
|
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
|
// 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.
|
// is a full 4 bytes.
|
||||||
@@ -516,7 +518,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
// convert int32 into array of bytes
|
// convert int32 into array of bytes
|
||||||
intBuffer[0] = iLen;
|
intBuffer[0] = iLen;
|
||||||
Buffer.BlockCopy(intBuffer, 0, byteBuffer, 1, 4);
|
Buffer.BlockCopy(intBuffer, 0, byteBuffer, 1, 4);
|
||||||
return fileStream.WriteData(byteBuffer, 5);
|
return WriteHelper(byteBuffer, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -532,6 +534,12 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
|
|||||||
return val.IsNull ? WriteNull() : valueWriteFunc(val);
|
return val.IsNull ? WriteNull() : valueWriteFunc(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int WriteHelper(byte[] buffer, int length)
|
||||||
|
{
|
||||||
|
fileStream.Write(buffer, 0, length);
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region IDisposable Implementation
|
#region IDisposable Implementation
|
||||||
|
|||||||
@@ -122,64 +122,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
|||||||
return fileName;
|
return fileName;
|
||||||
});
|
});
|
||||||
mock.Setup(fsf => fsf.GetReader(It.IsAny<string>()))
|
mock.Setup(fsf => fsf.GetReader(It.IsAny<string>()))
|
||||||
.Returns<string>(output => new ServiceBufferFileStreamReader(new InMemoryWrapper(storage[output]), output));
|
.Returns<string>(output => new ServiceBufferFileStreamReader(new MemoryStream(storage[output])));
|
||||||
mock.Setup(fsf => fsf.GetWriter(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
|
mock.Setup(fsf => fsf.GetWriter(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
|
||||||
.Returns<string, int, int>((output, chars, xml) => new ServiceBufferFileStreamWriter(
|
.Returns<string, int, int>((output, chars, xml) => new ServiceBufferFileStreamWriter(
|
||||||
new InMemoryWrapper(storage[output]), output, chars, xml));
|
new MemoryStream(storage[output]), chars, xml));
|
||||||
|
|
||||||
return mock.Object;
|
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
|
#endregion
|
||||||
|
|
||||||
#region DbConnection Mocking
|
#region DbConnection Mocking
|
||||||
|
|||||||
@@ -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<ArgumentException>(() => 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<ArgumentOutOfRangeException>(() => 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<ArgumentException>(() => 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<InvalidOperationException>(() => fsw.ReadData(buf, 1));
|
|
||||||
Assert.Throws<InvalidOperationException>(() => fsw.ReadData(buf, 1, 0));
|
|
||||||
Assert.Throws<InvalidOperationException>(() => fsw.WriteData(buf, 1));
|
|
||||||
Assert.Throws<InvalidOperationException>(() => 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<InvalidOperationException>(() => fsw.WriteData(buf, 1));
|
|
||||||
Assert.Throws<InvalidOperationException>(() => 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 */}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,45 +6,100 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data.SqlTypes;
|
using System.Data.SqlTypes;
|
||||||
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage;
|
using Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage;
|
||||||
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.DataStorage
|
namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.DataStorage
|
||||||
{
|
{
|
||||||
public class ReaderWriterPairTest
|
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<Stream>();
|
||||||
|
invalidStream.SetupGet(s => s.CanRead).Returns(false);
|
||||||
|
invalidStream.SetupGet(s => s.CanSeek).Returns(true);
|
||||||
|
Assert.Throws<InvalidOperationException>(() =>
|
||||||
|
{
|
||||||
|
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<Stream>();
|
||||||
|
invalidStream.SetupGet(s => s.CanRead).Returns(true);
|
||||||
|
invalidStream.SetupGet(s => s.CanSeek).Returns(false);
|
||||||
|
Assert.Throws<InvalidOperationException>(() =>
|
||||||
|
{
|
||||||
|
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<Stream>();
|
||||||
|
invalidStream.SetupGet(s => s.CanWrite).Returns(false);
|
||||||
|
invalidStream.SetupGet(s => s.CanSeek).Returns(true);
|
||||||
|
Assert.Throws<InvalidOperationException>(() =>
|
||||||
|
{
|
||||||
|
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<Stream>();
|
||||||
|
invalidStream.SetupGet(s => s.CanWrite).Returns(true);
|
||||||
|
invalidStream.SetupGet(s => s.CanSeek).Returns(false);
|
||||||
|
Assert.Throws<InvalidOperationException>(() =>
|
||||||
|
{
|
||||||
|
ServiceBufferFileStreamWriter obj = new ServiceBufferFileStreamWriter(invalidStream.Object, 1024, 1024);
|
||||||
|
obj.Dispose();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private static void VerifyReadWrite<T>(int valueLength, T value, Func<ServiceBufferFileStreamWriter, T, int> writeFunc, Func<ServiceBufferFileStreamReader, FileStreamReadResult> readFunc)
|
private static void VerifyReadWrite<T>(int valueLength, T value, Func<ServiceBufferFileStreamWriter, T, int> writeFunc, Func<ServiceBufferFileStreamReader, FileStreamReadResult> readFunc)
|
||||||
{
|
{
|
||||||
// Setup: Create a mock file stream wrapper
|
// Setup: Create a mock file stream
|
||||||
Common.InMemoryWrapper mockWrapper = new Common.InMemoryWrapper(new byte[8192]);
|
byte[] storage = new byte[8192];
|
||||||
try
|
|
||||||
|
// If:
|
||||||
|
// ... I write a type T to the writer
|
||||||
|
using (ServiceBufferFileStreamWriter writer = new ServiceBufferFileStreamWriter(new MemoryStream(storage), 10, 10))
|
||||||
{
|
{
|
||||||
// If:
|
int writtenBytes = writeFunc(writer, value);
|
||||||
// ... I write a type T to the writer
|
Assert.Equal(valueLength, writtenBytes);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
|
// ... And read the type T back
|
||||||
|
FileStreamReadResult outValue;
|
||||||
|
using (ServiceBufferFileStreamReader reader = new ServiceBufferFileStreamReader(new MemoryStream(storage)))
|
||||||
{
|
{
|
||||||
// Cleanup: Close the wrapper
|
outValue = readFunc(reader);
|
||||||
mockWrapper.Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Then:
|
||||||
|
Assert.Equal(value, outValue.Value.RawObject);
|
||||||
|
Assert.Equal(valueLength, outValue.TotalLength);
|
||||||
|
Assert.NotNull(outValue.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -222,16 +277,17 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.DataStorage
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void StringNullTest()
|
public void StringNullTest()
|
||||||
{
|
{
|
||||||
// Setup: Create a mock file stream wrapper
|
// Setup: Create a mock file stream
|
||||||
Common.InMemoryWrapper mockWrapper = new Common.InMemoryWrapper(new byte[8192]);
|
using (MemoryStream stream = new MemoryStream(new byte[8192]))
|
||||||
|
|
||||||
// If:
|
|
||||||
// ... I write null as a string to the writer
|
|
||||||
using (ServiceBufferFileStreamWriter writer = new ServiceBufferFileStreamWriter(mockWrapper, "abc", 10, 10))
|
|
||||||
{
|
{
|
||||||
// Then:
|
// If:
|
||||||
// ... I should get an argument null exception
|
// ... I write null as a string to the writer
|
||||||
Assert.Throws<ArgumentNullException>(() => writer.WriteString(null));
|
using (ServiceBufferFileStreamWriter writer = new ServiceBufferFileStreamWriter(stream, 10, 10))
|
||||||
|
{
|
||||||
|
// Then:
|
||||||
|
// ... I should get an argument null exception
|
||||||
|
Assert.Throws<ArgumentNullException>(() => writer.WriteString(null));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,15 +315,16 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.DataStorage
|
|||||||
public void BytesNullTest()
|
public void BytesNullTest()
|
||||||
{
|
{
|
||||||
// Setup: Create a mock file stream wrapper
|
// Setup: Create a mock file stream wrapper
|
||||||
Common.InMemoryWrapper mockWrapper = new Common.InMemoryWrapper(new byte[8192]);
|
using (MemoryStream stream = new MemoryStream(new byte[8192]))
|
||||||
|
|
||||||
// If:
|
|
||||||
// ... I write null as a string to the writer
|
|
||||||
using (ServiceBufferFileStreamWriter writer = new ServiceBufferFileStreamWriter(mockWrapper, "abc", 10, 10))
|
|
||||||
{
|
{
|
||||||
// Then:
|
// If:
|
||||||
// ... I should get an argument null exception
|
// ... I write null as a string to the writer
|
||||||
Assert.Throws<ArgumentNullException>(() => writer.WriteBytes(null));
|
using (ServiceBufferFileStreamWriter writer = new ServiceBufferFileStreamWriter(stream, 10, 10))
|
||||||
|
{
|
||||||
|
// Then:
|
||||||
|
// ... I should get an argument null exception
|
||||||
|
Assert.Throws<ArgumentNullException>(() => writer.WriteBytes(null));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user