Skip to content

Commit d48ab48

Browse files
committed
test: add more tests
1 parent a73ac8d commit d48ab48

File tree

11 files changed

+1837
-39
lines changed

11 files changed

+1837
-39
lines changed

drivers/spanner-ado-net/spanner-ado-net-tests/AbstractMockServerTests.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ public void Reset()
6060
Fixture.SpannerMock.Reset();
6161
}
6262

63+
protected SpannerConnection OpenConnection()
64+
{
65+
var connection = new SpannerConnection(ConnectionString);
66+
connection.Open();
67+
return connection;
68+
}
69+
6370
protected async Task<SpannerConnection> OpenConnectionAsync()
6471
{
6572
var connection = new SpannerConnection(ConnectionString);

drivers/spanner-ado-net/spanner-ado-net-tests/ReaderTests.cs

Lines changed: 1455 additions & 0 deletions
Large diffs are not rendered by default.

drivers/spanner-ado-net/spanner-ado-net-tests/SpannerParameterCollectionTests.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,20 @@ public void CloningSucceeds()
286286
Assert.DoesNotThrow(() => command.Clone());
287287
}
288288

289+
[Test]
290+
public void CleanName()
291+
{
292+
var param = new SpannerParameter();
293+
var command = new SpannerCommand();
294+
command.Parameters.Add(param);
295+
296+
param.ParameterName = null;
297+
298+
// These should not throw exceptions
299+
Assert.That(command.Parameters.IndexOf(param.ParameterName), Is.EqualTo(0));
300+
Assert.That(param.ParameterName, Is.EqualTo(""));
301+
}
302+
289303
class SomeOtherDbParameter : DbParameter
290304
{
291305
public override void ResetDbType() {}
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
using System.Data;
2+
using System.Data.Common;
3+
using Google.Cloud.Spanner.V1;
4+
using Google.Cloud.SpannerLib.MockServer;
5+
using TypeCode = Google.Cloud.Spanner.V1.TypeCode;
6+
7+
namespace Google.Cloud.Spanner.DataProvider.Tests;
8+
9+
public class SpannerParameterTests : AbstractMockServerTests
10+
{
11+
[Test]
12+
public void SettingValueDoesNotChangeDbType()
13+
{
14+
// ReSharper disable once UseObjectOrCollectionInitializer
15+
var p = new SpannerParameter { DbType = DbType.String };
16+
p.Value = 8;
17+
Assert.That(p.DbType, Is.EqualTo(DbType.String));
18+
}
19+
20+
[Test]
21+
public void DefaultConstructor()
22+
{
23+
var p = new SpannerParameter();
24+
Assert.That(p.DbType, Is.EqualTo(DbType.String), "DbType");
25+
Assert.That(p.Direction, Is.EqualTo(ParameterDirection.Input), "Direction");
26+
Assert.That(p.IsNullable, Is.False, "IsNullable");
27+
Assert.That(p.ParameterName, Is.Empty, "ParameterName");
28+
Assert.That(p.Precision, Is.EqualTo(0), "Precision");
29+
Assert.That(p.Scale, Is.EqualTo(0), "Scale");
30+
Assert.That(p.Size, Is.EqualTo(0), "Size");
31+
Assert.That(p.SourceColumn, Is.Empty, "SourceColumn");
32+
Assert.That(p.SourceVersion, Is.EqualTo(DataRowVersion.Current), "SourceVersion");
33+
Assert.That(p.Value, Is.Null, "Value");
34+
}
35+
36+
[Test]
37+
public void ConstructorValueDateTime()
38+
{
39+
var value = new DateTime(2004, 8, 24);
40+
41+
var p = new SpannerParameter("address", value);
42+
// Setting a parameter value does not change the type.
43+
Assert.That(p.DbType, Is.EqualTo(DbType.String), "B:DbType");
44+
Assert.That(p.Direction, Is.EqualTo(ParameterDirection.Input), "B:Direction");
45+
Assert.That(p.IsNullable, Is.False, "B:IsNullable");
46+
Assert.That(p.ParameterName, Is.EqualTo("address"), "B:ParameterName");
47+
Assert.That(p.Precision, Is.EqualTo(0), "B:Precision");
48+
Assert.That(p.Scale, Is.EqualTo(0), "B:Scale");
49+
Assert.That(p.Size, Is.EqualTo(0), "B:Size");
50+
Assert.That(p.SourceColumn, Is.Empty, "B:SourceColumn");
51+
Assert.That(p.SourceVersion, Is.EqualTo(DataRowVersion.Current), "B:SourceVersion");
52+
Assert.That(p.Value, Is.EqualTo(value), "B:Value");
53+
}
54+
55+
[Test]
56+
public void ConstructorValueDbNull()
57+
{
58+
var p = new SpannerParameter("address", DBNull.Value);
59+
Assert.That(p.DbType, Is.EqualTo(DbType.String), "B:DbType");
60+
Assert.That(p.Direction, Is.EqualTo(ParameterDirection.Input), "B:Direction");
61+
Assert.That(p.IsNullable, Is.False, "B:IsNullable");
62+
Assert.That(p.ParameterName, Is.EqualTo("address"), "B:ParameterName");
63+
Assert.That(p.Precision, Is.EqualTo(0), "B:Precision");
64+
Assert.That(p.Scale, Is.EqualTo(0), "B:Scale");
65+
Assert.That(p.Size, Is.EqualTo(0), "B:Size");
66+
Assert.That(p.SourceColumn, Is.Empty, "B:SourceColumn");
67+
Assert.That(p.SourceVersion, Is.EqualTo(DataRowVersion.Current), "B:SourceVersion");
68+
Assert.That(p.Value, Is.EqualTo(DBNull.Value), "B:Value");
69+
}
70+
71+
[Test]
72+
public void ConstructorValueNull()
73+
{
74+
var p = new SpannerParameter("address", null);
75+
Assert.That(p.DbType, Is.EqualTo(DbType.String), "A:DbType");
76+
Assert.That(p.Direction, Is.EqualTo(ParameterDirection.Input), "A:Direction");
77+
Assert.That(p.IsNullable, Is.False, "A:IsNullable");
78+
Assert.That(p.ParameterName, Is.EqualTo("address"), "A:ParameterName");
79+
Assert.That(p.Precision, Is.EqualTo(0), "A:Precision");
80+
Assert.That(p.Scale, Is.EqualTo(0), "A:Scale");
81+
Assert.That(p.Size, Is.EqualTo(0), "A:Size");
82+
Assert.That(p.SourceColumn, Is.Empty, "A:SourceColumn");
83+
Assert.That(p.SourceVersion, Is.EqualTo(DataRowVersion.Current), "A:SourceVersion");
84+
Assert.That(p.Value, Is.Null, "A:Value");
85+
}
86+
87+
[Test]
88+
public void Clone()
89+
{
90+
var expected = new SpannerParameter
91+
{
92+
Value = 42,
93+
ParameterName = "TheAnswer",
94+
95+
DbType = DbType.Int32,
96+
97+
Direction = ParameterDirection.InputOutput,
98+
IsNullable = true,
99+
Precision = 1,
100+
Scale = 2,
101+
Size = 4,
102+
103+
SourceVersion = DataRowVersion.Proposed,
104+
SourceColumn = "source",
105+
SourceColumnNullMapping = true,
106+
};
107+
var actual = expected.Clone();
108+
109+
Assert.That(actual.Value, Is.EqualTo(expected.Value));
110+
Assert.That(actual.ParameterName, Is.EqualTo(expected.ParameterName));
111+
112+
Assert.That(actual.DbType, Is.EqualTo(expected.DbType));
113+
114+
Assert.That(actual.Direction, Is.EqualTo(expected.Direction));
115+
Assert.That(actual.IsNullable, Is.EqualTo(expected.IsNullable));
116+
Assert.That(actual.Precision, Is.EqualTo(expected.Precision));
117+
Assert.That(actual.Scale, Is.EqualTo(expected.Scale));
118+
Assert.That(actual.Size, Is.EqualTo(expected.Size));
119+
120+
Assert.That(actual.SourceVersion, Is.EqualTo(expected.SourceVersion));
121+
Assert.That(actual.SourceColumn, Is.EqualTo(expected.SourceColumn));
122+
Assert.That(actual.SourceColumnNullMapping, Is.EqualTo(expected.SourceColumnNullMapping));
123+
}
124+
125+
[Test]
126+
public void ParameterNull()
127+
{
128+
var param = new SpannerParameter{ParameterName = "param", DbType = DbType.Decimal};
129+
Assert.That(param.Scale, Is.EqualTo(0), "#A1");
130+
param.Value = DBNull.Value;
131+
Assert.That(param.Scale, Is.EqualTo(0), "#A2");
132+
133+
param = new SpannerParameter{ParameterName = "param", DbType = DbType.Int32};
134+
Assert.That(param.Scale, Is.EqualTo(0), "#B1");
135+
param.Value = DBNull.Value;
136+
Assert.That(param.Scale, Is.EqualTo(0), "#B2");
137+
}
138+
139+
[Test]
140+
public async Task MatchParamIndexCaseInsensitively()
141+
{
142+
const string sql = "SELECT @p,@P";
143+
Fixture.SpannerMock.AddOrUpdateStatementResult(sql, StatementResult.CreateResultSet(
144+
new List<Tuple<TypeCode, string>>([Tuple.Create(TypeCode.String, "p"), Tuple.Create(TypeCode.String, "p")]),
145+
new List<object[]>([["Hello World", "Hello World"]])));
146+
147+
await using var conn = await OpenConnectionAsync();
148+
await using var cmd = new SpannerCommand(sql, conn);
149+
cmd.AddParameter("p", "Hello World");
150+
await cmd.ExecuteNonQueryAsync();
151+
152+
var request = Fixture.SpannerMock.Requests.OfType<ExecuteSqlRequest>().Single(r => r.Sql == sql);
153+
Assert.That(request, Is.Not.Null);
154+
// TODO: Revisit once https://github.com/googleapis/go-sql-spanner/issues/594 has been decided.
155+
Assert.That(request.Params.Fields.Count, Is.EqualTo(2));
156+
Assert.That(request.Params.Fields["p"].StringValue, Is.EqualTo("Hello World"));
157+
Assert.That(request.Params.Fields["P"].HasNullValue);
158+
}
159+
160+
[Test]
161+
public void PrecisionViaInterface()
162+
{
163+
var parameter = new SpannerParameter();
164+
var paramIface = (IDbDataParameter)parameter;
165+
166+
paramIface.Precision = 42;
167+
168+
Assert.That(paramIface.Precision, Is.EqualTo((byte)42));
169+
}
170+
171+
[Test]
172+
public void PrecisionViaBaseClass()
173+
{
174+
var parameter = new SpannerParameter();
175+
var paramBase = (DbParameter)parameter;
176+
177+
paramBase.Precision = 42;
178+
179+
Assert.That(paramBase.Precision, Is.EqualTo((byte)42));
180+
}
181+
182+
[Test]
183+
public void ScaleViaInterface()
184+
{
185+
var parameter = new SpannerParameter();
186+
var paramIface = (IDbDataParameter)parameter;
187+
188+
paramIface.Scale = 42;
189+
190+
Assert.That(paramIface.Scale, Is.EqualTo((byte)42));
191+
}
192+
193+
[Test]
194+
public void ScaleViaBaseClass()
195+
{
196+
var parameter = new SpannerParameter();
197+
var paramBase = (DbParameter)parameter;
198+
199+
paramBase.Scale = 42;
200+
201+
Assert.That(paramBase.Scale, Is.EqualTo((byte)42));
202+
}
203+
204+
[Test]
205+
public void NullValueThrows()
206+
{
207+
using var connection = OpenConnection();
208+
using var command = new SpannerCommand("SELECT @p", connection);
209+
command.Parameters.Add(new SpannerParameter("p", null));
210+
211+
Assert.That(() => command.ExecuteReader(), Throws.InvalidOperationException);
212+
}
213+
214+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using System;
16+
17+
namespace Google.Cloud.Spanner.DataProvider;
18+
19+
internal static class Preconditions
20+
{
21+
internal static int CheckIndexRange(int argument, string paramName, int minInclusive, int maxInclusive) =>
22+
argument < minInclusive || argument > maxInclusive ?
23+
throw new IndexOutOfRangeException($"Value {argument} should be in range [{minInclusive}, {maxInclusive}]") : argument;
24+
25+
}

drivers/spanner-ado-net/spanner-ado-net/SpannerCommand.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,10 @@ protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior)
311311
GaxPreconditions.CheckState(_mutation == null, "Cannot execute mutations with ExecuteDbDataReader()");
312312
try
313313
{
314-
var rows = Execute();
314+
var mode = behavior.HasFlag(CommandBehavior.SchemaOnly)
315+
? ExecuteSqlRequest.Types.QueryMode.Plan
316+
: ExecuteSqlRequest.Types.QueryMode.Normal;
317+
var rows = Execute(mode);
315318
return new SpannerDataReader(SpannerConnection, rows, behavior);
316319
}
317320
catch (SpannerException exception)
@@ -339,7 +342,10 @@ protected override async Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBeha
339342
GaxPreconditions.CheckState(_mutation == null, "Cannot execute mutations with ExecuteDbDataReader()");
340343
try
341344
{
342-
var rows = await ExecuteAsync(cancellationToken);
345+
var mode = behavior.HasFlag(CommandBehavior.SchemaOnly)
346+
? ExecuteSqlRequest.Types.QueryMode.Plan
347+
: ExecuteSqlRequest.Types.QueryMode.Normal;
348+
var rows = await ExecuteAsync(mode, cancellationToken);
343349
return new SpannerDataReader(SpannerConnection, rows, behavior);
344350
}
345351
catch (SpannerException exception)

0 commit comments

Comments
 (0)