Skip to content

Commit f87ab82

Browse files
committed
Improved SimulatedDbCommand similarity to SqlCommand.
1 parent 5f0b55d commit f87ab82

2 files changed

Lines changed: 145 additions & 24 deletions

File tree

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
using System.Data;
2+
using System.Data.Common;
3+
using static Microsoft.VisualStudio.TestTools.UnitTesting.Assert;
4+
5+
namespace SqlServerSimulator;
6+
7+
[TestClass]
8+
public class CommandTests
9+
{
10+
private static DbCommand CreateCommand() => new Simulation().CreateDbConnection().CreateCommand();
11+
12+
private static DbCommand CreateCommand(string? commandText) => new Simulation().CreateCommand(commandText);
13+
14+
private static DbConnection CreateOpenConnection() => new Simulation().CreateOpenConnection();
15+
16+
[TestMethod]
17+
public void DbConnectionPassThrough()
18+
{
19+
using var connection = new Simulation().CreateDbConnection();
20+
using var command = connection.CreateCommand();
21+
AreSame(connection, command.Connection);
22+
}
23+
24+
[TestMethod]
25+
public void CreateCommandIsNotNull() => IsNotNull(CreateCommand());
26+
27+
[TestMethod]
28+
public void CommandTypeDefaultsText() => AreEqual(System.Data.CommandType.Text, CreateCommand().CommandType);
29+
30+
[TestMethod]
31+
public void CreateCommandWithCommandText()
32+
{
33+
const string commandText = "select 1";
34+
using var command = CreateCommand(commandText);
35+
AreEqual(commandText, command.CommandText);
36+
}
37+
38+
[TestMethod]
39+
public void NullCommandTextConvertedToEmptyString() => AreSame(string.Empty, CreateCommand("").CommandText);
40+
41+
[TestMethod]
42+
public void CommandTimeoutRangeCheck()
43+
{
44+
using var command = CreateCommand();
45+
AreEqual(30, command.CommandTimeout);
46+
var exception = ThrowsExactly<ArgumentException>(() => command.CommandTimeout = -1);
47+
AreEqual(nameof(command.CommandTimeout), exception.ParamName);
48+
49+
command.CommandTimeout = 5;
50+
AreEqual(5, command.CommandTimeout);
51+
}
52+
53+
[TestMethod]
54+
public void DesignTimeVisibleBehavior()
55+
{
56+
using var command = CreateCommand();
57+
IsTrue(command.DesignTimeVisible);
58+
command.DesignTimeVisible = false;
59+
IsFalse(command.DesignTimeVisible);
60+
command.DesignTimeVisible = true;
61+
IsTrue(command.DesignTimeVisible);
62+
}
63+
64+
[TestMethod]
65+
public void TransactionPassThrough()
66+
{
67+
using var connection = CreateOpenConnection();
68+
using var transaction = connection.BeginTransaction();
69+
AreSame(transaction.Connection, connection);
70+
using var command = connection.CreateCommand();
71+
IsNull(command.Transaction);
72+
73+
command.Transaction = transaction;
74+
AreSame(transaction, command.Transaction);
75+
command.Transaction = null;
76+
IsNull(command.Transaction);
77+
}
78+
79+
sealed class TestTransaction : DbTransaction
80+
{
81+
public override IsolationLevel IsolationLevel => throw new NotImplementedException();
82+
protected override DbConnection? DbConnection => throw new NotImplementedException();
83+
public override void Commit() => throw new NotImplementedException();
84+
public override void Rollback() => throw new NotImplementedException();
85+
}
86+
87+
[TestMethod]
88+
public void TransactionRestrictions()
89+
{
90+
var simulation = new Simulation();
91+
using var connection = simulation.CreateOpenConnection();
92+
using (var sim1con2 = simulation.CreateOpenConnection())
93+
{
94+
using var otherConnectionTransaction = sim1con2.BeginTransaction();
95+
96+
using var doomedCommand = connection.CreateCommand();
97+
98+
_ = Throws<Exception>(() => doomedCommand.Transaction = otherConnectionTransaction);
99+
}
100+
101+
using var connection2 = CreateOpenConnection();
102+
using var transaction = connection.BeginTransaction();
103+
using var command2 = connection2.CreateCommand();
104+
_ = Throws<Exception>(() => command2.Transaction = transaction);
105+
_ = Throws<Exception>(() => command2.Transaction = new TestTransaction());
106+
}
107+
}

