-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGrpcPredicateMatcher.cs
More file actions
68 lines (56 loc) · 2.24 KB
/
Copy pathGrpcPredicateMatcher.cs
File metadata and controls
68 lines (56 loc) · 2.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
using System.Buffers.Binary;
using Google.Protobuf;
using WireMock.Matchers;
namespace WireMock.Net.Google.Protobuf.Request.Matchers;
/// <summary>
/// The <see cref="IObjectMatcher"/> that tests whether the incoming grpc message satisfies the predicate
/// </summary>
/// <param name="predicate">Boolean function to test whether the incoming grpc message satisfies a mapping</param>
/// <param name="matchBehaviour">The match behavior, default is <see cref="MatchBehaviour.AcceptOnMatch"/></param>
/// <typeparam name="TMessage">Proto compiled implementation of <see cref="IMessage{TMessage}"/></typeparam>
internal sealed class GrpcPredicateMatcher<TMessage>(
Func<TMessage, bool> predicate,
MatchBehaviour matchBehaviour) : IObjectMatcher
where TMessage : IMessage<TMessage>, new()
{
private static readonly TMessage Empty = new();
private static readonly MessageParser<TMessage> Parser = new(() => new());
/// <inheritdoc />
public MatchResult IsMatch(object? input)
{
if (input is not byte[] inputBytes)
return MatchResult.From(Name);
try
{
return MatchResult.From(
Name,
MatchBehaviour,
IsPredicateMatch(inputBytes));
}
catch (Exception e)
{
return MatchResult.From(Name, exception: e);
}
}
private bool IsPredicateMatch(byte[] inputBytes)
{
const int compressionFlagIndex = 0;
const int headerLength = 5;
if (inputBytes[compressionFlagIndex] != 0)
return false;
var sizeHeader = new ReadOnlySpan<byte>(inputBytes, 1, 4);
var length = BinaryPrimitives.ReadUInt32BigEndian(sizeHeader);
if (inputBytes.Length - headerLength < length)
return false;
var inputMessage = Parser.ParseFrom(new ReadOnlySpan<byte>(inputBytes, headerLength, (int)length));
return predicate.Invoke(inputMessage);
}
/// <inheritdoc />
public object Value => Empty;
/// <inheritdoc />
public string GetCSharpCodeArguments() => "NotImplemented";
/// <inheritdoc />
public string Name => nameof(GrpcPredicateMatcher<>);
/// <inheritdoc />
public MatchBehaviour MatchBehaviour => matchBehaviour;
}