mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-14 01:25:40 -05:00
This is a fairly large set of changes to the unit tests that help isolate the effectiveness of the unit tests. * Unit tests for query execution have been split into separate files for different classes. * Unit tests have been added for the ResultSet class which previously did not have tests * The InMemoryStreamWrapper has been improved to share memory, creating a simulated filesystem * Creating a mock ConnectionService to decrease noisy exceptions and prevent "row stealing". Unfortunately this lowers code coverage. However, since the tests that touched the connection service were not really testing it, this helps keep us honest. But it will require adding more unit tests for connection service. * Standardizing the await mechanism for query execution * Cleaning up the mechanism for getting WorkspaceService mocks and mock FileStreamFactories * Refactor the query execution tests into their own files * Removing tests from ExecuteTests.cs that were moved to separate files * Adding tests for ResultSet class * Adding test for the FOR XML/JSON component of the resultset class * Setting up shared storage between file stream readers/writers * Standardizing on Workspace mocking, awaiting execution completion * Adding comment for ResultSet class
327 lines
13 KiB
C#
327 lines
13 KiB
C#
//
|
|
// 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.Collections.Generic;
|
|
using System.Data.SqlTypes;
|
|
using System.Text;
|
|
using Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage;
|
|
using Xunit;
|
|
|
|
namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.DataStorage
|
|
{
|
|
public class ReaderWriterPairTest
|
|
{
|
|
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
|
|
Common.InMemoryWrapper mockWrapper = new Common.InMemoryWrapper(new byte[8192]);
|
|
try
|
|
{
|
|
// 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);
|
|
}
|
|
finally
|
|
{
|
|
// Cleanup: Close the wrapper
|
|
mockWrapper.Close();
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0)]
|
|
[InlineData(10)]
|
|
[InlineData(-10)]
|
|
[InlineData(short.MaxValue)] // Two byte number
|
|
[InlineData(short.MinValue)] // Negative two byte number
|
|
public void Int16(short value)
|
|
{
|
|
VerifyReadWrite(sizeof(short) + 1, value, (writer, val) => writer.WriteInt16(val), reader => reader.ReadInt16(0));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0)]
|
|
[InlineData(10)]
|
|
[InlineData(-10)]
|
|
[InlineData(short.MaxValue)] // Two byte number
|
|
[InlineData(short.MinValue)] // Negative two byte number
|
|
[InlineData(int.MaxValue)] // Four byte number
|
|
[InlineData(int.MinValue)] // Negative four byte number
|
|
public void Int32(int value)
|
|
{
|
|
VerifyReadWrite(sizeof(int) + 1, value, (writer, val) => writer.WriteInt32(val), reader => reader.ReadInt32(0));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0)]
|
|
[InlineData(10)]
|
|
[InlineData(-10)]
|
|
[InlineData(short.MaxValue)] // Two byte number
|
|
[InlineData(short.MinValue)] // Negative two byte number
|
|
[InlineData(int.MaxValue)] // Four byte number
|
|
[InlineData(int.MinValue)] // Negative four byte number
|
|
[InlineData(long.MaxValue)] // Eight byte number
|
|
[InlineData(long.MinValue)] // Negative eight byte number
|
|
public void Int64(long value)
|
|
{
|
|
VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteInt64(val), reader => reader.ReadInt64(0));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0)]
|
|
[InlineData(10)]
|
|
public void Byte(byte value)
|
|
{
|
|
VerifyReadWrite(sizeof(byte) + 1, value, (writer, val) => writer.WriteByte(val), reader => reader.ReadByte(0));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData('a')]
|
|
[InlineData('1')]
|
|
[InlineData((char)0x9152)] // Test something in the UTF-16 space
|
|
public void Char(char value)
|
|
{
|
|
VerifyReadWrite(sizeof(char) + 1, value, (writer, val) => writer.WriteChar(val), reader => reader.ReadChar(0));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(true)]
|
|
[InlineData(false)]
|
|
public void Boolean(bool value)
|
|
{
|
|
VerifyReadWrite(sizeof(bool) + 1, value, (writer, val) => writer.WriteBoolean(val), reader => reader.ReadBoolean(0));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0)]
|
|
[InlineData(10.1)]
|
|
[InlineData(-10.1)]
|
|
[InlineData(float.MinValue)]
|
|
[InlineData(float.MaxValue)]
|
|
[InlineData(float.PositiveInfinity)]
|
|
[InlineData(float.NegativeInfinity)]
|
|
public void Single(float value)
|
|
{
|
|
VerifyReadWrite(sizeof(float) + 1, value, (writer, val) => writer.WriteSingle(val), reader => reader.ReadSingle(0));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0)]
|
|
[InlineData(10.1)]
|
|
[InlineData(-10.1)]
|
|
[InlineData(float.MinValue)]
|
|
[InlineData(float.MaxValue)]
|
|
[InlineData(float.PositiveInfinity)]
|
|
[InlineData(float.NegativeInfinity)]
|
|
[InlineData(double.PositiveInfinity)]
|
|
[InlineData(double.NegativeInfinity)]
|
|
[InlineData(double.MinValue)]
|
|
[InlineData(double.MaxValue)]
|
|
public void Double(double value)
|
|
{
|
|
VerifyReadWrite(sizeof(double) + 1, value, (writer, val) => writer.WriteDouble(val), reader => reader.ReadDouble(0));
|
|
}
|
|
|
|
[Fact]
|
|
public void SqlDecimalTest()
|
|
{
|
|
// Setup: Create some test values
|
|
// NOTE: We are doing these here instead of InlineData because SqlDecimal values can't be written as constant expressions
|
|
SqlDecimal[] testValues =
|
|
{
|
|
SqlDecimal.MaxValue, SqlDecimal.MinValue, new SqlDecimal(0x01, 0x01, true, 0, 0, 0, 0)
|
|
};
|
|
foreach (SqlDecimal value in testValues)
|
|
{
|
|
int valueLength = 4 + value.BinData.Length;
|
|
VerifyReadWrite(valueLength, value, (writer, val) => writer.WriteSqlDecimal(val), reader => reader.ReadSqlDecimal(0));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Decimal()
|
|
{
|
|
// Setup: Create some test values
|
|
// NOTE: We are doing these here instead of InlineData because Decimal values can't be written as constant expressions
|
|
decimal[] testValues =
|
|
{
|
|
decimal.Zero, decimal.One, decimal.MinusOne, decimal.MinValue, decimal.MaxValue
|
|
};
|
|
|
|
foreach (decimal value in testValues)
|
|
{
|
|
int valueLength = decimal.GetBits(value).Length*4 + 1;
|
|
VerifyReadWrite(valueLength, value, (writer, val) => writer.WriteDecimal(val), reader => reader.ReadDecimal(0));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void DateTimeTest()
|
|
{
|
|
// Setup: Create some test values
|
|
// NOTE: We are doing these here instead of InlineData because DateTime values can't be written as constant expressions
|
|
DateTime[] testValues =
|
|
{
|
|
DateTime.Now, DateTime.UtcNow, DateTime.MinValue, DateTime.MaxValue
|
|
};
|
|
foreach (DateTime value in testValues)
|
|
{
|
|
VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteDateTime(val), reader => reader.ReadDateTime(0));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void DateTimeOffsetTest()
|
|
{
|
|
// Setup: Create some test values
|
|
// NOTE: We are doing these here instead of InlineData because DateTimeOffset values can't be written as constant expressions
|
|
DateTimeOffset[] testValues =
|
|
{
|
|
DateTimeOffset.Now, DateTimeOffset.UtcNow, DateTimeOffset.MinValue, DateTimeOffset.MaxValue
|
|
};
|
|
foreach (DateTimeOffset value in testValues)
|
|
{
|
|
VerifyReadWrite(sizeof(long)*2 + 1, value, (writer, val) => writer.WriteDateTimeOffset(val), reader => reader.ReadDateTimeOffset(0));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void TimeSpanTest()
|
|
{
|
|
// Setup: Create some test values
|
|
// NOTE: We are doing these here instead of InlineData because TimeSpan values can't be written as constant expressions
|
|
TimeSpan[] testValues =
|
|
{
|
|
TimeSpan.Zero, TimeSpan.MinValue, TimeSpan.MaxValue, TimeSpan.FromMinutes(60)
|
|
};
|
|
foreach (TimeSpan value in testValues)
|
|
{
|
|
VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteTimeSpan(val), reader => reader.ReadTimeSpan(0));
|
|
}
|
|
}
|
|
|
|
[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))
|
|
{
|
|
// Then:
|
|
// ... I should get an argument null exception
|
|
Assert.Throws<ArgumentNullException>(() => writer.WriteString(null));
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0, null)] // Test of empty string
|
|
[InlineData(1, new[] { 'j' })]
|
|
[InlineData(1, new[] { (char)0x9152 })]
|
|
[InlineData(100, new[] { 'j', (char)0x9152 })] // Test alternating utf-16/ascii characters
|
|
[InlineData(512, new[] { 'j', (char)0x9152 })] // Test that requires a 4 byte length
|
|
public void StringTest(int length, char[] values)
|
|
{
|
|
// Setup:
|
|
// ... Generate the test value
|
|
StringBuilder sb = new StringBuilder();
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
sb.Append(values[i%values.Length]);
|
|
}
|
|
string value = sb.ToString();
|
|
int lengthLength = length == 0 || length > 255 ? 5 : 1;
|
|
VerifyReadWrite(sizeof(char)*length + lengthLength, value, (writer, val) => writer.WriteString(value), reader => reader.ReadString(0));
|
|
}
|
|
|
|
[Fact]
|
|
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))
|
|
{
|
|
// Then:
|
|
// ... I should get an argument null exception
|
|
Assert.Throws<ArgumentNullException>(() => writer.WriteBytes(null));
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0, new byte[] { 0x00 })] // Test of empty byte[]
|
|
[InlineData(1, new byte[] { 0x00 })]
|
|
[InlineData(1, new byte[] { 0xFF })]
|
|
[InlineData(100, new byte[] { 0x10, 0xFF, 0x00 })]
|
|
[InlineData(512, new byte[] { 0x10, 0xFF, 0x00 })] // Test that requires a 4 byte length
|
|
public void Bytes(int length, byte[] values)
|
|
{
|
|
// Setup:
|
|
// ... Generate the test value
|
|
List<byte> sb = new List<byte>();
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
sb.Add(values[i % values.Length]);
|
|
}
|
|
byte[] value = sb.ToArray();
|
|
int lengthLength = length == 0 || length > 255 ? 5 : 1;
|
|
int valueLength = sizeof(byte)*length + lengthLength;
|
|
VerifyReadWrite(valueLength, value, (writer, val) => writer.WriteBytes(value), reader => reader.ReadBytes(0));
|
|
}
|
|
|
|
[Fact]
|
|
public void GuidTest()
|
|
{
|
|
// Setup:
|
|
// ... Create some test values
|
|
// NOTE: We are doing these here instead of InlineData because Guid type can't be written as constant expressions
|
|
Guid[] guids =
|
|
{
|
|
Guid.Empty, Guid.NewGuid(), Guid.NewGuid()
|
|
};
|
|
foreach (Guid guid in guids)
|
|
{
|
|
VerifyReadWrite(guid.ToByteArray().Length + 1, new SqlGuid(guid), (writer, val) => writer.WriteGuid(guid), reader => reader.ReadGuid(0));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void MoneyTest()
|
|
{
|
|
// Setup: Create some test values
|
|
// NOTE: We are doing these here instead of InlineData because SqlMoney can't be written as a constant expression
|
|
SqlMoney[] monies =
|
|
{
|
|
SqlMoney.Zero, SqlMoney.MinValue, SqlMoney.MaxValue, new SqlMoney(1.02)
|
|
};
|
|
foreach (SqlMoney money in monies)
|
|
{
|
|
VerifyReadWrite(sizeof(decimal) + 1, money, (writer, val) => writer.WriteMoney(money), reader => reader.ReadMoney(0));
|
|
}
|
|
}
|
|
}
|
|
}
|