Skip to content

Commit f5df519

Browse files
authored
Fix | SqlBuffer.SqlGuid (#2310)
1 parent 8c9b699 commit f5df519

File tree

4 files changed

+258
-1
lines changed

4 files changed

+258
-1
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,9 @@ healthchecksdb
353353
# Backup folder for Package Reference Convert tool in Visual Studio 2017
354354
MigrationBackup/
355355

356+
# JetBrains Rider (cross platform .NET IDE) working folder
357+
.idea/
358+
356359
# Ionide (cross platform F# VS Code tools) working folder
357360
.ionide/
358361

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlBuffer.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -811,7 +811,7 @@ internal SqlGuid SqlGuid
811811
{
812812
if (StorageType.Guid == _type)
813813
{
814-
return new SqlGuid(_value._guid);
814+
return IsNull ? SqlGuid.Null : new SqlGuid(_value._guid);
815815
}
816816
else if (StorageType.SqlGuid == _type)
817817
{

src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
<Compile Include="LocalizationTest.cs" />
3434
<Compile Include="MultipartIdentifierTests.cs" />
3535
<Compile Include="SqlAuthenticationProviderTest.cs" />
36+
<Compile Include="SqlBufferTests.cs" />
3637
<Compile Include="SqlClientLoggerTest.cs" />
3738
<Compile Include="SqlCommandSetTest.cs" />
3839
<Compile Include="SqlConfigurableRetryLogicTest.cs" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Data.SqlTypes;
8+
using System.Linq;
9+
using System.Reflection;
10+
using Xunit;
11+
12+
namespace Microsoft.Data.SqlClient.Tests
13+
{
14+
public sealed class SqlBufferTests
15+
{
16+
static SqlBufferTests()
17+
{
18+
const string sqlBufferTypeFullName = "Microsoft.Data.SqlClient.SqlBuffer";
19+
const string storageTypeName = nameof(SqlBufferProxy.StorageType);
20+
21+
var assembly = typeof(SqlClientFactory).Assembly;
22+
_sqlBufferType = assembly.GetType(sqlBufferTypeFullName)
23+
?? throw new Exception($"Type not found [{sqlBufferTypeFullName}]");
24+
_storageTypeType = _sqlBufferType.GetNestedTypes(BindingFlags.NonPublic)
25+
.FirstOrDefault(x => x.Name == storageTypeName)
26+
?? throw new Exception($"Type not found [{sqlBufferTypeFullName}+{storageTypeName}]");
27+
}
28+
29+
private static readonly Type _sqlBufferType;
30+
private static readonly Type _storageTypeType;
31+
private readonly SqlBufferProxy _target = new();
32+
33+
public static IEnumerable<object[]> GetStorageTypeValues()
34+
{
35+
#if NET6_0_OR_GREATER
36+
return Enum.GetValues<SqlBufferProxy.StorageType>()
37+
.Select(x => new object[] { x });
38+
#else
39+
return Enum.GetValues(typeof(SqlBufferProxy.StorageType))
40+
.OfType<SqlBufferProxy.StorageType>()
41+
.Select(x => new object[] { x });
42+
#endif
43+
}
44+
45+
[Theory]
46+
[MemberData(nameof(GetStorageTypeValues))]
47+
public void StorageTypeInProxyShouldHaveTheSameValueAsOriginal(SqlBufferProxy.StorageType expected)
48+
{
49+
var originalEnumName = Enum.GetName(_storageTypeType, (int)expected);
50+
51+
Assert.Equal(expected.ToString(), originalEnumName);
52+
}
53+
54+
[Fact]
55+
public void GuidShouldThrowWhenSqlGuidNullIsSet()
56+
{
57+
_target.SqlGuid = SqlGuid.Null;
58+
59+
Assert.Throws<SqlNullValueException>(() => _target.Guid);
60+
}
61+
62+
[Theory]
63+
[InlineData(SqlBufferProxy.StorageType.Guid)]
64+
[InlineData(SqlBufferProxy.StorageType.SqlGuid)]
65+
public void GuidShouldThrowWhenSetToNullOfTypeIsCalled(SqlBufferProxy.StorageType storageType)
66+
{
67+
_target.SetToNullOfType(storageType);
68+
69+
Assert.Throws<SqlNullValueException>(() => _target.Guid);
70+
}
71+
72+
[Fact]
73+
public void GuidShouldReturnWhenGuidIsSet()
74+
{
75+
var expected = Guid.NewGuid();
76+
_target.Guid = expected;
77+
78+
Assert.Equal(expected, _target.Guid);
79+
}
80+
81+
[Fact]
82+
public void GuidShouldReturnExpectedWhenSqlGuidIsSet()
83+
{
84+
var expected = Guid.NewGuid();
85+
_target.SqlGuid = expected;
86+
87+
Assert.Equal(expected, _target.Guid);
88+
}
89+
90+
[Theory]
91+
[InlineData(SqlBufferProxy.StorageType.Guid)]
92+
[InlineData(SqlBufferProxy.StorageType.SqlGuid)]
93+
public void SqlGuidShouldReturnSqlNullWhenSetToNullOfTypeIsCalled(SqlBufferProxy.StorageType storageType)
94+
{
95+
_target.SetToNullOfType(storageType);
96+
97+
Assert.Equal(SqlGuid.Null, _target.SqlGuid);
98+
}
99+
100+
[Fact]
101+
public void SqlGuidShouldReturnSqlGuidNullWhenSqlGuidNullIsSet()
102+
{
103+
_target.SqlGuid = SqlGuid.Null;
104+
105+
Assert.Equal(SqlGuid.Null, _target.SqlGuid);
106+
}
107+
108+
[Fact]
109+
public void SqlGuidShouldReturnExpectedWhenGuidIsSet()
110+
{
111+
var guid = Guid.NewGuid();
112+
SqlGuid expected = guid;
113+
_target.Guid = guid;
114+
115+
Assert.Equal(expected, _target.SqlGuid);
116+
}
117+
118+
[Fact]
119+
public void SqlGuidShouldReturnExpectedWhenSqlGuidIsSet()
120+
{
121+
SqlGuid expected = Guid.NewGuid();
122+
_target.SqlGuid = expected;
123+
124+
Assert.Equal(expected, _target.SqlGuid);
125+
}
126+
127+
[Fact]
128+
public void SqlValueShouldReturnExpectedWhenGuidIsSet()
129+
{
130+
var guid = Guid.NewGuid();
131+
SqlGuid expected = guid;
132+
_target.Guid = guid;
133+
134+
Assert.Equal(expected, _target.SqlValue);
135+
}
136+
137+
[Fact]
138+
public void SqlValueShouldReturnExpectedWhenSqlGuidIsSet()
139+
{
140+
SqlGuid expected = Guid.NewGuid();
141+
_target.SqlGuid = expected;
142+
143+
Assert.Equal(expected, _target.SqlValue);
144+
}
145+
146+
public sealed class SqlBufferProxy
147+
{
148+
public enum StorageType
149+
{
150+
Empty = 0,
151+
Boolean,
152+
Byte,
153+
DateTime,
154+
Decimal,
155+
Double,
156+
Int16,
157+
Int32,
158+
Int64,
159+
Guid,
160+
Money,
161+
Single,
162+
String,
163+
SqlBinary,
164+
SqlCachedBuffer,
165+
SqlGuid,
166+
SqlXml,
167+
Date,
168+
DateTime2,
169+
DateTimeOffset,
170+
Time,
171+
}
172+
173+
private static readonly PropertyInfo _guidProperty;
174+
private static readonly PropertyInfo _sqlGuidProperty;
175+
private static readonly PropertyInfo _sqlValueProperty;
176+
private static readonly MethodInfo _setToNullOfTypeMethod;
177+
private readonly object _instance;
178+
179+
static SqlBufferProxy()
180+
{
181+
var flags = BindingFlags.NonPublic | BindingFlags.Instance;
182+
_guidProperty = _sqlBufferType.GetProperty(nameof(Guid), flags);
183+
_sqlGuidProperty = _sqlBufferType.GetProperty(nameof(SqlGuid), flags);
184+
_sqlValueProperty = _sqlBufferType.GetProperty(nameof(SqlValue), flags);
185+
_setToNullOfTypeMethod = _sqlBufferType.GetMethod(nameof(SetToNullOfType), flags);
186+
}
187+
188+
public SqlBufferProxy()
189+
{
190+
_instance = Activator.CreateInstance(_sqlBufferType, true);
191+
}
192+
193+
public Guid Guid
194+
{
195+
get => GetPropertyValue<Guid>(_guidProperty);
196+
set => SetPropertyValue(_guidProperty, value);
197+
}
198+
199+
public SqlGuid SqlGuid
200+
{
201+
get => GetPropertyValue<SqlGuid>(_sqlGuidProperty);
202+
set => SetPropertyValue(_sqlGuidProperty, value);
203+
}
204+
205+
public object SqlValue
206+
{
207+
get => GetPropertyValue<object>(_sqlValueProperty);
208+
}
209+
210+
public void SetToNullOfType(StorageType storageType)
211+
{
212+
#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
213+
_setToNullOfTypeMethod
214+
.Invoke(_instance, BindingFlags.DoNotWrapExceptions, null, new object[] { (int)storageType }, null);
215+
#else
216+
_setToNullOfTypeMethod.Invoke(_instance, new object[] { (int)storageType });
217+
#endif
218+
}
219+
220+
private T GetPropertyValue<T>(PropertyInfo property)
221+
{
222+
#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
223+
return (T)property.GetValue(_instance, BindingFlags.DoNotWrapExceptions, null, null, null);
224+
#else
225+
try
226+
{
227+
return (T)property.GetValue(_instance);
228+
}
229+
catch (TargetInvocationException e)
230+
{
231+
throw e.InnerException!;
232+
}
233+
#endif
234+
}
235+
236+
private void SetPropertyValue(PropertyInfo property, object value)
237+
{
238+
#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
239+
property.SetValue(_instance, value, BindingFlags.DoNotWrapExceptions, null, null, null);
240+
#else
241+
try
242+
{
243+
property.SetValue(_instance, value);
244+
}
245+
catch (TargetInvocationException e)
246+
{
247+
throw e.InnerException!;
248+
}
249+
#endif
250+
}
251+
}
252+
}
253+
}

0 commit comments

Comments
 (0)