diff --git a/kx.Benchmark.Test/kx.Benchmark.Test.csproj b/kx.Benchmark.Test/kx.Benchmark.Test.csproj
index 2f9a120..d5d49b3 100644
--- a/kx.Benchmark.Test/kx.Benchmark.Test.csproj
+++ b/kx.Benchmark.Test/kx.Benchmark.Test.csproj
@@ -21,8 +21,6 @@
-
-
diff --git a/kx.Test/Connection/ConnectionSerialisationTests.cs b/kx.Test/Connection/ConnectionSerialisationTests.cs
index b8655bc..199a727 100644
--- a/kx.Test/Connection/ConnectionSerialisationTests.cs
+++ b/kx.Test/Connection/ConnectionSerialisationTests.cs
@@ -9,6 +9,8 @@ namespace kx.Test.Connection
[TestFixture]
public class ConnectionSerialisationTests
{
+ private static readonly string[] Keys = {"Key_1"};
+ private static readonly object[] Values = {"Value_1"};
private readonly int _testVersionNumber = 3;
[Test]
@@ -402,7 +404,7 @@ public void ConnectionSerialisesAndDeserialisesTimeSpanInput()
[Test]
public void ConnectionSerialisesAndDeserialisesDictInput()
{
- c.Dict expected = new c.Dict(new string[] { "Key_1" }, new object[] { "Value_1" });
+ c.Dict expected = new c.Dict(Keys, Values);
using (var connection = new c(_testVersionNumber))
{
@@ -419,7 +421,7 @@ public void ConnectionSerialisesAndDeserialisesDictInput()
[Test]
public void ConnectionSerialisesAndDeserialisesFlipInput()
{
- c.Flip expected = new c.Flip(new c.Dict(new string[] { "Key_1" }, new object[] { "Value_1" }));
+ c.Flip expected = new c.Flip(new c.Dict(Keys, Values));
using (var connection = new c(_testVersionNumber))
{
diff --git a/kx.Test/Connection/ConnectionTests.cs b/kx.Test/Connection/ConnectionTests.cs
index 6a41a5a..57b8f66 100644
--- a/kx.Test/Connection/ConnectionTests.cs
+++ b/kx.Test/Connection/ConnectionTests.cs
@@ -1,4 +1,7 @@
using System;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
using kx.Test.TestUtils;
using NUnit.Framework;
@@ -86,5 +89,156 @@ public void ConnectionThrowsSerialisableExpectionIfAuthenticationDoesNotPass()
Assert.IsNotNull(error);
}
}
+
+ [Test]
+ public void ProtectedConstructorAndBufferStateAreAccessibleToDerivedTypes()
+ {
+ using (var connection = new TestConnection())
+ {
+ Assert.IsNull(connection.ExposedReadBuffer);
+ Assert.IsFalse(connection.ExposedIsLittleEndian);
+ Assert.AreEqual(0, connection.ExposedReadPosition);
+
+ connection.ExposedReadPosition = 3;
+ Assert.AreEqual(3, connection.ExposedReadPosition);
+ Assert.Throws(() => connection.ExposedReadPosition = -1);
+ }
+ }
+
+ [Test]
+ public void DisposeCanBeCalledMoreThanOnce()
+ {
+ var connection = new c(new MemoryStream());
+
+ connection.Dispose();
+
+ Assert.DoesNotThrow(connection.Dispose);
+ }
+
+ [Test]
+ public void CloseClosesBothStreamAndSocket()
+ {
+ using (var server = new TestableTcpServer())
+ {
+ var connection = new c("localhost", server.TestPort);
+
+ Assert.DoesNotThrow(connection.Close);
+ connection.Dispose();
+ }
+ }
+
+ [Test]
+ public void ExplicitTlsOptionsConstructorAcceptsNullAsDisabled()
+ {
+ using (var server = new TestableTcpServer())
+ using (var connection = new c("localhost", server.TestPort, Environment.UserName, 1024, null))
+ {
+ Assert.IsNotNull(connection);
+ }
+ }
+
+ [Test]
+ public async Task ParameterlessAsyncReadReturnsDeserialisedObject()
+ {
+ const int expected = 42;
+ byte[] message;
+ using (var serializer = new c(3))
+ {
+ message = serializer.Serialize(1, expected);
+ }
+
+ using (var stream = new MemoryStream(message))
+ using (var connection = new c(stream))
+ {
+ Assert.AreEqual(expected, await connection.kAsync());
+ }
+ }
+
+ [Test]
+ public async Task ParameterlessAsyncHeaderReadPopulatesReadableBuffer()
+ {
+ const int expected = 42;
+ byte[] message;
+ using (var serializer = new c(3))
+ {
+ message = serializer.Serialize(1, expected);
+ }
+
+ using (var stream = new MemoryStream(message))
+ using (var connection = new TestConnection(stream))
+ {
+ await connection.k0Async();
+
+ Assert.AreEqual(expected, connection.ExposedReadObject());
+ }
+ }
+
+ [TestCase(1)]
+ [TestCase(2)]
+ public async Task ParameterlessAsyncMessageWritesExpectedMessageType(int messageType)
+ {
+ const string expected = "payload";
+ using (var stream = new MemoryStream())
+ using (var connection = new c(stream))
+ {
+ if (messageType == 1)
+ {
+ await connection.knAsync(expected);
+ }
+ else
+ {
+ await connection.krAsync(expected);
+ }
+
+ byte[] message = stream.ToArray();
+ Assert.AreEqual(messageType, message[1]);
+ Assert.AreEqual(expected, connection.Deserialize(message));
+ }
+ }
+
+ [Test]
+ public async Task ProtectedParameterlessWriteAsyncWritesRequestedBytes()
+ {
+ byte[] expected = { 1, 2, 3, 4 };
+ using (var stream = new MemoryStream())
+ using (var connection = new TestConnection(stream))
+ {
+ await connection.ExposedWriteAsync(expected, expected.Length);
+
+ Assert.IsTrue(expected.SequenceEqual(stream.ToArray()));
+ }
+ }
+
+ private sealed class TestConnection : c
+ {
+ internal TestConnection()
+ {
+ }
+
+ internal TestConnection(Stream stream)
+ : base(stream)
+ {
+ }
+
+ internal byte[] ExposedReadBuffer => ReadBuffer;
+
+ internal int ExposedReadPosition
+ {
+ get => ReadPosition;
+ set => ReadPosition = value;
+ }
+
+ internal bool ExposedIsLittleEndian => IsLittleEndian;
+
+ internal object ExposedReadObject()
+ {
+ return ReadObject();
+ }
+
+ internal Task ExposedWriteAsync(byte[] bytes, int number)
+ {
+ return WriteAsync(bytes, number);
+ }
+ }
}
}
diff --git a/kx.Test/Connection/KExceptionTests.cs b/kx.Test/Connection/KExceptionTests.cs
new file mode 100644
index 0000000..d2f5c30
--- /dev/null
+++ b/kx.Test/Connection/KExceptionTests.cs
@@ -0,0 +1,40 @@
+using System;
+using NUnit.Framework;
+
+namespace kx.Test.Connection
+{
+ [TestFixture]
+ public class KExceptionTests
+ {
+ [Test]
+ public void DefaultConstructorCreatesExceptionWithDefaultMessage()
+ {
+ var exception = new KException();
+
+ Assert.IsNull(exception.InnerException);
+ Assert.IsNotEmpty(exception.Message);
+ }
+
+ [Test]
+ public void MessageConstructorPreservesMessage()
+ {
+ const string expected = "kdb error";
+
+ var exception = new KException(expected);
+
+ Assert.AreEqual(expected, exception.Message);
+ }
+
+ [Test]
+ public void InnerExceptionConstructorPreservesMessageAndCause()
+ {
+ const string expected = "serialization failed";
+ var cause = new InvalidOperationException("cause");
+
+ var exception = new KException(expected, cause);
+
+ Assert.AreEqual(expected, exception.Message);
+ Assert.AreSame(cause, exception.InnerException);
+ }
+ }
+}
diff --git a/kx/c.cs b/kx/c.cs
index a8db7a8..ddb47d1 100644
--- a/kx/c.cs
+++ b/kx/c.cs
@@ -369,6 +369,7 @@ public c(
///
protected c()
{
+ _maxBufferSize = DefaultMaxBufferSize;
_versionNumber = 3;
}
@@ -382,6 +383,7 @@ protected c()
///
internal c(int versionNumber)
{
+ _maxBufferSize = DefaultMaxBufferSize;
_versionNumber = versionNumber;
}
@@ -411,6 +413,7 @@ internal c(Stream clientStream)
internal c(Stream clientStream, int versionNumber)
{
_clientStream = clientStream;
+ _maxBufferSize = DefaultMaxBufferSize;
_versionNumber = versionNumber;
}