diff --git a/YamlDotNet.Test/Serialization/SerializationTests.cs b/YamlDotNet.Test/Serialization/SerializationTests.cs index 20b822116..b18acd650 100644 --- a/YamlDotNet.Test/Serialization/SerializationTests.cs +++ b/YamlDotNet.Test/Serialization/SerializationTests.cs @@ -31,6 +31,7 @@ using System.IO; using System.Linq; using System.Reflection; +using System.Text; using System.Text.RegularExpressions; using Xunit; using YamlDotNet.Core; @@ -1968,6 +1969,84 @@ public void ShouldIndentSequences() Assert.Equal(expected.NormalizeNewLines(), yaml.NormalizeNewLines().TrimNewLines()); } + public class CycleTestEntity + { + public CycleTestEntity Cycle { get; set; } + } + + [Fact] + public void SerializeCycleWithAlias() + { + var sut = new SerializerBuilder() + .WithTagMapping("!CycleTag", typeof(CycleTestEntity)) + .Build(); + + var entity = new CycleTestEntity(); + entity.Cycle = entity; + var yaml = sut.Serialize(entity); + var expected = Yaml.Text(@"&o0 !CycleTag +Cycle: *o0"); + + Assert.Equal(expected.NormalizeNewLines(), yaml.NormalizeNewLines().TrimNewLines()); + } + + [Fact] + public void DeserializeCycleWithAlias() + { + var sut = new DeserializerBuilder() + .WithTagMapping("!CycleTag", typeof(CycleTestEntity)) + .Build(); + + var yaml = Yaml.Text(@"&o0 !CycleTag +Cycle: *o0"); + var obj = sut.Deserialize(yaml); + + Assert.Same(obj, obj.Cycle); + } + + [Fact] + public void DeserializeCycleWithoutAlias() + { + var sut = new DeserializerBuilder() + .Build(); + + var yaml = Yaml.Text(@"&o0 +Cycle: *o0"); + var obj = sut.Deserialize(yaml); + + Assert.Same(obj, obj.Cycle); + } + + public static IEnumerable Depths => Enumerable.Range(1, 10).Select(i => new[] { (object)i }); + + [Theory] + [MemberData(nameof(Depths))] + public void DeserializeCycleWithAnchorsWithDepth(int? depth) + { + var sut = new DeserializerBuilder() + .WithTagMapping("!CycleTag", typeof(CycleTestEntity)) + .Build(); + + StringBuilder builder = new StringBuilder(@"&o0 !CycleTag"); + builder.AppendLine(); + string indentation; + for (int i = 0; i < depth - 1; ++i) + { + indentation = string.Concat(Enumerable.Repeat(" ", i)); + builder.AppendLine($"{indentation}Cycle: !CycleTag"); + } + indentation = string.Concat(Enumerable.Repeat(" ", depth.Value - 1)); + builder.AppendLine($"{indentation}Cycle: *o0"); + var yaml = Yaml.Text(builder.ToString()); + var obj = sut.Deserialize(yaml); + CycleTestEntity iterator = obj; + for (int i = 0; i < depth; ++i) + { + iterator = iterator.Cycle; + } + Assert.Same(obj, iterator); + } + [TypeConverter(typeof(DoublyConvertedTypeConverter))] public class DoublyConverted { diff --git a/YamlDotNet/Serialization/ValueDeserializers/AliasValueDeserializer.cs b/YamlDotNet/Serialization/ValueDeserializers/AliasValueDeserializer.cs index da731a729..6e9a87e88 100644 --- a/YamlDotNet/Serialization/ValueDeserializers/AliasValueDeserializer.cs +++ b/YamlDotNet/Serialization/ValueDeserializers/AliasValueDeserializer.cs @@ -114,6 +114,11 @@ public object? Value if (parser.Accept(out var nodeEvent) && !nodeEvent.Anchor.IsEmpty) { anchor = nodeEvent.Anchor; + var aliasState = state.Get(); + if (!aliasState.ContainsKey(anchor)) + { + aliasState[anchor] = new ValuePromise(new AnchorAlias(anchor)); + } } value = innerDeserializer.DeserializeValue(parser, expectedType, state, nestedObjectDeserializer);