Skip to content

Commit 277264a

Browse files
Lucas Michonotsenkun
authored andcommitted
Handle merge references correctly
1 parent 9bc7f1a commit 277264a

File tree

2 files changed

+80
-1
lines changed

2 files changed

+80
-1
lines changed

src/NetEscapades.Configuration.Yaml/YamlConfigurationFileParser.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace NetEscapades.Configuration.Yaml
1010
internal class YamlConfigurationFileParser
1111
{
1212
private readonly IDictionary<string, string> _data = new SortedDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
13+
private readonly HashSet<string> _mergedKeys = new HashSet<string>();
1314
private readonly Stack<string> _context = new Stack<string>();
1415
private string _currentPath;
1516

@@ -61,7 +62,13 @@ private void VisitYamlScalarNode(string context, YamlScalarNode yamlValue)
6162
EnterContext(context);
6263
var currentKey = _currentPath;
6364

64-
if (_data.ContainsKey(currentKey))
65+
if (currentKey.Contains("<<"))
66+
{
67+
currentKey = currentKey.Replace("<<:", "");
68+
_mergedKeys.Add(currentKey);
69+
}
70+
71+
if (_data.ContainsKey(currentKey) && !_mergedKeys.Contains(currentKey))
6572
{
6673
throw new FormatException(Resources.FormatError_KeyIsDuplicated(currentKey));
6774
}

test/NetEscapades.Configuration.Yaml.Tests/YamlConfigurationTests.cs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,78 @@ public void ReturnEmptyConfigWhenFileIsEmpty()
151151
Assert.Empty(config.AsEnumerable());
152152
}
153153

154+
[Fact]
155+
public void ShouldMergeKeysInsideAnObject()
156+
{
157+
var yaml = @"---
158+
defaults: &defaults
159+
A: 1
160+
B: 2
161+
D:
162+
E: 78
163+
F: 79
164+
mapping:
165+
<< : *defaults
166+
A: 23
167+
C: 99
168+
D:
169+
E: 56
170+
G:
171+
- 1
172+
- 2";
173+
174+
var yamlConfigSrc = LoadProvider(yaml);
175+
176+
Assert.Equal("23", yamlConfigSrc.Get("mapping:A"));
177+
Assert.Equal("2", yamlConfigSrc.Get("mapping:B"));
178+
Assert.Equal("99", yamlConfigSrc.Get("mapping:C"));
179+
Assert.Equal("56", yamlConfigSrc.Get("mapping:D:E"));
180+
Assert.Equal("79", yamlConfigSrc.Get("mapping:D:F"));
181+
Assert.Equal("1", yamlConfigSrc.Get("mapping:D:G:0"));
182+
Assert.Equal("2", yamlConfigSrc.Get("mapping:D:G:1"));
183+
}
184+
185+
[Fact]
186+
public void ShouldMergeKeysInsideASequence()
187+
{
188+
var yaml = @"---
189+
defaults: &defaults
190+
A: 1
191+
B: 2
192+
D:
193+
E: 78
194+
F: 79
195+
mapping:
196+
- <<: *defaults
197+
A: 23
198+
C: 99
199+
- A: 2
200+
B: 3
201+
D:
202+
E: 4
203+
F: 5
204+
- <<: *defaults";
205+
206+
var yamlConfigSrc = LoadProvider(yaml);
207+
208+
Assert.Equal("23", yamlConfigSrc.Get("mapping:0:A"));
209+
Assert.Equal("2", yamlConfigSrc.Get("mapping:0:B"));
210+
Assert.Equal("99", yamlConfigSrc.Get("mapping:0:C"));
211+
Assert.Equal("78", yamlConfigSrc.Get("mapping:0:D:E"));
212+
Assert.Equal("79", yamlConfigSrc.Get("mapping:0:D:F"));
213+
214+
Assert.Equal("2", yamlConfigSrc.Get("mapping:1:A"));
215+
Assert.Equal("3", yamlConfigSrc.Get("mapping:1:B"));
216+
Assert.Throws<InvalidOperationException>(() => yamlConfigSrc.Get("mapping:1:C"));
217+
Assert.Equal("4", yamlConfigSrc.Get("mapping:1:D:E"));
218+
Assert.Equal("5", yamlConfigSrc.Get("mapping:1:D:F"));
219+
220+
Assert.Equal("1", yamlConfigSrc.Get("mapping:2:A"));
221+
Assert.Equal("2", yamlConfigSrc.Get("mapping:2:B"));
222+
Assert.Equal("78", yamlConfigSrc.Get("mapping:2:D:E"));
223+
Assert.Equal("79", yamlConfigSrc.Get("mapping:2:D:F"));
224+
}
225+
154226
[Fact]
155227
public void ThrowExceptionWhenUnexpectedFirstCharacterInScalarValue()
156228
{

0 commit comments

Comments
 (0)