mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-14 01:25:40 -05:00
623 lines
24 KiB
C#
623 lines
24 KiB
C#
//
|
|
// Copyright (c) Microsoft. All rights reserved.
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
//
|
|
|
|
#nullable disable
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data.SqlTypes;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
|
|
using Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage;
|
|
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
|
using Microsoft.SqlTools.ServiceLayer.UnitTests.Utility;
|
|
using Moq;
|
|
using NUnit.Framework;
|
|
|
|
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage
|
|
{
|
|
public partial class ServiceBufferReaderWriterTests
|
|
{
|
|
[Test]
|
|
public void ReaderStreamNull()
|
|
{
|
|
// If: I create a service buffer file stream reader with a null stream
|
|
// Then: It should throw an exception
|
|
Assert.Throws<ArgumentNullException>(() => new ServiceBufferFileStreamReader(null, new QueryExecutionSettings()));
|
|
}
|
|
|
|
[Test]
|
|
public void ReaderSettingsNull()
|
|
{
|
|
// If: I create a service buffer file stream reader with null settings
|
|
// Then: It should throw an exception
|
|
Assert.Throws<ArgumentNullException>(() => new ServiceBufferFileStreamReader(Stream.Null, null));
|
|
}
|
|
|
|
[Test]
|
|
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>(() =>
|
|
{
|
|
var obj = new ServiceBufferFileStreamReader(invalidStream.Object, new QueryExecutionSettings());
|
|
obj.Dispose();
|
|
});
|
|
}
|
|
|
|
[Test]
|
|
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>(() =>
|
|
{
|
|
var obj = new ServiceBufferFileStreamReader(invalidStream.Object, new QueryExecutionSettings());
|
|
obj.Dispose();
|
|
});
|
|
}
|
|
|
|
[Test]
|
|
public void WriterStreamNull()
|
|
{
|
|
// If: I create a service buffer file stream writer with a null stream
|
|
// Then: It should throw an exception
|
|
Assert.Throws<ArgumentNullException>(() => new ServiceBufferFileStreamWriter(null, new QueryExecutionSettings()));
|
|
}
|
|
|
|
[Test]
|
|
public void WriterSettingsNull()
|
|
{
|
|
// If: I create a service buffer file stream writer with null settings
|
|
// Then: It should throw an exception
|
|
Assert.Throws<ArgumentNullException>(() => new ServiceBufferFileStreamWriter(Stream.Null, null));
|
|
}
|
|
|
|
[Test]
|
|
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>(() =>
|
|
{
|
|
var obj = new ServiceBufferFileStreamWriter(invalidStream.Object, new QueryExecutionSettings());
|
|
obj.Dispose();
|
|
});
|
|
}
|
|
|
|
[Test]
|
|
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>(() =>
|
|
{
|
|
var obj = new ServiceBufferFileStreamWriter(invalidStream.Object, new QueryExecutionSettings());
|
|
obj.Dispose();
|
|
});
|
|
}
|
|
|
|
[SuppressMessage("ReSharper", "UnusedParameter.Local")]
|
|
private static string VerifyReadWrite<T>(int valueLength, T value,
|
|
Func<ServiceBufferFileStreamWriter, T, int> writeFunc,
|
|
Func<ServiceBufferFileStreamReader, long, FileStreamReadResult> readFunc,
|
|
QueryExecutionSettings overrideSettings = null)
|
|
{
|
|
// Setup: Create a mock file stream
|
|
byte[] storage = new byte[8192];
|
|
overrideSettings = overrideSettings ?? new QueryExecutionSettings();
|
|
const long rowId = 100;
|
|
|
|
// If:
|
|
// ... I write a type T to the writer
|
|
using (var writer = new ServiceBufferFileStreamWriter(new MemoryStream(storage), overrideSettings))
|
|
{
|
|
int writtenBytes = writeFunc(writer, value);
|
|
Assert.AreEqual(valueLength, writtenBytes);
|
|
}
|
|
|
|
// ... And read the type T back
|
|
FileStreamReadResult outValue;
|
|
using (var reader = new ServiceBufferFileStreamReader(new MemoryStream(storage), overrideSettings))
|
|
{
|
|
outValue = readFunc(reader, rowId);
|
|
}
|
|
|
|
// Then:
|
|
Assert.AreEqual(value, outValue.Value.RawObject);
|
|
Assert.AreEqual(valueLength, outValue.TotalLength);
|
|
Assert.NotNull(outValue.Value);
|
|
|
|
// ... The id we set should be stored in the returned db cell value
|
|
Assert.AreEqual(rowId, outValue.Value.RowId);
|
|
|
|
return outValue.Value.DisplayValue;
|
|
}
|
|
|
|
[Test]
|
|
|
|
|
|
|
|
|
|
|
|
public void Int16([Values(
|
|
0,
|
|
10,
|
|
-10,
|
|
short.MaxValue, // Two byte number
|
|
short.MinValue // Negative two byte number
|
|
)] short value)
|
|
{
|
|
VerifyReadWrite(sizeof(short) + 1, value, (writer, val) => writer.WriteInt16(val), (reader, rowId) => reader.ReadInt16(0, rowId));
|
|
}
|
|
|
|
[Test]
|
|
public void Int32([Values(
|
|
0,
|
|
10,
|
|
-10,
|
|
short.MaxValue, // Two byte number
|
|
short.MinValue, // Negative two byte number
|
|
int.MaxValue, // Four byte number
|
|
int.MinValue // Negative four byte number
|
|
)] int value)
|
|
{
|
|
VerifyReadWrite(sizeof(int) + 1, value, (writer, val) => writer.WriteInt32(val), (reader, rowId) => reader.ReadInt32(0, rowId));
|
|
}
|
|
|
|
[Test]
|
|
public void Int64([Values(
|
|
0,
|
|
10,
|
|
-10,
|
|
short.MaxValue, // Two byte number
|
|
short.MinValue, // Negative two byte number
|
|
int.MaxValue, // Four byte number
|
|
int.MinValue, // Negative four byte number
|
|
long.MaxValue, // Eight byte number
|
|
long.MinValue // Negative eight byte number
|
|
)] long value)
|
|
{
|
|
VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteInt64(val), (reader, rowId) => reader.ReadInt64(0, rowId));
|
|
}
|
|
|
|
[Test]
|
|
public void Byte([Values(0,10)] byte value)
|
|
{
|
|
VerifyReadWrite(sizeof(byte) + 1, value, (writer, val) => writer.WriteByte(val), (reader, rowId) => reader.ReadByte(0, rowId));
|
|
}
|
|
|
|
[Test]
|
|
public void Char([Values('a',
|
|
'1',
|
|
(char)0x9152)] // Test something in the UTF-16 space
|
|
char value)
|
|
{
|
|
VerifyReadWrite(sizeof(char) + 1, value, (writer, val) => writer.WriteChar(val), (reader, rowId) => reader.ReadChar(0, rowId));
|
|
}
|
|
|
|
[Test]
|
|
public void Boolean([Values] bool value, [Values] bool preferNumeric)
|
|
{
|
|
string displayValue = VerifyReadWrite(sizeof(bool) + 1, value,
|
|
(writer, val) => writer.WriteBoolean(val),
|
|
(reader, rowId) => reader.ReadBoolean(0, rowId),
|
|
new QueryExecutionSettings {DisplayBitAsNumber = preferNumeric}
|
|
);
|
|
|
|
// Validate the display value
|
|
if (preferNumeric)
|
|
{
|
|
int output;
|
|
Assert.True(int.TryParse(displayValue, out output));
|
|
}
|
|
else
|
|
{
|
|
bool output;
|
|
Assert.True(bool.TryParse(displayValue, out output));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void Single([Values(
|
|
0,
|
|
10.1F,
|
|
-10.1F,
|
|
float.MinValue,
|
|
float.MaxValue,
|
|
float.PositiveInfinity,
|
|
float.NegativeInfinity
|
|
)] float value)
|
|
{
|
|
VerifyReadWrite(sizeof(float) + 1, value, (writer, val) => writer.WriteSingle(val), (reader, rowId) => reader.ReadSingle(0, rowId));
|
|
}
|
|
|
|
[Test]
|
|
public void Double([Values(
|
|
0,
|
|
10.1,
|
|
-10.1,
|
|
float.MinValue,
|
|
float.MaxValue,
|
|
float.PositiveInfinity,
|
|
float.NegativeInfinity,
|
|
double.PositiveInfinity,
|
|
double.NegativeInfinity,
|
|
double.MinValue,
|
|
double.MaxValue
|
|
)]double value)
|
|
{
|
|
VerifyReadWrite(sizeof(double) + 1, value, (writer, val) => writer.WriteDouble(val), (reader, rowId) => reader.ReadDouble(0, rowId));
|
|
}
|
|
|
|
[Test]
|
|
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, rowId) => reader.ReadSqlDecimal(0, rowId));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
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, rowId) => reader.ReadDecimal(0, rowId));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void DateTest()
|
|
{
|
|
// 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
|
|
};
|
|
|
|
// Setup: Create a DATE column
|
|
var col = new DbColumnWrapper(new TestDbColumn {DataTypeName = "DaTe"});
|
|
|
|
foreach (DateTime value in testValues)
|
|
{
|
|
string displayValue = VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteDateTime(val),
|
|
(reader, rowId) => reader.ReadDateTime(0, rowId, col));
|
|
|
|
// Make sure the display value does not have a time string
|
|
Assert.True(GetDateRegex().IsMatch(displayValue));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
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
|
|
};
|
|
|
|
// Setup: Create a DATETIME column
|
|
var col = new DbColumnWrapper(new TestDbColumn {DataTypeName = "DaTeTiMe"});
|
|
|
|
foreach (DateTime value in testValues)
|
|
{
|
|
string displayValue = VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteDateTime(val),
|
|
(reader, rowId) => reader.ReadDateTime(0, rowId, col));
|
|
|
|
// Make sure the display value has a time string with 3 milliseconds
|
|
Assert.True(GetDateTimeRegex().IsMatch(displayValue));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void DateTime2Test([Values(1,2,3,4,5,6,7)] int precision)
|
|
{
|
|
// 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
|
|
};
|
|
|
|
// Setup: Create a DATETIME column
|
|
var col = new DbColumnWrapper(new TestDbColumn
|
|
{
|
|
DataTypeName = "DaTeTiMe2",
|
|
NumericScale = precision
|
|
});
|
|
|
|
foreach (DateTime value in testValues)
|
|
{
|
|
string displayValue = VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteDateTime(val),
|
|
(reader, rowId) => reader.ReadDateTime(0, rowId, col));
|
|
|
|
// Make sure the display value has a time string with variable number of milliseconds
|
|
Assert.True(GetTimeRegex().IsMatch(displayValue));
|
|
if (precision > 0)
|
|
{
|
|
Assert.True(Regex.IsMatch(displayValue, $@"\.[\d]{{{precision}}}$"));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void DateTime2ZeroScaleTest()
|
|
{
|
|
// 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
|
|
};
|
|
|
|
// Setup: Create a DATETIME2 column
|
|
var col = new DbColumnWrapper(new TestDbColumn {DataTypeName = "DaTeTiMe2", NumericScale = 0});
|
|
|
|
foreach (DateTime value in testValues)
|
|
{
|
|
string displayValue = VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteDateTime(val),
|
|
(reader, rowId) => reader.ReadDateTime(0, rowId, col));
|
|
|
|
// Make sure the display value has a time string with 0 milliseconds
|
|
Assert.True(GetTimeRegex().IsMatch(displayValue));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void DateTime2InvalidScaleTest()
|
|
{
|
|
// 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
|
|
};
|
|
|
|
// Setup: Create a DATETIME2 column
|
|
var col = new DbColumnWrapper(new TestDbColumn {DataTypeName = "DaTeTiMe2", NumericScale = 255});
|
|
|
|
foreach (DateTime value in testValues)
|
|
{
|
|
string displayValue = VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteDateTime(val),
|
|
(reader, rowId) => reader.ReadDateTime(0, rowId, col));
|
|
|
|
// Make sure the display value has a time string with 7 milliseconds
|
|
Assert.True(GetDateTime2Regex().IsMatch(displayValue));
|
|
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
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
|
|
};
|
|
|
|
// Setup: Create a DATETIMEOFFSET column
|
|
var col = new DbColumnWrapper(new TestDbColumn { DataTypeName = "datetimeoffset", NumericScale = 6 });
|
|
|
|
foreach (DateTimeOffset value in testValues)
|
|
{
|
|
string displayValue = VerifyReadWrite(sizeof(long)*2 + 1, value, (writer, val) => writer.WriteDateTimeOffset(val),
|
|
(reader, rowId) => reader.ReadDateTimeOffset(0, rowId, col));
|
|
|
|
// Make sure the display value has a time string with 6 milliseconds and a time zone
|
|
Assert.True(GetDateTimeOffset6Regex().IsMatch(displayValue));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void DateTimeOffsetZeroScaleTest()
|
|
{
|
|
// Setup: Create some test values
|
|
DateTimeOffset[] testValues =
|
|
{
|
|
DateTimeOffset.Now, DateTimeOffset.UtcNow, DateTimeOffset.MinValue, DateTimeOffset.MaxValue
|
|
};
|
|
|
|
// Setup: Create a DATETIMEOFFSET column
|
|
var col = new DbColumnWrapper(new TestDbColumn { DataTypeName = "datetimeoffset", NumericScale = 0 });
|
|
|
|
foreach (DateTimeOffset value in testValues)
|
|
{
|
|
string displayValue = VerifyReadWrite(sizeof(long) * 2 + 1, value, (writer, val) => writer.WriteDateTimeOffset(val),
|
|
(reader, rowId) => reader.ReadDateTimeOffset(0, rowId, col));
|
|
|
|
// Make sure the display value has a time string with no millisecond and a time zone
|
|
Assert.True(GetDateTimeOffset0Regex().IsMatch(displayValue));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
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, rowId) => reader.ReadTimeSpan(0, rowId));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void StringNullTest()
|
|
{
|
|
// Setup: Create a mock file stream
|
|
using (var stream = new MemoryStream(new byte[8192]))
|
|
{
|
|
// If:
|
|
// ... I write null as a string to the writer
|
|
using (var writer = new ServiceBufferFileStreamWriter(stream, new QueryExecutionSettings()))
|
|
{
|
|
// Then:
|
|
// ... I should get an argument null exception
|
|
Assert.Throws<ArgumentNullException>(() => writer.WriteString(null));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Test, Sequential]
|
|
public void StringTest([Values(0,1,1,100,512)] int length,
|
|
[Values(null,
|
|
new[] { 'j' },
|
|
new[] { (char)0x9152 },
|
|
new[] { 'j', (char)0x9152 }, // Test alternating utf-16/ascii characters
|
|
new[] { 'j', (char)0x9152 })] // Test that requires a 4 byte length
|
|
char[] values)
|
|
{
|
|
// Setup:
|
|
// ... Generate the test value
|
|
var 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, rowId) => reader.ReadString(0, rowId));
|
|
}
|
|
|
|
[Test]
|
|
public void BytesNullTest()
|
|
{
|
|
// Setup: Create a mock file stream wrapper
|
|
using (var stream = new MemoryStream(new byte[8192]))
|
|
{
|
|
// If:
|
|
// ... I write null as a string to the writer
|
|
using (var writer = new ServiceBufferFileStreamWriter(stream, new QueryExecutionSettings()))
|
|
{
|
|
// Then:
|
|
// ... I should get an argument null exception
|
|
Assert.Throws<ArgumentNullException>(() => writer.WriteBytes(null));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Test, Sequential]
|
|
public void Bytes([Values(0, 1, 1, 100, 512)] int length,
|
|
[Values(new byte[] { 0x00 }, // Test of empty byte[]
|
|
new byte[] { 0x00 },
|
|
new byte[] { 0xFF },
|
|
new byte[] { 0x10, 0xFF, 0x00 },
|
|
new byte[] { 0x10, 0xFF, 0x00 } // Test that requires a 4 byte length
|
|
)]
|
|
byte[] values)
|
|
{
|
|
// Setup:
|
|
// ... Generate the test value
|
|
var 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, rowId) => reader.ReadBytes(0, rowId));
|
|
}
|
|
|
|
private static IEnumerable<Guid> GuidTestParameters
|
|
{
|
|
get
|
|
{
|
|
yield return Guid.Empty;
|
|
yield return Guid.NewGuid();
|
|
yield return Guid.NewGuid();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void GuidTest()
|
|
{
|
|
foreach (var testValue in GuidTestParameters)
|
|
{
|
|
VerifyReadWrite(testValue.ToByteArray().Length + 1, testValue,
|
|
(writer, val) => writer.WriteGuid(testValue),
|
|
(reader, rowId) => reader.ReadGuid(0, rowId));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
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, rowId) => reader.ReadMoney(0, rowId));
|
|
}
|
|
}
|
|
|
|
[GeneratedRegex("^[\\d]{4}-[\\d]{2}-[\\d]{2}$")]
|
|
private static partial Regex GetDateRegex();
|
|
|
|
[GeneratedRegex("^[\\d]{4}-[\\d]{2}-[\\d]{2} [\\d]{2}:[\\d]{2}:[\\d]{2}")]
|
|
private static partial Regex GetTimeRegex();
|
|
|
|
[GeneratedRegex("^[\\d]{4}-[\\d]{2}-[\\d]{2} [\\d]{2}:[\\d]{2}:[\\d]{2}\\.[\\d]{3}$")]
|
|
private static partial Regex GetDateTimeRegex();
|
|
|
|
[GeneratedRegex("^[\\d]{4}-[\\d]{2}-[\\d]{2} [\\d]{2}:[\\d]{2}:[\\d]{2}\\.[\\d]{7}$")]
|
|
private static partial Regex GetDateTime2Regex();
|
|
|
|
[GeneratedRegex("^[\\d]{4}-[\\d]{2}-[\\d]{2} [\\d]{2}:[\\d]{2}:[\\d]{2}\\.[\\d]{6} [+-][01][\\d]:[\\d]{2}$")]
|
|
private static partial Regex GetDateTimeOffset6Regex();
|
|
[GeneratedRegex("^[\\d]{4}-[\\d]{2}-[\\d]{2} [\\d]{2}:[\\d]{2}:[\\d]{2} [+-][01][\\d]:[\\d]{2}$")]
|
|
private static partial Regex GetDateTimeOffset0Regex();
|
|
}
|
|
} |