|
5 | 5 | using IO.Ably.MessageEncoders; |
6 | 6 | using IO.Ably.Types; |
7 | 7 | using MessagePack; |
| 8 | +using Newtonsoft.Json; |
| 9 | +using Newtonsoft.Json.Linq; |
8 | 10 | using Xunit; |
9 | 11 | using Xunit.Abstractions; |
10 | 12 |
|
@@ -606,6 +608,118 @@ private static byte[] SerializeString(string str) |
606 | 608 | return bytes.ToArray(); |
607 | 609 | } |
608 | 610 |
|
| 611 | + /// <summary> |
| 612 | + /// Test fixture class for msgpack test data. |
| 613 | + /// </summary> |
| 614 | + public class MsgpackTestFixture |
| 615 | + { |
| 616 | + [JsonProperty("name")] |
| 617 | + public string Name { get; set; } |
| 618 | + |
| 619 | + [JsonProperty("data")] |
| 620 | + public object Data { get; set; } |
| 621 | + |
| 622 | + [JsonProperty("encoding")] |
| 623 | + public string Encoding { get; set; } |
| 624 | + |
| 625 | + [JsonProperty("numRepeat")] |
| 626 | + public int NumRepeat { get; set; } |
| 627 | + |
| 628 | + [JsonProperty("type")] |
| 629 | + public string Type { get; set; } |
| 630 | + |
| 631 | + [JsonProperty("msgpack")] |
| 632 | + public string MsgPack { get; set; } |
| 633 | + } |
| 634 | + |
| 635 | + /// <summary> |
| 636 | + /// Loads msgpack test fixtures from the embedded resource. |
| 637 | + /// </summary> |
| 638 | + private static List<MsgpackTestFixture> LoadMsgpackFixtures() |
| 639 | + { |
| 640 | + var json = ResourceHelper.GetResource("msgpack_test_fixtures.json"); |
| 641 | + return JsonConvert.DeserializeObject<List<MsgpackTestFixture>>(json); |
| 642 | + } |
| 643 | + |
| 644 | + /// <summary> |
| 645 | + /// Provides test data for msgpack decoding tests. |
| 646 | + /// Each test case is named after the fixture name for better test reporting. |
| 647 | + /// </summary> |
| 648 | + public static IEnumerable<object[]> MsgpackDecodingFixtures |
| 649 | + { |
| 650 | + get |
| 651 | + { |
| 652 | + var fixtures = LoadMsgpackFixtures(); |
| 653 | + foreach (var fixture in fixtures) |
| 654 | + { |
| 655 | + // Pass fixture.Name as first parameter for better test display names |
| 656 | + yield return new object[] { fixture.Name, fixture }; |
| 657 | + } |
| 658 | + } |
| 659 | + } |
| 660 | + |
| 661 | + [Theory] |
| 662 | + [MemberData(nameof(MsgpackDecodingFixtures))] |
| 663 | + public void TestMsgpackDecoding(string testName, MsgpackTestFixture fixture) |
| 664 | + { |
| 665 | + Output.WriteLine($"Testing: {testName}"); |
| 666 | + |
| 667 | + // Decode base64 msgpack data |
| 668 | + var msgpackData = Convert.FromBase64String(fixture.MsgPack); |
| 669 | + |
| 670 | + // Deserialize to ProtocolMessage |
| 671 | + var protoMsg = MsgPackHelper.Deserialise<ProtocolMessage>(msgpackData); |
| 672 | + protoMsg.Should().NotBeNull(); |
| 673 | + protoMsg.Messages.Should().NotBeNull(); |
| 674 | + protoMsg.Messages.Should().HaveCount(1); |
| 675 | + |
| 676 | + var msg = protoMsg.Messages[0]; |
| 677 | + |
| 678 | + // Decode the message data using FromEncoded |
| 679 | + var decodedMsg = Message.FromEncoded(msg); |
| 680 | + |
| 681 | + // Verify decoded data based on type |
| 682 | + switch (fixture.Type) |
| 683 | + { |
| 684 | + case "string": |
| 685 | + decodedMsg.Data.Should().BeOfType<string>(); |
| 686 | + var expectedString = string.Concat(Enumerable.Repeat(fixture.Data.ToString(), fixture.NumRepeat)); |
| 687 | + decodedMsg.Data.Should().Be(expectedString); |
| 688 | + (decodedMsg.Data as string).Length.Should().Be(fixture.NumRepeat); |
| 689 | + break; |
| 690 | + |
| 691 | + case "binary": |
| 692 | + decodedMsg.Data.Should().BeOfType<byte[]>(); |
| 693 | + var expectedBytes = System.Text.Encoding.UTF8.GetBytes( |
| 694 | + string.Concat(Enumerable.Repeat(fixture.Data.ToString(), fixture.NumRepeat))); |
| 695 | + (decodedMsg.Data as byte[]).Should().Equal(expectedBytes); |
| 696 | + (decodedMsg.Data as byte[]).Length.Should().Be(fixture.NumRepeat); |
| 697 | + break; |
| 698 | + |
| 699 | + case "jsonObject": |
| 700 | + // For JSON objects, compare as JToken for proper equality |
| 701 | + var expectedJson = JsonConvert.SerializeObject(fixture.Data); |
| 702 | + var actualJson = JsonConvert.SerializeObject(decodedMsg.Data); |
| 703 | + JToken.DeepEquals(JToken.Parse(expectedJson), JToken.Parse(actualJson)).Should().BeTrue(); |
| 704 | + break; |
| 705 | + |
| 706 | + case "jsonArray": |
| 707 | + // For JSON arrays, compare as JToken for proper equality |
| 708 | + var expectedArrayJson = JsonConvert.SerializeObject(fixture.Data); |
| 709 | + var actualArrayJson = JsonConvert.SerializeObject(decodedMsg.Data); |
| 710 | + JToken.DeepEquals(JToken.Parse(expectedArrayJson), JToken.Parse(actualArrayJson)).Should().BeTrue(); |
| 711 | + break; |
| 712 | + |
| 713 | + default: |
| 714 | + throw new InvalidOperationException($"Unknown fixture type: {fixture.Type}"); |
| 715 | + } |
| 716 | + |
| 717 | + // TODO: Re-encode the message and verify it matches the original |
| 718 | + // Create a new message with the decoded data and encode it |
| 719 | + // Similar to `TestMsgpackDecoding` test in `proto_message_decoding_test.go` |
| 720 | + // This will need omitting keys for null values, current serializer omits keys with nulls. |
| 721 | + } |
| 722 | + |
609 | 723 | public MsgPackMessageSerializerTests(ITestOutputHelper output) |
610 | 724 | : base(output) |
611 | 725 | { |
|
0 commit comments