SqlServerSimulator/SimulatedDbCommand.cs

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,47 +6,61 @@ namespace SqlServerSimulator;
66

77
sealed class SimulatedDbCommand : DbCommand
88
{
9-
internal Simulation simulation;
10-
internal SimulatedDbConnection connection;
11-
internal SimulatedDbTransaction? transaction;
12-
private string commandText = string.Empty;
9+
internal readonly Simulation simulation;
1310

1411
public SimulatedDbCommand(Simulation simulation, SimulatedDbConnection connection)
1512
{
1613
this.simulation = simulation;
17-
this.connection = connection;
18-
}
19-
20-
public SimulatedDbCommand(Simulation simulation, SimulatedDbConnection connection, SimulatedDbTransaction transaction)
21-
{
22-
this.simulation = simulation;
23-
this.connection = connection;
24-
this.transaction = transaction;
14+
this.Connection = connection;
2515
}
2616

2717
[AllowNull]
2818
public override string CommandText
2919
{
30-
get => commandText;
31-
set => commandText = value ?? string.Empty;
32-
}
20+
get;
21+
set => field = value ?? string.Empty;
22+
} = string.Empty;
23+
24+
public override int CommandTimeout
25+
{
26+
get;
27+
set => field = value >= 0 ?
28+
value :
29+
throw new ArgumentException($"Invalid {nameof(CommandTimeout)} value {value}; the value must be >= 0.", nameof(CommandTimeout));
30+
// ArgumentOutOfRangeException would be more appropriate but the official SQL Client uses ArgumentException, so this is more consistent.
31+
} = 30;
32+
33+
public override CommandType CommandType
34+
{
35+
get;
36+
set => throw (Enum.IsDefined(value) ? new NotSupportedException() : new ArgumentOutOfRangeException(nameof(CommandType), value, null));
37+
} = CommandType.Text;
3338

34-
public override int CommandTimeout { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
35-
public override CommandType CommandType { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
36-
public override bool DesignTimeVisible { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
37-
public override UpdateRowSource UpdatedRowSource { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
38-
protected override DbConnection? DbConnection { get => this.connection; set => throw new NotImplementedException(); }
39+
public override bool DesignTimeVisible { get; set; } = true;
40+
41+
public override UpdateRowSource UpdatedRowSource { get; set; } = UpdateRowSource.Both;
42+
43+
protected override DbConnection? DbConnection
44+
{
45+
get;
46+
set
47+
{
48+
if (field is not null) // Set by the constructor.
49+
throw new NotSupportedException("Simulated DbCommands cannot switch to different connections.");
50+
field = value;
51+
}
52+
}
3953

4054
protected override DbParameterCollection DbParameterCollection { get; } = new SimulatedDbParameterCollection();
4155

4256
protected override DbTransaction? DbTransaction
4357
{
44-
get => this.transaction;
58+
get;
4559
set
4660
{
4761
if (value == null)
4862
{
49-
this.transaction = null;
63+
field = null;
5064
return;
5165
}
5266

@@ -56,10 +70,10 @@ protected override DbTransaction? DbTransaction
5670
if (transaction.simulation != this.simulation)
5771
throw new NotSupportedException("Simulated DbCommands cannot switch to different simulations.");
5872

59-
if (transaction.connection != this.connection)
73+
if (transaction.connection != this.Connection)
6074
throw new NotSupportedException("Simulated DbCommands cannot switch to different connections.");
6175

62-
this.transaction = transaction;
76+
field = transaction;
6377
}
6478
}
6579

0 commit comments

Comments
 (0)