modspec 0.1.4 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +4 -0
  3. data/.github/workflows/release.yml +5 -0
  4. data/.rubocop.yml +18 -6
  5. data/.rubocop_todo.yml +108 -76
  6. data/CLAUDE.md +61 -0
  7. data/Gemfile +4 -3
  8. data/lib/modspec/conformance_class.rb +4 -8
  9. data/lib/modspec/conformance_test.rb +19 -5
  10. data/lib/modspec/identifier.rb +0 -1
  11. data/lib/modspec/normative_statement.rb +3 -39
  12. data/lib/modspec/normative_statements_class.rb +3 -3
  13. data/lib/modspec/suite.rb +73 -82
  14. data/lib/modspec/version.rb +1 -1
  15. data/lib/modspec.rb +8 -22
  16. data/modspec.gemspec +3 -2
  17. data/spec/conformance_class.liquid +2 -2
  18. data/spec/fixtures/advanced-json-rc.yaml +5 -7
  19. data/spec/fixtures/advanced-rc.yaml +12 -14
  20. data/spec/fixtures/basic-quaternion-json-rc.yaml +5 -7
  21. data/spec/fixtures/basic-quaternion-json-strict-rc.yaml +4 -5
  22. data/spec/fixtures/basic-quaternion-rc.yaml +7 -8
  23. data/spec/fixtures/basic-ypr-json-rc.yaml +5 -8
  24. data/spec/fixtures/basic-ypr-rc.yaml +7 -7
  25. data/spec/fixtures/chain-json-rc.yaml +5 -7
  26. data/spec/fixtures/chain-rc.yaml +11 -13
  27. data/spec/fixtures/frame-spec-rc.yaml +10 -10
  28. data/spec/fixtures/global-rc.yaml +7 -4
  29. data/spec/fixtures/graph-json-rc.yaml +5 -7
  30. data/spec/fixtures/graph-rc.yaml +11 -13
  31. data/spec/fixtures/series-irregular-json-rc.yaml +5 -7
  32. data/spec/fixtures/series-irregular-rc.yaml +13 -15
  33. data/spec/fixtures/series-regular-json-rc.yaml +5 -7
  34. data/spec/fixtures/series-regular-rc.yaml +15 -17
  35. data/spec/fixtures/stream-json-rc.yaml +9 -11
  36. data/spec/fixtures/stream-rc.yaml +10 -12
  37. data/spec/fixtures/tangent-point-rc.yaml +10 -11
  38. data/spec/fixtures/time-rc.yaml +6 -8
  39. data/spec/modspec/conformance_class_spec.rb +44 -35
  40. data/spec/modspec/conformance_test_spec.rb +26 -7
  41. data/spec/modspec/normative_statement_spec.rb +16 -12
  42. data/spec/modspec/normative_statements_class_spec.rb +18 -6
  43. data/spec/modspec/suite_spec.rb +198 -37
  44. data/spec/modspec_spec.rb +7 -7
  45. data/spec/spec_helper.rb +1 -0
  46. metadata +6 -4
@@ -5,7 +5,7 @@ RSpec.describe Modspec::ConformanceTest do
5
5
  Modspec::NormativeStatement.new(
6
6
  identifier: "/req/basic-ypr/position",
7
7
  name: "Expression of outer frame",
8
- statement: "The `Basic_YPR.position` attribute shall represent the outer frame, specified by an implicit WGS-84 CRS and an implicit EPSG 4461-CS (LTP-ENU) coordinate system and explicit parameters to define the tangent point."
8
+ statement: "The `Basic_YPR.position` attribute shall represent the outer frame.",
9
9
  )
10
10
  end
11
11
 
@@ -13,18 +13,18 @@ RSpec.describe Modspec::ConformanceTest do
13
13
  Modspec::NormativeStatementsClass.new(
14
14
  identifier: "/req/basic-ypr",
15
15
  name: "Basic-YPR logical model SDU",
16
- normative_statements: [normative_statement]
16
+ normative_statements: [normative_statement],
17
17
  )
