modspec 0.2.0 → 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/.rubocop.yml +3 -0
- data/.rubocop_todo.yml +69 -24
- data/lib/modspec/conformance_class.rb +0 -2
- data/lib/modspec/conformance_test.rb +0 -1
- data/lib/modspec/identifier.rb +0 -1
- data/lib/modspec/normative_statement.rb +2 -38
- data/lib/modspec/normative_statements_class.rb +0 -2
- data/lib/modspec/suite.rb +37 -53
- data/lib/modspec/version.rb +1 -1
- data/lib/modspec.rb +7 -10
- data/spec/modspec/conformance_class_spec.rb +19 -12
- data/spec/modspec/conformance_test_spec.rb +21 -3
- data/spec/modspec/normative_statements_class_spec.rb +16 -4
- data/spec/modspec/suite_spec.rb +178 -21
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 74bb2806f9ebad2c91453ba473103f5e581c76b78223d9eeba79f4580e8858db
|
|
4
|
+
data.tar.gz: cb2903e0b33726419f118c65f64ad5463a2bef0b385643f877de977bc447f8d9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d31ab6413761a379a95aa692e94471538daa63cb507ecfcf25ab6e4b3bc34cdfc22d8234ca4239e0159921bdd203ce4e8bec8bec3e4d99323222c34d49d59ac0
|
|
7
|
+
data.tar.gz: 615225d2adf7b489e0d627147b3a3dbdd43009ed0c96df174f690b9ebeec6c7c752eb5a684505f6822af40d7ee9710ef2a165e9aa601ba6144d82b52a2192a38
|
data/.rubocop.yml
CHANGED
data/.rubocop_todo.yml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# This configuration was generated by
|
|
2
2
|
# `rubocop --auto-gen-config`
|
|
3
|
-
# on 2026-05-
|
|
3
|
+
# on 2026-05-06 00:19:18 UTC using RuboCop version 1.86.1.
|
|
4
4
|
# The point is for the user to remove these configuration records
|
|
5
5
|
# one by one as the offenses are removed from the code base.
|
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
|
@@ -11,7 +11,48 @@ Gemspec/RequiredRubyVersion:
|
|
|
11
11
|
Exclude:
|
|
12
12
|
- 'modspec.gemspec'
|
|
13
13
|
|
|
14
|
-
# Offense count:
|
|
14
|
+
# Offense count: 7
|
|
15
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
16
|
+
# Configuration parameters: EnforcedStyle, IndentationWidth.
|
|
17
|
+
# SupportedStyles: with_first_argument, with_fixed_indentation
|
|
18
|
+
Layout/ArgumentAlignment:
|
|
19
|
+
Exclude:
|
|
20
|
+
- 'lib/modspec/suite.rb'
|
|
21
|
+
- 'spec/modspec/suite_spec.rb'
|
|
22
|
+
|
|
23
|
+
# Offense count: 1
|
|
24
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
25
|
+
# Configuration parameters: EnforcedStyleAlignWith.
|
|
26
|
+
# SupportedStylesAlignWith: either, start_of_block, start_of_line
|
|
27
|
+
Layout/BlockAlignment:
|
|
28
|
+
Exclude:
|
|
29
|
+
- 'lib/modspec/suite.rb'
|
|
30
|
+
|
|
31
|
+
# Offense count: 1
|
|
32
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
33
|
+
Layout/BlockEndNewline:
|
|
34
|
+
Exclude:
|
|
35
|
+
- 'lib/modspec/suite.rb'
|
|
36
|
+
|
|
37
|
+
# Offense count: 6
|
|
38
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
39
|
+
# Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle.
|
|
40
|
+
# SupportedHashRocketStyles: key, separator, table
|
|
41
|
+
# SupportedColonStyles: key, separator, table
|
|
42
|
+
# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
|
|
43
|
+
Layout/HashAlignment:
|
|
44
|
+
Exclude:
|
|
45
|
+
- 'spec/modspec/suite_spec.rb'
|
|
46
|
+
|
|
47
|
+
# Offense count: 2
|
|
48
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
49
|
+
# Configuration parameters: Width, EnforcedStyleAlignWith, AllowedPatterns.
|
|
50
|
+
# SupportedStylesAlignWith: start_of_line, relative_to_receiver
|
|
51
|
+
Layout/IndentationWidth:
|
|
52
|
+
Exclude:
|
|
53
|
+
- 'lib/modspec/suite.rb'
|
|
54
|
+
|
|
55
|
+
# Offense count: 36
|
|
15
56
|
# This cop supports safe autocorrection (--autocorrect).
|
|
16
57
|
# Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
|
|
17
58
|
# URISchemes: http, https
|
|
@@ -19,7 +60,6 @@ Layout/LineLength:
|
|
|
19
60
|
Exclude:
|
|
20
61
|
- 'lib/modspec/conformance_class.rb'
|
|
21
62
|
- 'lib/modspec/conformance_test.rb'
|
|
22
|
-
- 'lib/modspec/normative_statement.rb'
|
|
23
63
|
- 'lib/modspec/normative_statements_class.rb'
|
|
24
64
|
- 'lib/modspec/suite.rb'
|
|
25
65
|
- 'spec/modspec/conformance_class_spec.rb'
|
|
@@ -29,21 +69,14 @@ Layout/LineLength:
|
|
|
29
69
|
- 'spec/modspec/suite_spec.rb'
|
|
30
70
|
|
|
31
71
|
# Offense count: 4
|
|
32
|
-
# Configuration parameters: AllowComments, AllowEmptyLambdas.
|
|
33
|
-
Lint/EmptyBlock:
|
|
34
|
-
Exclude:
|
|
35
|
-
- 'spec/modspec/conformance_class_spec.rb'
|
|
36
|
-
- 'spec/modspec/suite_spec.rb'
|
|
37
|
-
|
|
38
|
-
# Offense count: 1
|
|
39
72
|
# This cop supports safe autocorrection (--autocorrect).
|
|
40
|
-
# Configuration parameters:
|
|
41
|
-
|
|
42
|
-
Lint/UnusedMethodArgument:
|
|
73
|
+
# Configuration parameters: AllowInHeredoc.
|
|
74
|
+
Layout/TrailingWhitespace:
|
|
43
75
|
Exclude:
|
|
44
|
-
- 'lib/modspec/
|
|
76
|
+
- 'lib/modspec/suite.rb'
|
|
77
|
+
- 'spec/modspec/suite_spec.rb'
|
|
45
78
|
|
|
46
|
-
# Offense count:
|
|
79
|
+
# Offense count: 5
|
|
47
80
|
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
|
|
48
81
|
Metrics/AbcSize:
|
|
49
82
|
Exclude:
|
|
@@ -58,25 +91,20 @@ Metrics/CyclomaticComplexity:
|
|
|
58
91
|
# Offense count: 9
|
|
59
92
|
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
|
60
93
|
Metrics/MethodLength:
|
|
61
|
-
Max:
|
|
94
|
+
Max: 19
|
|
62
95
|
|
|
63
|
-
# Offense count:
|
|
96
|
+
# Offense count: 2
|
|
64
97
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
|
65
98
|
Metrics/PerceivedComplexity:
|
|
66
99
|
Exclude:
|
|
67
100
|
- 'lib/modspec/suite.rb'
|
|
68
101
|
|
|
69
|
-
# Offense count:
|
|
102
|
+
# Offense count: 2
|
|
70
103
|
# Configuration parameters: MinSize.
|
|
71
104
|
Performance/CollectionLiteralInLoop:
|
|
72
105
|
Exclude:
|
|
73
106
|
- 'lib/modspec/suite.rb'
|
|
74
107
|
|
|
75
|
-
# Offense count: 5
|
|
76
|
-
# Configuration parameters: CountAsOne.
|
|
77
|
-
RSpec/ExampleLength:
|
|
78
|
-
Max: 15
|
|
79
|
-
|
|
80
108
|
# Offense count: 1
|
|
81
109
|
# This cop supports safe autocorrection (--autocorrect).
|
|
82
110
|
RSpec/ExpectActual:
|
|
@@ -90,7 +118,7 @@ RSpec/IndexedLet:
|
|
|
90
118
|
- 'spec/modspec/normative_statements_class_spec.rb'
|
|
91
119
|
- 'spec/modspec/suite_spec.rb'
|
|
92
120
|
|
|
93
|
-
# Offense count:
|
|
121
|
+
# Offense count: 8
|
|
94
122
|
RSpec/MultipleExpectations:
|
|
95
123
|
Max: 9
|
|
96
124
|
|
|
@@ -103,3 +131,20 @@ RSpec/MultipleMemoizedHelpers:
|
|
|
103
131
|
RSpec/RepeatedExample:
|
|
104
132
|
Exclude:
|
|
105
133
|
- 'spec/modspec_spec.rb'
|
|
134
|
+
|
|
135
|
+
# Offense count: 1
|
|
136
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
137
|
+
# Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, AllowedMethods, AllowedPatterns, AllowBracesOnProceduralOneLiners, BracesRequiredMethods.
|
|
138
|
+
# SupportedStyles: line_count_based, semantic, braces_for_chaining, always_braces
|
|
139
|
+
# ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object
|
|
140
|
+
# FunctionalMethods: let, let!, subject, watch
|
|
141
|
+
# AllowedMethods: lambda, proc, it
|
|
142
|
+
Style/BlockDelimiters:
|
|
143
|
+
Exclude:
|
|
144
|
+
- 'lib/modspec/suite.rb'
|
|
145
|
+
|
|
146
|
+
# Offense count: 2
|
|
147
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
148
|
+
Style/MultilineIfModifier:
|
|
149
|
+
Exclude:
|
|
150
|
+
- 'lib/modspec/suite.rb'
|
data/lib/modspec/identifier.rb
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "lutaml/model"
|
|
4
|
-
require_relative "identifier"
|
|
5
4
|
|
|
6
5
|
module Modspec
|
|
7
6
|
class NormativeStatementPart < Lutaml::Model::Serializable
|
|
@@ -46,43 +45,8 @@ module Modspec
|
|
|
46
45
|
map_element "parts", to: :parts
|
|
47
46
|
end
|
|
48
47
|
|
|
49
|
-
def validate(
|
|
50
|
-
|
|
51
|
-
errors.concat(validate_dependencies(suite)) if suite
|
|
52
|
-
errors.concat(validate_nested_requirement)
|
|
53
|
-
errors
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
private
|
|
57
|
-
|
|
58
|
-
def all_dependencies
|
|
59
|
-
(
|
|
60
|
-
(dependencies || []) +
|
|
61
|
-
(indirect_dependency || []) +
|
|
62
|
-
(implements || [])
|
|
63
|
-
).flatten.compact
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def validate_dependencies(suite)
|
|
67
|
-
errors = []
|
|
68
|
-
all_identifiers = suite.all_identifiers.map(&:to_s)
|
|
69
|
-
all_dependencies.each do |dep|
|
|
70
|
-
errors << "Requirement #{identifier} has an invalid dependency: #{dep}" unless all_identifiers.include?(dep)
|
|
71
|
-
end
|
|
72
|
-
errors
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def validate_nested_requirement
|
|
76
|
-
if has_parent_requirement?
|
|
77
|
-
["Nested requirement detected: #{identifier}"]
|
|
78
|
-
else
|
|
79
|
-
[]
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def has_parent_requirement?
|
|
84
|
-
# Implementation depends on how you determine if a requirement is nested
|
|
85
|
-
false
|
|
48
|
+
def validate(_suite = nil, register: Lutaml::Model::Config.default_register)
|
|
49
|
+
super(register: register)
|
|
86
50
|
end
|
|
87
51
|
end
|
|
88
52
|
end
|
data/lib/modspec/suite.rb
CHANGED
|
@@ -95,18 +95,17 @@ module Modspec
|
|
|
95
95
|
end
|
|
96
96
|
|
|
97
97
|
def setup_relationships
|
|
98
|
-
|
|
99
|
-
normative_statements_classes.flat_map(&:normative_statements)
|
|
100
|
-
else
|
|
101
|
-
[]
|
|
102
|
-
end
|
|
98
|
+
return unless normative_statements_classes && conformance_classes
|
|
103
99
|
|
|
104
|
-
|
|
100
|
+
req_index = normative_statements_classes
|
|
101
|
+
.flat_map(&:normative_statements)
|
|
102
|
+
.to_h { |r| [r.identifier.to_s, r] }
|
|
105
103
|
|
|
106
104
|
conformance_classes.each do |cc|
|
|
107
105
|
cc.tests.each do |ct|
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
targets = Array(ct.targets).map(&:to_s)
|
|
107
|
+
ct.corresponding_requirements = targets.filter_map do |t|
|
|
108
|
+
req_index[t]
|
|
110
109
|
end
|
|
111
110
|
ct.parent_class = cc
|
|
112
111
|
end
|
|
@@ -171,15 +170,14 @@ module Modspec
|
|
|
171
170
|
|
|
172
171
|
all_statements.each do |statement|
|
|
173
172
|
id = statement.identifier.to_s
|
|
174
|
-
|
|
173
|
+
deps = Set.new
|
|
175
174
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
dependency_properties.each do |property|
|
|
181
|
-
graph[id].merge(statement.send(property).map(&:to_s)) if statement.respond_to?(property) && !statement.send(property).nil?
|
|
175
|
+
%i[dependencies indirect_dependency implements targets].each do |prop|
|
|
176
|
+
refs = statement.send(prop) if statement.respond_to?(prop)
|
|
177
|
+
deps.merge(refs.map(&:to_s)) if refs
|
|
182
178
|
end
|
|
179
|
+
|
|
180
|
+
graph[id] = deps
|
|
183
181
|
end
|
|
184
182
|
|
|
185
183
|
graph
|
|
@@ -205,20 +203,14 @@ module Modspec
|
|
|
205
203
|
recursion_stack.add(node)
|
|
206
204
|
path.push(node)
|
|
207
205
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
elsif recursion_stack.include?(neighbor)
|
|
216
|
-
return path[path.index(neighbor)..] + [neighbor]
|
|
217
|
-
end
|
|
206
|
+
graph[node]&.each do |neighbor|
|
|
207
|
+
if !visited.include?(neighbor)
|
|
208
|
+
cycle = detect_cycle_util(neighbor, graph, visited,
|
|
209
|
+
recursion_stack, path)
|
|
210
|
+
return cycle if cycle
|
|
211
|
+
elsif recursion_stack.include?(neighbor)
|
|
212
|
+
return path[path.index(neighbor)..] + [neighbor]
|
|
218
213
|
end
|
|
219
|
-
else
|
|
220
|
-
# If the node doesn't exist in the graph, log a warning
|
|
221
|
-
puts "Warning: Node #{node} referenced but not found in the graph"
|
|
222
214
|
end
|
|
223
215
|
|
|
224
216
|
path.pop
|
|
@@ -240,20 +232,24 @@ module Modspec
|
|
|
240
232
|
end
|
|
241
233
|
|
|
242
234
|
def validate_dependencies
|
|
243
|
-
|
|
235
|
+
all_ids = collect_all_identifiers
|
|
244
236
|
|
|
245
237
|
errors = []
|
|
246
238
|
normative_statements_classes&.each do |nsc|
|
|
247
|
-
errors.concat(
|
|
239
|
+
errors.concat(validate_refs(nsc, all_ids, :dependencies))
|
|
240
|
+
errors.concat(validate_refs(nsc, all_ids, :implements))
|
|
248
241
|
nsc.normative_statements.each do |ns|
|
|
249
|
-
errors.concat(
|
|
242
|
+
errors.concat(validate_refs(ns, all_ids, :dependencies))
|
|
243
|
+
errors.concat(validate_refs(ns, all_ids, :indirect_dependency))
|
|
244
|
+
errors.concat(validate_refs(ns, all_ids, :implements))
|
|
250
245
|
end
|
|
251
246
|
end
|
|
252
247
|
|
|
253
248
|
conformance_classes&.each do |cc|
|
|
254
|
-
errors.concat(
|
|
249
|
+
errors.concat(validate_refs(cc, all_ids, :dependencies))
|
|
255
250
|
cc.tests.each do |ct|
|
|
256
|
-
errors.concat(
|
|
251
|
+
errors.concat(validate_refs(ct, all_ids, :dependencies))
|
|
252
|
+
errors.concat(validate_refs(ct, all_ids, :targets))
|
|
257
253
|
end
|
|
258
254
|
end
|
|
259
255
|
|
|
@@ -280,28 +276,16 @@ module Modspec
|
|
|
280
276
|
identifiers
|
|
281
277
|
end
|
|
282
278
|
|
|
283
|
-
def
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
errors << "Invalid dependency #{dep} in #{klass.identifier}" unless all_identifiers.key?(dep.to_s)
|
|
287
|
-
end
|
|
288
|
-
errors
|
|
289
|
-
end
|
|
279
|
+
def validate_refs(obj, all_ids, property)
|
|
280
|
+
refs = obj.send(property)
|
|
281
|
+
return [] unless refs
|
|
290
282
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
errors
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
def validate_test_targets(test, all_identifiers)
|
|
300
|
-
errors = []
|
|
301
|
-
test.targets&.each do |target|
|
|
302
|
-
errors << "Invalid target #{target} in #{test.identifier}" unless all_identifiers.key?(target.to_s)
|
|
283
|
+
refs.filter_map do |ref|
|
|
284
|
+
unless all_ids.key?(ref.to_s)
|
|
285
|
+
"Invalid #{property.to_s.tr('_',
|
|
286
|
+
' ')} #{ref} in #{obj.identifier}"
|
|
287
|
+
end
|
|
303
288
|
end
|
|
304
|
-
errors
|
|
305
289
|
end
|
|
306
290
|
end
|
|
307
291
|
end
|
data/lib/modspec/version.rb
CHANGED
data/lib/modspec.rb
CHANGED
|
@@ -5,14 +5,11 @@ require "lutaml/model"
|
|
|
5
5
|
require "set"
|
|
6
6
|
|
|
7
7
|
module Modspec
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
autoload :Identifier, "modspec/identifier"
|
|
9
|
+
autoload :NormativeStatement, "modspec/normative_statement"
|
|
10
|
+
autoload :NormativeStatementPart, "modspec/normative_statement"
|
|
11
|
+
autoload :NormativeStatementsClass, "modspec/normative_statements_class"
|
|
12
|
+
autoload :ConformanceTest, "modspec/conformance_test"
|
|
13
|
+
autoload :ConformanceClass, "modspec/conformance_class"
|
|
14
|
+
autoload :Suite, "modspec/suite"
|
|
11
15
|
end
|
|
12
|
-
|
|
13
|
-
require_relative "modspec/identifier"
|
|
14
|
-
require_relative "modspec/normative_statement"
|
|
15
|
-
require_relative "modspec/normative_statements_class"
|
|
16
|
-
require_relative "modspec/conformance_test"
|
|
17
|
-
require_relative "modspec/conformance_class"
|
|
18
|
-
require_relative "modspec/suite"
|
|
@@ -11,12 +11,12 @@ RSpec.describe Modspec::ConformanceClass do
|
|
|
11
11
|
Modspec::NormativeStatement.new(
|
|
12
12
|
identifier: "/req/basic-ypr/position",
|
|
13
13
|
name: "Expression of outer frame",
|
|
14
|
-
statement: "The `Basic_YPR.position` attribute shall represent the outer frame
|
|
14
|
+
statement: "The `Basic_YPR.position` attribute shall represent the outer frame.",
|
|
15
15
|
),
|
|
16
16
|
Modspec::NormativeStatement.new(
|
|
17
17
|
identifier: "/req/basic-ypr/angles",
|
|
18
18
|
name: "Expression of inner frame",
|
|
19
|
-
statement: "The `Basic_YPR.angles` attribute shall represent the inner frame
|
|
19
|
+
statement: "The `Basic_YPR.angles` attribute shall represent the inner frame.",
|
|
20
20
|
),
|
|
21
21
|
],
|
|
22
22
|
)
|
|
@@ -35,7 +35,7 @@ RSpec.describe Modspec::ConformanceClass do
|
|
|
35
35
|
identifier: "/conf/basic-ypr/position",
|
|
36
36
|
name: "Verify expression of outer frame",
|
|
37
37
|
targets: ["/req/basic-ypr/position"],
|
|
38
|
-
description: "To confirm
|
|
38
|
+
description: "To confirm outer frame.",
|
|
39
39
|
purpose: "Verify that this requirement is satisfied.",
|
|
40
40
|
test_method: "Inspection",
|
|
41
41
|
),
|
|
@@ -43,7 +43,7 @@ RSpec.describe Modspec::ConformanceClass do
|
|
|
43
43
|
identifier: "/conf/basic-ypr/angles",
|
|
44
44
|
name: "Verify expression of inner frame",
|
|
45
45
|
targets: ["/req/basic-ypr/angles"],
|
|
46
|
-
description: "To confirm
|
|
46
|
+
description: "To confirm inner frame.",
|
|
47
47
|
purpose: "Verify that this requirement is satisfied.",
|
|
48
48
|
test_method: "Inspection",
|
|
49
49
|
),
|
|
@@ -88,7 +88,7 @@ RSpec.describe Modspec::ConformanceClass do
|
|
|
88
88
|
identifier: "/conf/global/sdu",
|
|
89
89
|
name: "Verify SDU conformance",
|
|
90
90
|
targets: ["/req/global/sdu"],
|
|
91
|
-
description: "To confirm
|
|
91
|
+
description: "To confirm SDU conformance.",
|
|
92
92
|
purpose: "Verify that this requirement is satisfied.",
|
|
93
93
|
test_method: "Inspection",
|
|
94
94
|
),
|
|
@@ -105,11 +105,10 @@ RSpec.describe Modspec::ConformanceClass do
|
|
|
105
105
|
identifier: "/conf/tangent-point/height",
|
|
106
106
|
name: "Verify tangent point height",
|
|
107
107
|
targets: ["/req/tangent-point/height"],
|
|
108
|
-
description: "To confirm
|
|
108
|
+
description: "To confirm tangent point height.",
|
|
109
109
|
purpose: "Verify that this requirement is satisfied.",
|
|
110
110
|
test_method: "Inspection",
|
|
111
111
|
),
|
|
112
|
-
|
|
113
112
|
],
|
|
114
113
|
)
|
|
115
114
|
end
|
|
@@ -140,17 +139,25 @@ RSpec.describe Modspec::ConformanceClass do
|
|
|
140
139
|
describe "#validate" do
|
|
141
140
|
it "returns no errors for a valid conformance class" do
|
|
142
141
|
errors = suite.validate
|
|
143
|
-
if errors.any?
|
|
144
|
-
|
|
145
|
-
errors.each { |error| }
|
|
146
|
-
end
|
|
147
142
|
expect(errors).to be_empty
|
|
148
143
|
end
|
|
149
144
|
|
|
150
145
|
it "returns errors if there are no conformance tests" do
|
|
151
146
|
conformance_class.tests = []
|
|
152
147
|
errors = conformance_class.validate
|
|
153
|
-
expect(errors).
|
|
148
|
+
expect(errors).to include(a_string_matching(/no child conformance tests/))
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
it "returns errors if test identifier does not share prefix" do
|
|
152
|
+
conformance_class.tests = [
|
|
153
|
+
Modspec::ConformanceTest.new(
|
|
154
|
+
identifier: "/conf/other/test",
|
|
155
|
+
name: "Mismatched test",
|
|
156
|
+
targets: ["/req/basic-ypr/position"],
|
|
157
|
+
),
|
|
158
|
+
]
|
|
159
|
+
errors = conformance_class.validate
|
|
160
|
+
expect(errors).to include(a_string_matching(/does not share the expected prefix/))
|
|
154
161
|
end
|
|
155
162
|
end
|
|
156
163
|
end
|
|
@@ -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
|
|
|
@@ -22,7 +22,7 @@ RSpec.describe Modspec::ConformanceTest do
|
|
|
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
|
)
|
|
@@ -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,6 +65,24 @@ 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
|
|
69
87
|
|
|
70
88
|
it "has a corresponding requirement" do
|
|
@@ -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,7 +13,7 @@ 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
|
|
|
@@ -21,7 +21,7 @@ RSpec.describe Modspec::NormativeStatementsClass 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
26
|
normative_statements: [normative_statement1, normative_statement2],
|
|
27
27
|
)
|
|
@@ -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
|
@@ -38,12 +38,174 @@ RSpec.describe Modspec::Suite do
|
|
|
38
38
|
.combine(frame_spec_suite)
|
|
39
39
|
|
|
40
40
|
errors = combined_suite.validate
|
|
41
|
-
if errors.any?
|
|
42
|
-
|
|
43
|
-
errors.each { |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
|
|
@@ -63,6 +225,16 @@ RSpec.describe Modspec::Suite do
|
|
|
63
225
|
)
|
|
64
226
|
end
|
|
65
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
|
+
|
|
66
238
|
it "resolves conflicts when combining suites" do
|
|
67
239
|
combined_suite = suite1
|
|
68
240
|
.combine(suite2)
|
|
@@ -72,10 +244,6 @@ RSpec.describe Modspec::Suite do
|
|
|
72
244
|
.combine(frame_spec_suite)
|
|
73
245
|
|
|
74
246
|
errors = combined_suite.validate
|
|
75
|
-
if errors.any?
|
|
76
|
-
|
|
77
|
-
errors.each { |error| }
|
|
78
|
-
end
|
|
79
247
|
expect(errors).to be_empty
|
|
80
248
|
end
|
|
81
249
|
end
|
|
@@ -89,24 +257,13 @@ RSpec.describe Modspec::Suite do
|
|
|
89
257
|
expect(combined_suite).to be_a(described_class)
|
|
90
258
|
expect(combined_suite.name).to eq("Combined Suite")
|
|
91
259
|
|
|
92
|
-
# Ensure the combined suite has content
|
|
93
260
|
expect(combined_suite.normative_statements_classes).not_to be_empty
|
|
94
261
|
expect(combined_suite.conformance_classes).not_to be_empty
|
|
95
262
|
|
|
96
|
-
# Validate the combined suite
|
|
97
263
|
errors = combined_suite.validate
|
|
98
|
-
|
|
99
|
-
if errors.any?
|
|
100
|
-
|
|
101
|
-
errors.each { |error| }
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
# Check for specific error types
|
|
105
|
-
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/))
|
|
106
265
|
expect(errors).not_to include(a_string_matching(/Cycle detected/))
|
|
107
|
-
expect(errors).not_to include(a_string_matching(/
|
|
108
|
-
|
|
109
|
-
# 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/))
|
|
110
267
|
expect(errors).to be_empty
|
|
111
268
|
end
|
|
112
269
|
end
|
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.2.
|
|
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: 2026-05-
|
|
11
|
+
date: 2026-05-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: lutaml-model
|