Skip to content

Commit 2689ee0

Browse files
authored
Merge pull request #251 from riscv-software-src/mref-fix
Fix recursive $mref
2 parents 7f140b4 + 4e437de commit 2689ee0

File tree

2 files changed

+184
-7
lines changed

2 files changed

+184
-7
lines changed

lib/test/test_yaml_loader.rb

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
require "minitest/autorun"
23

34
$root ||= (Pathname.new(__FILE__) / ".." / ".." ).realpath
@@ -6,6 +7,163 @@
67

78
class TestYamlLoader < Minitest::Test
89

10+
def test_that_mref_with_nested_replace_works
11+
yaml = <<~YAML
12+
base:
13+
key1:
14+
sub_key1: value1
15+
key2: value2
16+
17+
middle:
18+
$mref: "#/base"
19+
key3: value3
20+
key4: value4
21+
22+
bottom:
23+
$mref:
24+
- "#/base"
25+
- "#/middle"
26+
key1:
27+
sub_key6: value6
28+
key2: value2_new
29+
key4: value4_new
30+
key5: value5
31+
YAML
32+
33+
f = Tempfile.new("yml")
34+
f.write(yaml)
35+
f.flush
36+
37+
doc = YamlLoader.load(f.path)
38+
assert_equal({ "key1" => {"sub_key1" => "value1", "sub_key6" => "value6"}, "key2" => "value2_new", "key3" => "value3", "key4" => "value4_new", "key5" => "value5" }, doc["bottom"])
39+
end
40+
41+
def test_that_spurious_recursive_mref_works
42+
yaml = <<~YAML
43+
base:
44+
key1: value1
45+
key2: value2
46+
47+
middle:
48+
$mref: "#/base"
49+
key3: value3
50+
key4: value4
51+
52+
bottom:
53+
$mref:
54+
- "#/base"
55+
- "#/middle"
56+
key2: value2_new
57+
key4: value4_new
58+
key5: value5
59+
YAML
60+
61+
f = Tempfile.new("yml")
62+
f.write(yaml)
63+
f.flush
64+
65+
doc = YamlLoader.load(f.path)
66+
assert_equal({ "key1" => "value1", "key2" => "value2", "key3" => "value3", "key4" => "value4" }, doc["middle"])
67+
assert_equal({ "key1" => "value1", "key2" => "value2_new", "key3" => "value3", "key4" => "value4_new", "key5" => "value5" }, doc["bottom"])
68+
end
69+
70+
def test_that_recursive_mref_works
71+
yaml = <<~YAML
72+
base:
73+
key1: value1
74+
key2: value2
75+
76+
middle:
77+
$mref: "#/base"
78+
key3: value3
79+
key4: value4
80+
81+
bottom:
82+
$mref: "#/middle"
83+
key2: value2_new
84+
key4: value4_new
85+
key5: value5
86+
YAML
87+
88+
f = Tempfile.new("yml")
89+
f.write(yaml)
90+
f.flush
91+
92+
doc = YamlLoader.load(f.path)
93+
assert_equal({ "key1" => "value1", "key2" => "value2", "key3" => "value3", "key4" => "value4" }, doc["middle"])
94+
assert_equal({ "key1" => "value1", "key2" => "value2_new", "key3" => "value3", "key4" => "value4_new", "key5" => "value5" }, doc["bottom"])
95+
end
96+
97+
def test_that_nested_mref_works
98+
yaml = <<~YAML
99+
top:
100+
base:
101+
key1: value1
102+
key2: value2
103+
key3: value3
104+
105+
bottom:
106+
child:
107+
$mref: "#/top/base"
108+
key3: value3_new
109+
YAML
110+
111+
f = Tempfile.new("yml")
112+
f.write(yaml)
113+
f.flush
114+
115+
doc = YamlLoader.load(f.path)
116+
assert_equal({ "key1" => "value1", "key2" => "value2", "key3" => "value3_new" }, doc["bottom"]["child"])
117+
end
118+
119+
def test_that_mref_doesnt_delete_keys
120+
yaml = <<~YAML
121+
base:
122+
key1: value1
123+
key2: value2
124+
key3: value3
125+
126+
child:
127+
$mref: "#/base"
128+
key3: value3_new
129+
YAML
130+
131+
f = Tempfile.new("yml")
132+
f.write(yaml)
133+
f.flush
134+
135+
doc = YamlLoader.load(f.path)
136+
assert_equal({ "key1" => "value1", "key2" => "value2", "key3" => "value3_new" }, doc["child"])
137+
end
138+
139+
def test_that_double_mref_doesnt_delete_keys
140+
yaml = <<~YAML
141+
base1:
142+
key1: value1
143+
key2: value2
144+
key3: value3
145+
146+
base2:
147+
key4: value4
148+
key5: value5
149+
key6: value6
150+
151+
child:
152+
$mref:
153+
- "#/base1"
154+
- "#/base2"
155+
key3: value3_new
156+
key6: value6_new
157+
YAML
158+
159+
f = Tempfile.new("yml")
160+
f.write(yaml)
161+
f.flush
162+
163+
doc = YamlLoader.load(f.path)
164+
assert_equal({ "key1" => "value1", "key2" => "value2", "key3" => "value3_new", "key4" => "value4", "key5" => "value5", "key6" => "value6_new" }, doc["child"])
165+
end
166+
9167
def test_refs_in_the_same_document
10168
yaml = <<~YAML
11169
$defs:

lib/yaml_loader.rb

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,19 +72,38 @@ def self.expand(filename, obj, yaml_opts = {})
7272
raise DereferenceError, "JSON Path #{mref_target.split('#')[1]} does not exist in #{relative_path}"
7373
end
7474

75+
target_obj = expand(filename, target_obj, yaml_opts)
7576
target_obj.each do |target_key, target_value|
76-
new_obj[target_key] = expand(filename, target_value, yaml_opts)
77+
if (new_obj[target_key].is_a?(Hash))
78+
raise "Should be a hash" unless target_value.is_a?(Hash)
79+
new_obj[target_key] = target_value.merge(new_obj[target_key])
80+
else
81+
new_obj[target_key] = target_value
82+
end
7783
end
7884
end
7985

8086
obj.delete("$mref")
81-
obj_keys = obj.keys
82-
obj_keys.each do |key|
83-
value = obj[key]
84-
85-
new_obj[key] = expand(filename, value, yaml_opts)
87+
# now merge target_obj and obj
88+
keys = (obj.keys + new_obj.keys).uniq
89+
final_obj = {}
90+
keys.each do |key|
91+
if !obj.key?(key)
92+
final_obj[key] = new_obj[key]
93+
elsif !new_obj.key?(key)
94+
final_obj[key] = expand(filename, obj[key], yaml_opts)
95+
else
96+
value = obj[key]
97+
98+
if new_obj[key].is_a?(Hash)
99+
raise "should be a hash" unless new_obj[key].is_a?(Hash)
100+
final_obj[key] = new_obj[key].merge(obj[key])
101+
else
102+
final_obj[key] = expand(filename, obj[key], yaml_opts)
103+
end
104+
end
86105
end
87-
new_obj
106+
final_obj
88107
else
89108
obj_keys = obj.keys
90109
obj_keys.each do |key|

0 commit comments

Comments
 (0)