18
18
  end
19
19
 
20
20
  let(:conformance_test) do
21
- Modspec::ConformanceTest.new(
21
+ described_class.new(
22
22
  identifier: "/conf/basic-ypr/position",
23
23
  name: "Verify expression of outer frame",
24
24
  targets: ["/req/basic-ypr/position"],
25
- description: "To confirm that an implementation of a Basic-YPR consists of an Outer Frame specified by an implicit WGS-84 CRS and an implicit EPSG 4461-CS (LTP-ENU) coordinate system and explicit parameters to define the tangent point.",
25
+ description: "To confirm outer frame.",
26
26
  purpose: "Verify that this requirement is satisfied.",
27
- method: "Inspection"
27
+ test_method: "Inspection",
28
28
  )
29
29
  end
30
30
 
@@ -32,7 +32,7 @@ RSpec.describe Modspec::ConformanceTest do
32
32
  Modspec::ConformanceClass.new(
33
33
  identifier: "/conf/basic-ypr",
34
34
  name: "Basic-YPR logical model SDU conformance",
35
- tests: [conformance_test]
35
+ tests: [conformance_test],
36
36
  )
37
37
  end
38
38
 
@@ -45,7 +45,7 @@ RSpec.describe Modspec::ConformanceTest do
45
45
  end
46
46
 
47
47
  before do
48
- suite # Ensure the suite is created and relationships are set up
48
+ suite
49
49
  end
50
50
 
51
51
  it "has an identifier" do
@@ -65,7 +65,26 @@ RSpec.describe Modspec::ConformanceTest do
65
65
  errors = conformance_test.validate
66
66
  expect(errors).to be_empty
67
67
  end
68
+
69
+ it "returns errors when corresponding_requirements is nil" do
70
+ conformance_test.corresponding_requirements = nil
71
+ errors = conformance_test.validate
72
+ expect(errors).to include(a_string_matching(/no corresponding requirements/))
73
+ end
74
+
75
+ it "returns errors when corresponding_requirements is empty" do
76
+ conformance_test.corresponding_requirements = []
77
+ errors = conformance_test.validate
78
+ expect(errors).to include(a_string_matching(/no corresponding requirements/))
79
+ end
80
+
81
+ it "returns errors when parent_class is nil" do
82
+ conformance_test.parent_class = nil
83
+ errors = conformance_test.validate
84
+ expect(errors).to include(a_string_matching(/does not belong to its parent class/))
85
+ end
68
86
  end
87
+
69
88
  it "has a corresponding requirement" do
70
89
  expect(conformance_test.corresponding_requirements).to include(normative_statement)
71
90
  end
@@ -2,23 +2,23 @@
2
2
 
3
3
  RSpec.describe Modspec::NormativeStatement do
4
4
  let(:global_sdu_statement) do
5
- Modspec::NormativeStatement.new(
5
+ described_class.new(
6
6
  identifier: "/req/global/sdu",
7
7
  name: "SDU conforms to the 'Structural Data Unit - SDU' stereotype",
8
- statement: "Implementations using encoded SDUs SHALL conform to the logical description of the Logical Model elements with the 'Structural Data Unit - SDU' stereotype."
8
+ statement: "Implementations using encoded SDUs SHALL conform to the logical description of the Logical Model elements with the 'Structural Data Unit - SDU' stereotype.",
9
9
  )
10
10
  end
11
11
 
12
12
  let(:tangent_point_statement) do
13
- Modspec::NormativeStatement.new(
13
+ described_class.new(
14
14
  identifier: "/req/tangent-point",
15
15
  name: "Tangent point requirements",
16
- statement: "Common tangent point requirements for SDUs that include tangent points."
16
+ statement: "Common tangent point requirements for SDUs that include tangent points.",
17
17
  )
18
18
  end
19
19
 
20
20
  let(:normative_statement) do
21
- Modspec::NormativeStatement.new(
21
+ described_class.new(
22
22
  identifier: "/req/basic-ypr/position",
23
23
  name: "Expression of outer frame",
24
24
  statement: "The `Basic_YPR.position` attribute shall represent the outer frame, specified by an implicit WGS-84 CRS and an implicit EPSG 4461-CS (LTP-ENU) coordinate system and explicit parameters to define the tangent point.",
@@ -26,7 +26,7 @@ RSpec.describe Modspec::NormativeStatement do
26
26
  subject: "Basic_YPR.position",
27
27
  inherit: ["/req/global/sdu"],
28
28
  dependencies: ["/req/tangent-point"],
29
- guidance: ["Ensure the coordinate system is correctly specified."]
29
+ guidance: ["Ensure the coordinate system is correctly specified."],
30
30
  )
31
31
  end
32
32
 
@@ -34,17 +34,18 @@ RSpec.describe Modspec::NormativeStatement do
34
34
  suite = Modspec::Suite.new
35
35
  global_class = Modspec::NormativeStatementsClass.new(
36
36
  identifier: "/req/global",
37
- normative_statements: [global_sdu_statement]
37
+ normative_statements: [global_sdu_statement],
38
38
  )
39
39
  tangent_point_class = Modspec::NormativeStatementsClass.new(
40
40
  identifier: "/req/tangent-point",
41
- normative_statements: [tangent_point_statement]
41
+ normative_statements: [tangent_point_statement],
42
42
  )
43
43
  basic_ypr_class = Modspec::NormativeStatementsClass.new(
44
44
  identifier: "/req/basic-ypr",
45
- normative_statements: [normative_statement]
45
+ normative_statements: [normative_statement],
46
46
  )
47
- suite.normative_statements_classes = [global_class, tangent_point_class, basic_ypr_class]
47
+ suite.normative_statements_classes = [global_class, tangent_point_class,
48
+ basic_ypr_class]
48
49
  suite
49
50
  end
50
51
 
@@ -61,7 +62,8 @@ RSpec.describe Modspec::NormativeStatement do
61
62
  end
62
63
 
63
64
  it "has a valid obligation" do
64
- expect(%w[requirement recommendation permission]).to include(normative_statement.obligation)
65
+ expect(%w[requirement recommendation
66
+ permission]).to include(normative_statement.obligation)
65
67
  end
66
68
 
67
69
  describe "#validate" do
@@ -72,7 +74,9 @@ RSpec.describe Modspec::NormativeStatement do
72
74
 
73
75
  it "returns errors for an invalid obligation" do
74
76
  normative_statement.obligation = "invalid"
75
- expect { normative_statement.validate! }.to raise_error(Lutaml::Model::ValidationError) do |error|
77
+ expect do
78
+ normative_statement.validate!
79
+ end.to raise_error(Lutaml::Model::ValidationError) do |error|
76
80
  expect(error).to include(Lutaml::Model::InvalidValueError)
77
81
  expect(error.error_messages).to include("obligation is `invalid`, must be one of the following [recommendation, permission, requirement]")
78
82
  end
@@ -5,7 +5,7 @@ RSpec.describe Modspec::NormativeStatementsClass do
5
5
  Modspec::NormativeStatement.new(
6
6
  identifier: "/req/basic-ypr/position",
7
7
  name: "Expression of outer frame",
8
- statement: "The `Basic_YPR.position` attribute shall represent the outer frame, specified by an implicit WGS-84 CRS and an implicit EPSG 4461-CS (LTP-ENU) coordinate system and explicit parameters to define the tangent point."
8
+ statement: "The `Basic_YPR.position` attribute shall represent the outer frame.",
9
9
  )
10
10
  end
11
11
 
@@ -13,17 +13,17 @@ RSpec.describe Modspec::NormativeStatementsClass do
13
13
  Modspec::NormativeStatement.new(
14
14
  identifier: "/req/basic-ypr/angles",
15
15
  name: "Expression of inner frame",
16
- statement: "The `Basic_YPR.angles` attribute shall represent the inner frame, which is a rotation-only transformation with Yaw, Pitch, and Roll (YPR) angles."
16
+ statement: "The `Basic_YPR.angles` attribute shall represent the inner frame.",
17
17
  )
18
18
  end
19
19
 
20
20
  let(:normative_statements_class) do
21
- Modspec::NormativeStatementsClass.new(
21
+ described_class.new(
22
22
  identifier: "/req/basic-ypr",
23
23
  name: "Basic-YPR logical model SDU",
24
- description: "The Basic-YPR Target has a simple structure with no options. Position is specified as a point in an LTP-ENU frame and rotation is specified by yaw, pitch, and roll angles specified in decimal degrees.",
24
+ description: "The Basic-YPR Target has a simple structure.",
25
25
  dependencies: ["/req/global", "/req/tangent-point"],
26
- normative_statements: [normative_statement1, normative_statement2]
26
+ normative_statements: [normative_statement1, normative_statement2],
27
27
  )
28
28
  end
29
29
 
@@ -55,7 +55,19 @@ RSpec.describe Modspec::NormativeStatementsClass do
55
55
  it "returns errors if there are no normative statements" do
56
56
  normative_statements_class.normative_statements = []
57
57
  errors = normative_statements_class.validate
58
- expect(errors).not_to be_empty
58
+ expect(errors).to include(a_string_matching(/no child requirements/))
59
+ end
60
+
61
+ it "returns errors if statement identifier does not share prefix" do
62
+ normative_statements_class.normative_statements = [
63
+ Modspec::NormativeStatement.new(
64
+ identifier: "/req/other/mismatch",
65
+ name: "Mismatched",
66
+ statement: "stmt",
67
+ ),
68
+ ]
69
+ errors = normative_statements_class.validate
70
+ expect(errors).to include(a_string_matching(/does not share the expected prefix/))
59
71
  end
60
72
  end
61
73
  end
@@ -9,10 +9,10 @@ RSpec.describe Modspec::Suite do
9
9
  let(:time_rc) { File.read("spec/fixtures/time-rc.yaml") }
10
10
  let(:frame_spec_rc) { File.read("spec/fixtures/frame-spec-rc.yaml") }
11
11
 
12
- let(:global_suite) { Modspec::Suite.from_yaml(global_rc) }
13
- let(:tangent_point_suite) { Modspec::Suite.from_yaml(tangent_point_rc) }
14
- let(:time_suite) { Modspec::Suite.from_yaml(time_rc) }
15
- let(:frame_spec_suite) { Modspec::Suite.from_yaml(frame_spec_rc) }
12
+ let(:global_suite) { described_class.from_yaml(global_rc) }
13
+ let(:tangent_point_suite) { described_class.from_yaml(tangent_point_rc) }
14
+ let(:time_suite) { described_class.from_yaml(time_rc) }
15
+ let(:frame_spec_suite) { described_class.from_yaml(frame_spec_rc) }
16
16
 
17
17
  describe ".from_yaml" do
18
18
  it "parses a requirements class YAML file" do
@@ -32,46 +32,218 @@ RSpec.describe Modspec::Suite do
32
32
  it "returns no errors for a valid combined suite" do
33
33
  base_suite = described_class.from_yaml(rc_yaml)
34
34
  combined_suite = base_suite
35
- .combine(global_suite)
36
- .combine(tangent_point_suite)
37
- .combine(time_suite)
38
- .combine(frame_spec_suite)
35
+ .combine(global_suite)
36
+ .combine(tangent_point_suite)
37
+ .combine(time_suite)
38
+ .combine(frame_spec_suite)
39
39
 
40
40
  errors = combined_suite.validate
41
- if errors.any?
42
- puts "Validation errors:"
43
- errors.each { |error| puts " #{error}" }
44
- end
45
41
  expect(errors).to be_empty
46
42
  end
43
+
44
+ it "detects duplicate identifiers" do
45
+ suite = described_class.new(
46
+ identifier: "/suite",
47
+ name: "Test",
48
+ normative_statements_classes: [
49
+ Modspec::NormativeStatementsClass.new(
50
+ identifier: "/req/test",
51
+ normative_statements: [
52
+ Modspec::NormativeStatement.new(identifier: "/req/test/a",
53
+ name: "A", statement: "a"),
54
+ Modspec::NormativeStatement.new(identifier: "/req/test/a",
55
+ name: "A2", statement: "a2"),
56
+ ],
57
+ ),
58
+ ],
59
+ conformance_classes: [],
60
+ )
61
+
62
+ errors = suite.validate
63
+ expect(errors).to include(a_string_matching(/Duplicate identifier/))
64
+ end
65
+
66
+ it "detects dependency cycles" do
67
+ ns_a = Modspec::NormativeStatement.new(
68
+ identifier: "/req/test/a", name: "A", statement: "a",
69
+ dependencies: ["/req/test/b"]
70
+ )
71
+ ns_b = Modspec::NormativeStatement.new(
72
+ identifier: "/req/test/b", name: "B", statement: "b",
73
+ dependencies: ["/req/test/a"]
74
+ )
75
+
76
+ suite = described_class.new(
77
+ identifier: "/suite",
78
+ name: "Test",
79
+ normative_statements_classes: [
80
+ Modspec::NormativeStatementsClass.new(
81
+ identifier: "/req/test",
82
+ normative_statements: [ns_a, ns_b],
83
+ ),
84
+ ],
85
+ conformance_classes: [],
86
+ )
87
+
88
+ errors = suite.validate
89
+ expect(errors).to include(a_string_matching(/Cycle detected/))
90
+ end
91
+
92
+ it "detects invalid dependencies" do
93
+ suite = described_class.new(
94
+ identifier: "/suite",
95
+ name: "Test",
96
+ normative_statements_classes: [
97
+ Modspec::NormativeStatementsClass.new(
98
+ identifier: "/req/test",
99
+ dependencies: ["/req/nonexistent"],
100
+ normative_statements: [
101
+ Modspec::NormativeStatement.new(
102
+ identifier: "/req/test/a", name: "A", statement: "a",
103
+ dependencies: ["/req/missing"]
104
+ ),
105
+ ],
106
+ ),
107
+ ],
108
+ conformance_classes: [],
109
+ )
110
+
111
+ errors = suite.validate
112
+ expect(errors).to include(a_string_matching(/Invalid dependencies .* in \/req\/test\b/))
113
+ expect(errors).to include(a_string_matching(/Invalid dependencies .* in \/req\/test\/a/))
114
+ end
115
+
116
+ it "detects invalid conformance test targets" do
117
+ suite = described_class.new(
118
+ identifier: "/suite",
119
+ name: "Test",
120
+ normative_statements_classes: [
121
+ Modspec::NormativeStatementsClass.new(
122
+ identifier: "/req/test",
123
+ normative_statements: [
124
+ Modspec::NormativeStatement.new(identifier: "/req/test/a",
125
+ name: "A", statement: "a"),
126
+ ],
127
+ ),
128
+ ],
129
+ conformance_classes: [
130
+ Modspec::ConformanceClass.new(
131
+ identifier: "/conf/test",
132
+ tests: [
133
+ Modspec::ConformanceTest.new(
134
+ identifier: "/conf/test/a",
135
+ name: "CT-A",
136
+ targets: ["/req/nonexistent"],
137
+ ),
138
+ ],
139
+ ),
140
+ ],
141
+ )
142
+
143
+ errors = suite.validate
144
+ expect(errors).to include(a_string_matching(/Invalid targets .* in \/conf\/test\/a/))
145
+ end
146
+
147
+ it "detects invalid indirect_dependency references" do
148
+ suite = described_class.new(
149
+ identifier: "/suite",
150
+ name: "Test",
151
+ normative_statements_classes: [
152
+ Modspec::NormativeStatementsClass.new(
153
+ identifier: "/req/test",
154
+ normative_statements: [
155
+ Modspec::NormativeStatement.new(
156
+ identifier: "/req/test/a", name: "A", statement: "a",
157
+ indirect_dependency: ["/req/ghost"]
158
+ ),
159
+ ],
160
+ ),
161
+ ],
162
+ conformance_classes: [],
163
+ )
164
+
165
+ errors = suite.validate
166
+ expect(errors).to include(a_string_matching(/indirect dependency.*in \/req\/test\/a/))
167
+ end
168
+
169
+ it "detects invalid implements references" do
170
+ suite = described_class.new(
171
+ identifier: "/suite",
172
+ name: "Test",
173
+ normative_statements_classes: [
174
+ Modspec::NormativeStatementsClass.new(
175
+ identifier: "/req/test",
176
+ implements: ["/req/phantom"],
177
+ normative_statements: [],
178
+ ),
179
+ ],
180
+ conformance_classes: [],
181
+ )
182
+
183
+ errors = suite.validate
184
+ expect(errors).to include(a_string_matching(/implements.*in \/req\/test/))
185
+ end
186
+
187
+ it "detects invalid conformance test dependencies" do
188
+ suite = described_class.new(
189
+ identifier: "/suite",
190
+ name: "Test",
191
+ normative_statements_classes: [],
192
+ conformance_classes: [
193
+ Modspec::ConformanceClass.new(
194
+ identifier: "/conf/test",
195
+ tests: [
196
+ Modspec::ConformanceTest.new(
197
+ identifier: "/conf/test/a",
198
+ name: "CT-A",
199
+ dependencies: ["/conf/nonexistent"],
200
+ ),
201
+ ],
202
+ ),
203
+ ],
204
+ )
205
+
206
+ errors = suite.validate
207
+ expect(errors).to include(a_string_matching(/Invalid dependencies .* in \/conf\/test\/a/))
208
+ end
47
209
  end
48
210
 
49
211
  describe "#combine" do
50
- let(:suite1) { described_class.from_yaml(File.read("spec/fixtures/basic-ypr-rc.yaml")) }
51
- let(:suite2) { described_class.from_yaml(File.read("spec/fixtures/basic-quaternion-rc.yaml")) }
212
+ let(:suite1) do
213
+ described_class.from_yaml(File.read("spec/fixtures/basic-ypr-rc.yaml"))
214
+ end
215
+ let(:suite2) do
216
+ described_class.from_yaml(File.read("spec/fixtures/basic-quaternion-rc.yaml"))
217
+ end
52
218
 
53
219
  it "combines two suites" do
54
220
  combined_suite = suite1.combine(suite2)
55
221
  expect(combined_suite.name).to eq("#{suite1.name} + #{suite2.name}")
56
222
  expect(combined_suite.normative_statements_classes.count).to eq(
57
223
  suite1.normative_statements_classes.count +
58
- suite2.normative_statements_classes.count
224
+ suite2.normative_statements_classes.count,
59
225
  )
60
226
  end
61
227
 
228
+ it "raises ArgumentError for non-Suite argument" do
229
+ expect { suite1.combine("not a suite") }.to raise_error(ArgumentError)
230
+ end
231
+
232
+ it "deduplicates by identifier" do
233
+ combined = suite1.combine(suite1)
234
+ nsc_count = combined.normative_statements_classes.count
235
+ expect(nsc_count).to eq(suite1.normative_statements_classes.count)
236
+ end
237
+
62
238
  it "resolves conflicts when combining suites" do
63
239
  combined_suite = suite1
64
- .combine(suite2)
65
- .combine(global_suite)
66
- .combine(tangent_point_suite)
67
- .combine(time_suite)
68
- .combine(frame_spec_suite)
240
+ .combine(suite2)
241
+ .combine(global_suite)
242
+ .combine(tangent_point_suite)
243
+ .combine(time_suite)
244
+ .combine(frame_spec_suite)
69
245
 
70
246
  errors = combined_suite.validate
71
- if errors.any?
72
- puts "Validation errors:"
73
- errors.each { |error| puts " #{error}" }
74
- end
75
247
  expect(errors).to be_empty
76
248
  end
77
249
  end
@@ -85,24 +257,13 @@ RSpec.describe Modspec::Suite do
85
257
  expect(combined_suite).to be_a(described_class)
86
258
  expect(combined_suite.name).to eq("Combined Suite")
87
259
 
88
- # Ensure the combined suite has content
89
260
  expect(combined_suite.normative_statements_classes).not_to be_empty
90
261
  expect(combined_suite.conformance_classes).not_to be_empty
91
262
 
92
- # Validate the combined suite
93
263
  errors = combined_suite.validate
94
-
95
- if errors.any?
96
- puts "Validation errors:"
97
- errors.each { |error| puts " #{error}" }
98
- end
99
-
100
- # Check for specific error types
101
- expect(errors).not_to include(a_string_matching(/Conformance test .* has no corresponding requirement/))
264
+ expect(errors).not_to include(a_string_matching(/has no corresponding requirement/))
102
265
  expect(errors).not_to include(a_string_matching(/Cycle detected/))
103
- expect(errors).not_to include(a_string_matching(/Requirement .* has an invalid dependency/))
104
-
105
- # If there are still errors, they should be of a different nature
266
+ expect(errors).not_to include(a_string_matching(/has an invalid dependency/))
106
267
  expect(errors).to be_empty
107
268
  end
108
269
  end
data/spec/modspec_spec.rb CHANGED
@@ -2,24 +2,24 @@
2
2
 
3
3
  RSpec.describe Modspec do
4
4
  it "has a version number" do
5
- expect(Modspec::VERSION).not_to be nil
5
+ expect(Modspec::VERSION).not_to be_nil
6
6
  end
7
7
 
8
8
  Dir.glob("spec/fixtures/*-rc.yaml").each do |file|
9
9
  it "parses normative statements class #{file}" do
10
- yaml = IO.read(file)
11
- Modspec::Suite.from_yaml(yaml)
10
+ source_yaml = File.read(file)
11
+ output_yaml = Modspec::Suite.from_yaml(source_yaml).to_yaml
12
12
 
13
- # TODO: tests
13
+ expect(output_yaml).to be_yaml_equivalent_to(source_yaml)
14
14
  end
15
15
  end
16
16
 
17
17
  Dir.glob("spec/fixtures/*-cc.yaml").each do |file|
18
18
  it "parses conformance class #{file}" do
19
- yaml = IO.read(file)
20
- Modspec::Suite.from_yaml(yaml)
19
+ source_yaml = File.read(file)
20
+ output_yaml = Modspec::Suite.from_yaml(source_yaml).to_yaml
21
21
 
22
- # TODO: tests
22
+ expect(output_yaml).to be_yaml_equivalent_to(source_yaml)
23
23
  end
24
24
  end
25
25
  end
data/spec/spec_helper.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "modspec"
4
4
  require "yaml"
5
+ require "canon"
5
6
 
6
7
  RSpec.configure do |config|
7
8
  # Enable flags like --only-failures and --next-failure
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: modspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-03-28 00:00:00.000000000 Z
11
+ date: 2026-05-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lutaml-model
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.7'
19
+ version: 0.8.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.7'
26
+ version: 0.8.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: nokogiri
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -65,6 +65,7 @@ files:
65
65
  - ".rspec"
66
66
  - ".rubocop.yml"
67
67
  - ".rubocop_todo.yml"
68
+ - CLAUDE.md
68
69
  - CODE_OF_CONDUCT.md
69
70
  - Gemfile
70
71
  - README.adoc
@@ -137,6 +138,7 @@ metadata:
137
138
  homepage_uri: https://github.com/metanorma/modspec-ruby
138
139
  source_code_uri: https://github.com/metanorma/modspec-ruby
139
140
  bug_tracker_uri: https://github.com/metanorma/modspec-ruby/issues
141
+ rubygems_mfa_required: 'true'
140
142
  post_install_message:
141
143
  rdoc_options: []
142
144
  require_paths: