Skip to content

Commit

Permalink
Improve code coverage on Messages and fix a few bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
Seddryck committed Sep 2, 2023
1 parent 4e85aa0 commit 101667a
Show file tree
Hide file tree
Showing 24 changed files with 628 additions and 134 deletions.
1 change: 1 addition & 0 deletions Pgnoli.Testing/Messages/Backend/BackendParserTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ private class StubContext : IMessageContext
[TestCase("Backend.Query.CloseComplete.Default", typeof(CloseComplete))]
[TestCase("Backend.Query.CommandComplete.SelectRowCount", typeof(CommandComplete))]
[TestCase("Backend.Query.DataRow.SingleInt", typeof(DataRow))]
[TestCase("Backend.Query.ErrorResponse.Default", typeof(ErrorResponse))]
[TestCase("Backend.Query.ParseComplete.Default", typeof(ParseComplete))]
[TestCase("Backend.Query.RowDescription.SingleInt", typeof(RowDescription))]
public void Parse(string msgPath, Type expected)
Expand Down
19 changes: 16 additions & 3 deletions Pgnoli.Testing/Messages/Backend/Query/CommandCompleteTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,29 @@ namespace Pgnoli.Testing.Messages.Backend.Query
{
public class CommandCompleteTest
{
private static CommandComplete.CommandCompleteBuilder[] BuilderCases
=> new[]
{
CommandComplete.Select(1978),
CommandComplete.Delete(1978),
CommandComplete.Merge(1978),
CommandComplete.Move(1978),
CommandComplete.Update(1978),
CommandComplete.Fetch(1978),
CommandComplete.Copy(1978),
};

[Test]
public void Roundtrip_SelectRowCount_Success()
[TestCaseSource(nameof(BuilderCases))]
public void Roundtrip_SelectRowCount_Success(CommandComplete.CommandCompleteBuilder builder)
{
var msg = CommandComplete.Select(1978).Build();
var msg = builder.Build();
Assert.That(msg.Payload.RowCount, Is.EqualTo(1978));

var bytes = msg.GetBytes();
Assert.That(bytes, Is.Not.Null);
Assert.That(bytes, Has.Length.GreaterThan(0));
Assert.That(bytes[0], Is.GreaterThanOrEqualTo('A').And.LessThanOrEqualTo('Z'));
Assert.That(bytes[0], Is.EqualTo('C'));

var roundtrip = new CommandComplete(bytes);
Assert.DoesNotThrow(() => roundtrip.Read());
Expand Down
68 changes: 68 additions & 0 deletions Pgnoli.Testing/Messages/Backend/Query/ErrorResponseTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using Pgnoli.Messages;
using Pgnoli.Messages.Backend.Query;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Pgnoli.Testing.Messages.Backend.Query
{
public class ErrorResponseTest
{
[Test]
public void Roundtrip_Ok_Success()
{
var msg = ErrorResponse.Warning("SQL00001", "!Oups!").With('q', "SELECT @@version").Build();
var bytes = msg.GetBytes();
Assert.That(bytes, Is.Not.Null);
Assert.Multiple(() =>
{
Assert.That(bytes, Has.Length.EqualTo(51));
Assert.That(bytes[0], Is.EqualTo('E'));
Assert.That(bytes[50], Is.EqualTo(0));
});

var roundtrip = new ErrorResponse(bytes);
Assert.DoesNotThrow(() => roundtrip.Read());
Assert.Multiple(() =>
{
Assert.That(roundtrip.Payload.Severity, Is.EqualTo(msg.Payload.Severity));
Assert.That(roundtrip.Payload.SqlState, Is.EqualTo(msg.Payload.SqlState));
Assert.That(roundtrip.Payload.Message, Is.EqualTo(msg.Payload.Message));
Assert.That(roundtrip.Payload.OptionalMessages, Has.Count.EqualTo(msg.Payload.OptionalMessages.Count));
foreach (var option in roundtrip.Payload.OptionalMessages)
{
Assert.That(msg.Payload.OptionalMessages.ContainsKey(option.Key), Is.True);
Assert.That(roundtrip.Payload.OptionalMessages[option.Key], Is.EqualTo(msg.Payload.OptionalMessages[option.Key]));
}
});
}

[Test]
public void Write_Default_Success()
{
var msg = ErrorResponse.Warning("SQL00001", "!Oups!").With('q', "SELECT @@version").Build();

var bytes = msg.GetBytes();

var reader = new ResourceBytesReader();
Assert.That(bytes, Is.EqualTo(reader.Read("Backend.Query.ErrorResponse.Default")));
}

[Test]
public void Read_Default_Success()
{
var reader = new ResourceBytesReader();
var bytes = reader.Read("Backend.Query.ErrorResponse.Default");
var msg = new ErrorResponse(bytes);

Assert.DoesNotThrow(() => msg.Read());
Assert.That(msg.Payload.Severity, Is.EqualTo(ErrorSeverity.Warning));
Assert.That(msg.Payload.SqlState, Is.EqualTo("SQL00001"));
Assert.That(msg.Payload.Message, Is.EqualTo("!Oups!"));
Assert.That(msg.Payload.OptionalMessages.ContainsKey('q'), Is.True);
Assert.That(msg.Payload.OptionalMessages['q'], Is.EqualTo("SELECT @@version"));
}
}
}
74 changes: 74 additions & 0 deletions Pgnoli.Testing/Messages/CodeMessageTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using Pgnoli.Messages;
using Pgnoli.Messages.Backend.Handshake;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;

namespace Pgnoli.Testing.Messages
{
public class CodeMessageTest
{
private class StubMessage : CodeMessage
{
public const char Code = '=';

public StubMessage(byte[] bytes)
: base(Code, bytes) { }

protected override int GetPayloadLength() => 0;
protected internal override void ReadPayload(Buffer buffer) { }
protected internal override void WritePayload(Buffer buffer) { }
}

private class StubBrokenMessage : StubMessage
{
public StubBrokenMessage(byte[] bytes)
: base(bytes) { }

protected override int GetPayloadLength() => 1;
}

[Test]
public void Read_ValidBytes_DoesNotThrow()
{
var bytes = new Byte[] { Convert.ToByte(StubMessage.Code), 0, 0, 0, 4 };
var msg = new StubMessage(bytes);
Assert.DoesNotThrow(() => msg.Read());
}

[Test]
public void Read_UnexpectedCode_Throws()
{
var bytes = new Byte[] { (byte)(Convert.ToByte(StubMessage.Code)-1), 0, 0, 0, 4 };
var msg = new StubMessage(bytes);
Assert.Throws<MessageUnexpectedCodeException>(() => msg.Read());
}

[Test]
public void Read_UnexpectedLength_Throws()
{
var bytes = new Byte[] { Convert.ToByte(StubMessage.Code), 0, 0, 0, 20 };
var msg = new StubMessage(bytes);
Assert.Throws<MessageUnexpectedLengthException>(() => msg.Read());
}

[Test]
public void Read_MessageNotFullyConsumedException_Throws()
{
var bytes = new Byte[] { Convert.ToByte(StubMessage.Code), 0, 0, 0, 5, 1 };
var msg = new StubBrokenMessage(bytes);
Assert.Throws<MessageNotFullyConsumedException>(() => msg.Read());
}

[Test]
public void Read_EmptyBuffer_Throws()
{
var bytes = Array.Empty<byte>();
var msg = new StubMessage(bytes);
Assert.Throws<BufferEmptyException>(() => msg.Read());
}
}
}
36 changes: 36 additions & 0 deletions Pgnoli.Testing/Messages/Frontend/FrontendParserTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Pgnoli.Options.DateStyles;
using Pgnoli.Messages;
using Pgnoli.Messages.Frontend;
using Pgnoli.Messages.Frontend.Query;
using Pgnoli.Types.TypeHandlers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Threading.Tasks;

namespace Pgnoli.Testing.Messages.Frontend
{
public class FrontendParserTest
{
[Test]
[TestCase("Frontend.Query.Bind.UnnamedPortal", typeof(Bind))]
[TestCase("Frontend.Query.Close.UnnamedPortal", typeof(Close))]
[TestCase("Frontend.Query.Describe.UnnamedPortal", typeof(Describe))]
[TestCase("Frontend.Query.Execute.UnnamedPortal", typeof(Execute))]
[TestCase("Frontend.Query.Query.To_timestamp", typeof(Pgnoli.Messages.Frontend.Query.Query))]
[TestCase("Frontend.Query.Parse.To_timestamp", typeof(Parse))]
[TestCase("Frontend.Query.Sync.Default", typeof(Sync))]
public void Parse(string msgPath, Type expected)
{
var reader = new ResourceBytesReader();
var bytes = reader.Read(msgPath);

var parser = new FrontendParser();
var msg = parser.Parse(bytes, 0, out var length);
Assert.That(msg, Is.TypeOf(expected));
Assert.That(length, Is.EqualTo(bytes.Length));
}
}
}
63 changes: 63 additions & 0 deletions Pgnoli.Testing/Messages/Frontend/Query/CloseTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Pgnoli.Messages.Frontend.Query;

namespace Pgnoli.Testing.Messages.Frontend.Query
{
public class CloseTest
{
[Test]
public void Write_Default_Success()
{
var msg = Close.UnnamedPortal.Build();
var bytes = msg.GetBytes();

var reader = new ResourceBytesReader();
Assert.That(bytes, Is.EqualTo(reader.Read("Frontend.Query.Close.UnnamedPortal")));
}

[Test]
public void Read_UnnamedPortal_Success()
{
var reader = new ResourceBytesReader();
var bytes = reader.Read("Frontend.Query.Close.UnnamedPortal");
var msg = new Close(bytes);

Assert.DoesNotThrow(() => msg.Read());
Assert.That(msg.Payload.PortalType, Is.EqualTo(PortalType.Portal));
Assert.That(msg.Payload.Name, Is.EqualTo(string.Empty));
}

private static Close.CloseBuilder[] BuilderCases
=> new[]
{
Close.Portal("the_name"),
Close.PreparedStatement("the_name"),
Close.UnnamedPortal,
Close.UnnamedPreparedStatement
};

[Test]
[TestCaseSource(nameof(BuilderCases))]
public void Roundtrip_Close_Success(Close.CloseBuilder builder)
{
var msg = builder.Build();

var bytes = msg.GetBytes();
Assert.That(bytes, Is.Not.Null);
Assert.That(bytes, Has.Length.GreaterThan(0));
Assert.That(bytes[0], Is.EqualTo('C'));

var roundtrip = new Close(bytes);
Assert.DoesNotThrow(() => roundtrip.Read());
Assert.Multiple(() =>
{
Assert.That(msg.Payload.Name, Is.EqualTo(roundtrip.Payload.Name));
Assert.That(msg.Payload.PortalType, Is.EqualTo(roundtrip.Payload.PortalType));
});
}
}
}
33 changes: 33 additions & 0 deletions Pgnoli.Testing/Messages/Frontend/Query/QueryTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FQ = Pgnoli.Messages.Frontend.Query;

namespace Pgnoli.Testing.Messages.Frontend.Query
{
public class QueryTest
{
[Test]
public void Write_To_timestamp_Success()
{
var msg = FQ.Query.Message("select to_timestamp('2022-12-10 15:18:16+7', 'YYYY-MM-DD HH24:MI:SSTZH')::timestamptz").Build();
var bytes = msg.GetBytes();

var reader = new ResourceBytesReader();
Assert.That(bytes, Is.EqualTo(reader.Read("Frontend.Query.Query.To_timestamp")));
}

[Test]
public void Read_To_timestamp_Success()
{
var reader = new ResourceBytesReader();
var bytes = reader.Read("Frontend.Query.Query.To_timestamp");
var msg = new FQ.Query(bytes);

Assert.DoesNotThrow(() => msg.Read());
Assert.That(msg.Payload.Sql, Is.Not.Null.And.Not.Empty);
}
}
}
6 changes: 6 additions & 0 deletions Pgnoli.Testing/Pgnoli.Testing.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@
<None Remove="Resources\Backend\Query\CommandComplete\SelectRowCount.txt" />
<None Remove="Resources\Backend\Query\BindComplete\Default.txt" />
<None Remove="Resources\Backend\Query\DataRow\SingleInt.txt" />
<None Remove="Resources\Backend\Query\ErrorResponse\Default.txt" />
<None Remove="Resources\Backend\Query\ParseComplete\Default.txt" />
<None Remove="Resources\Backend\Handshake\ParameterStatus\ClientEncoding.txt" />
<None Remove="Resources\Backend\Handshake\ReadyForQuery\Idle.txt" />
<None Remove="Resources\Backend\Query\RowDescription\SingleInt.txt" />
<None Remove="Resources\Frontend\Handshake\Terminate\Default.txt" />
<None Remove="Resources\Frontend\Query\Close\UnnamedPortal.txt" />
<None Remove="Resources\Frontend\Query\Bind\UnnamedPortal.txt" />
<None Remove="Resources\Frontend\Query\Describe\UnnamedPortal.txt" />
<None Remove="Resources\Frontend\Query\Execute\UnnamedPortal.txt" />
<None Remove="Resources\Frontend\Query\Query\To_timestamp.txt" />
<None Remove="Resources\Frontend\Query\Parse\To_timestamp.txt" />
<None Remove="Resources\Frontend\Handshake\Startup\Default.txt" />
<None Remove="Resources\Frontend\Query\Sync\Default.txt" />
Expand All @@ -23,13 +26,16 @@
<EmbeddedResource Include="Resources\Backend\Query\CommandComplete\SelectRowCount.txt" />
<EmbeddedResource Include="Resources\Backend\Query\BindComplete\Default.txt" />
<EmbeddedResource Include="Resources\Backend\Query\DataRow\SingleInt.txt" />
<EmbeddedResource Include="Resources\Backend\Query\ErrorResponse\Default.txt" />
<EmbeddedResource Include="Resources\Backend\Query\ParseComplete\Default.txt" />
<EmbeddedResource Include="Resources\Backend\Handshake\ParameterStatus\ClientEncoding.txt" />
<EmbeddedResource Include="Resources\Backend\Handshake\ReadyForQuery\Idle.txt" />
<EmbeddedResource Include="Resources\Backend\Query\RowDescription\SingleInt.txt" />
<EmbeddedResource Include="Resources\Frontend\Handshake\Terminate\Default.txt" />
<EmbeddedResource Include="Resources\Frontend\Query\Close\UnnamedPortal.txt" />
<EmbeddedResource Include="Resources\Frontend\Query\Bind\UnnamedPortal.txt" />
<EmbeddedResource Include="Resources\Frontend\Query\Describe\UnnamedPortal.txt" />
<EmbeddedResource Include="Resources\Frontend\Query\Query\To_timestamp.txt" />
<EmbeddedResource Include="Resources\Frontend\Query\Parse\To_timestamp.txt" />
<EmbeddedResource Include="Resources\Frontend\Handshake\Startup\Default.txt" />
<EmbeddedResource Include="Resources\Frontend\Query\Execute\UnnamedPortal.txt" />
Expand Down
Loading

0 comments on commit 101667a

Please sign in to comment.