Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix | SqlBuffer.SqlGuid #2310

Merged
merged 3 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,9 @@ healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/

# JetBrains Rider (cross platform .NET IDE) working folder
.idea/

# Ionide (cross platform F# VS Code tools) working folder
.ionide/

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -811,7 +811,7 @@ internal SqlGuid SqlGuid
{
if (StorageType.Guid == _type)
{
return new SqlGuid(_value._guid);
return IsNull ? SqlGuid.Null : new SqlGuid(_value._guid);
}
else if (StorageType.SqlGuid == _type)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
<Compile Include="LocalizationTest.cs" />
<Compile Include="MultipartIdentifierTests.cs" />
<Compile Include="SqlAuthenticationProviderTest.cs" />
<Compile Include="SqlBufferTests.cs" />
<Compile Include="SqlClientLoggerTest.cs" />
<Compile Include="SqlCommandSetTest.cs" />
<Compile Include="SqlConfigurableRetryLogicTest.cs" />
Expand Down
253 changes: 253 additions & 0 deletions src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlBufferTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Data.SqlTypes;
using System.Linq;
using System.Reflection;
using Xunit;

namespace Microsoft.Data.SqlClient.Tests
{
public sealed class SqlBufferTests
{
static SqlBufferTests()
{
const string sqlBufferTypeFullName = "Microsoft.Data.SqlClient.SqlBuffer";
const string storageTypeName = nameof(SqlBufferProxy.StorageType);

var assembly = typeof(SqlClientFactory).Assembly;
_sqlBufferType = assembly.GetType(sqlBufferTypeFullName)
?? throw new Exception($"Type not found [{sqlBufferTypeFullName}]");
_storageTypeType = _sqlBufferType.GetNestedTypes(BindingFlags.NonPublic)
.FirstOrDefault(x => x.Name == storageTypeName)
?? throw new Exception($"Type not found [{sqlBufferTypeFullName}+{storageTypeName}]");
}

private static readonly Type _sqlBufferType;
private static readonly Type _storageTypeType;
private readonly SqlBufferProxy _target = new();

public static IEnumerable<object[]> GetStorageTypeValues()
{
#if NET6_0_OR_GREATER
return Enum.GetValues<SqlBufferProxy.StorageType>()
.Select(x => new object[] { x });
#else
return Enum.GetValues(typeof(SqlBufferProxy.StorageType))
.OfType<SqlBufferProxy.StorageType>()
.Select(x => new object[] { x });
#endif
}

[Theory]
[MemberData(nameof(GetStorageTypeValues))]
public void StorageTypeInProxyShouldHaveTheSameValueAsOriginal(SqlBufferProxy.StorageType expected)
{
var originalEnumName = Enum.GetName(_storageTypeType, (int)expected);

Assert.Equal(expected.ToString(), originalEnumName);
}

[Fact]
public void GuidShouldThrowWhenSqlGuidNullIsSet()
{
_target.SqlGuid = SqlGuid.Null;

Assert.Throws<SqlNullValueException>(() => _target.Guid);
}

[Theory]
[InlineData(SqlBufferProxy.StorageType.Guid)]
[InlineData(SqlBufferProxy.StorageType.SqlGuid)]
public void GuidShouldThrowWhenSetToNullOfTypeIsCalled(SqlBufferProxy.StorageType storageType)
{
_target.SetToNullOfType(storageType);

Assert.Throws<SqlNullValueException>(() => _target.Guid);
}

[Fact]
public void GuidShouldReturnWhenGuidIsSet()
{
var expected = Guid.NewGuid();
_target.Guid = expected;

Assert.Equal(expected, _target.Guid);
}

[Fact]
public void GuidShouldReturnExpectedWhenSqlGuidIsSet()
{
var expected = Guid.NewGuid();
_target.SqlGuid = expected;

Assert.Equal(expected, _target.Guid);
}

[Theory]
[InlineData(SqlBufferProxy.StorageType.Guid)]
[InlineData(SqlBufferProxy.StorageType.SqlGuid)]
public void SqlGuidShouldReturnSqlNullWhenSetToNullOfTypeIsCalled(SqlBufferProxy.StorageType storageType)
{
_target.SetToNullOfType(storageType);

Assert.Equal(SqlGuid.Null, _target.SqlGuid);
}

[Fact]
public void SqlGuidShouldReturnSqlGuidNullWhenSqlGuidNullIsSet()
{
_target.SqlGuid = SqlGuid.Null;

Assert.Equal(SqlGuid.Null, _target.SqlGuid);
}

[Fact]
public void SqlGuidShouldReturnExpectedWhenGuidIsSet()
{
var guid = Guid.NewGuid();
SqlGuid expected = guid;
_target.Guid = guid;

Assert.Equal(expected, _target.SqlGuid);
}

[Fact]
public void SqlGuidShouldReturnExpectedWhenSqlGuidIsSet()
{
SqlGuid expected = Guid.NewGuid();
_target.SqlGuid = expected;

Assert.Equal(expected, _target.SqlGuid);
}

[Fact]
public void SqlValueShouldReturnExpectedWhenGuidIsSet()
{
var guid = Guid.NewGuid();
SqlGuid expected = guid;
_target.Guid = guid;

Assert.Equal(expected, _target.SqlValue);
}

[Fact]
public void SqlValueShouldReturnExpectedWhenSqlGuidIsSet()
{
SqlGuid expected = Guid.NewGuid();
_target.SqlGuid = expected;

Assert.Equal(expected, _target.SqlValue);
}

public sealed class SqlBufferProxy
{
public enum StorageType
{
Empty = 0,
Boolean,
Byte,
DateTime,
Decimal,
Double,
Int16,
Int32,
Int64,
Guid,
Money,
Single,
String,
SqlBinary,
SqlCachedBuffer,
SqlGuid,
SqlXml,
Date,
DateTime2,
DateTimeOffset,
Time,
}

private static readonly PropertyInfo _guidProperty;
private static readonly PropertyInfo _sqlGuidProperty;
private static readonly PropertyInfo _sqlValueProperty;
private static readonly MethodInfo _setToNullOfTypeMethod;
private readonly object _instance;

static SqlBufferProxy()
{
var flags = BindingFlags.NonPublic | BindingFlags.Instance;
_guidProperty = _sqlBufferType.GetProperty(nameof(Guid), flags);
_sqlGuidProperty = _sqlBufferType.GetProperty(nameof(SqlGuid), flags);
_sqlValueProperty = _sqlBufferType.GetProperty(nameof(SqlValue), flags);
_setToNullOfTypeMethod = _sqlBufferType.GetMethod(nameof(SetToNullOfType), flags);
}

public SqlBufferProxy()
{
_instance = Activator.CreateInstance(_sqlBufferType, true);
}

public Guid Guid
{
get => GetPropertyValue<Guid>(_guidProperty);
set => SetPropertyValue(_guidProperty, value);
}

public SqlGuid SqlGuid
{
get => GetPropertyValue<SqlGuid>(_sqlGuidProperty);
set => SetPropertyValue(_sqlGuidProperty, value);
}

public object SqlValue
{
get => GetPropertyValue<object>(_sqlValueProperty);
}

public void SetToNullOfType(StorageType storageType)
{
#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
_setToNullOfTypeMethod
.Invoke(_instance, BindingFlags.DoNotWrapExceptions, null, new object[] { (int)storageType }, null);
#else
_setToNullOfTypeMethod.Invoke(_instance, new object[] { (int)storageType });
#endif
}

private T GetPropertyValue<T>(PropertyInfo property)
{
#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
return (T)property.GetValue(_instance, BindingFlags.DoNotWrapExceptions, null, null, null);
#else
try
{
return (T)property.GetValue(_instance);
}
catch (TargetInvocationException e)
{
throw e.InnerException!;
}
#endif
}

private void SetPropertyValue(PropertyInfo property, object value)
{
#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
property.SetValue(_instance, value, BindingFlags.DoNotWrapExceptions, null, null, null);
#else
try
{
property.SetValue(_instance, value);
}
catch (TargetInvocationException e)
{
throw e.InnerException!;
}
#endif
}
}
}
}
Loading