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.
- checksums.yaml +4 -4
- data/.github/workflows/rake.yml +4 -0
- data/.github/workflows/release.yml +5 -0
- data/.rubocop.yml +18 -6
- data/.rubocop_todo.yml +108 -76
- data/CLAUDE.md +61 -0
- data/Gemfile +4 -3
- data/lib/modspec/conformance_class.rb +4 -8
- data/lib/modspec/conformance_test.rb +19 -5
- data/lib/modspec/identifier.rb +0 -1
- data/lib/modspec/normative_statement.rb +3 -39
- data/lib/modspec/normative_statements_class.rb +3 -3
- data/lib/modspec/suite.rb +73 -82
- data/lib/modspec/version.rb +1 -1
- data/lib/modspec.rb +8 -22
- data/modspec.gemspec +3 -2
- data/spec/conformance_class.liquid +2 -2
- data/spec/fixtures/advanced-json-rc.yaml +5 -7
- data/spec/fixtures/advanced-rc.yaml +12 -14
- data/spec/fixtures/basic-quaternion-json-rc.yaml +5 -7
- data/spec/fixtures/basic-quaternion-json-strict-rc.yaml +4 -5
- data/spec/fixtures/basic-quaternion-rc.yaml +7 -8
- data/spec/fixtures/basic-ypr-json-rc.yaml +5 -8
- data/spec/fixtures/basic-ypr-rc.yaml +7 -7
- data/spec/fixtures/chain-json-rc.yaml +5 -7
- data/spec/fixtures/chain-rc.yaml +11 -13
- data/spec/fixtures/frame-spec-rc.yaml +10 -10
- data/spec/fixtures/global-rc.yaml +7 -4
- data/spec/fixtures/graph-json-rc.yaml +5 -7
- data/spec/fixtures/graph-rc.yaml +11 -13
- data/spec/fixtures/series-irregular-json-rc.yaml +5 -7
- data/spec/fixtures/series-irregular-rc.yaml +13 -15
- data/spec/fixtures/series-regular-json-rc.yaml +5 -7
- data/spec/fixtures/series-regular-rc.yaml +15 -17
- data/spec/fixtures/stream-json-rc.yaml +9 -11
- data/spec/fixtures/stream-rc.yaml +10 -12
- data/spec/fixtures/tangent-point-rc.yaml +10 -11
- data/spec/fixtures/time-rc.yaml +6 -8
- data/spec/modspec/conformance_class_spec.rb +44 -35
- data/spec/modspec/conformance_test_spec.rb +26 -7
- data/spec/modspec/normative_statement_spec.rb +16 -12
- data/spec/modspec/normative_statements_class_spec.rb +18 -6
- data/spec/modspec/suite_spec.rb +198 -37
- data/spec/modspec_spec.rb +7 -7
- data/spec/spec_helper.rb +1 -0
- 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
|
|
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
|
-
|
|
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
|
|
25
|
+
description: "To confirm outer frame.",
|
|
26
26
|
purpose: "Verify that this requirement is satisfied.",
|
|
27
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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).
|
|
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
|
data/spec/modspec/suite_spec.rb
CHANGED
|
@@ -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) {
|
|
13
|
-
let(:tangent_point_suite) {
|
|
14
|
-
let(:time_suite) {
|
|
15
|
-
let(:frame_spec_suite) {
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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)
|
|
51
|
-
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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(/
|
|
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
|
|
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
|
-
|
|
11
|
-
Modspec::Suite.from_yaml(
|
|
10
|
+
source_yaml = File.read(file)
|
|
11
|
+
output_yaml = Modspec::Suite.from_yaml(source_yaml).to_yaml
|
|
12
12
|
|
|
13
|
-
|
|
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
|
-
|
|
20
|
-
Modspec::Suite.from_yaml(
|
|
19
|
+
source_yaml = File.read(file)
|
|
20
|
+
output_yaml = Modspec::Suite.from_yaml(source_yaml).to_yaml
|
|
21
21
|
|
|
22
|
-
|
|
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
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
|
+
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:
|
|
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:
|
|
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:
|
|
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:
|