ncs_mdes 0.11.0 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +16 -0
- data/Gemfile +1 -1
- data/README.md +15 -5
- data/bin/mdes-console +3 -1
- data/documents/1.2/child_or_parent_instrument_tables.yml +28 -0
- data/documents/2.0/child_or_parent_instrument_tables.yml +68 -0
- data/documents/2.1/child_or_parent_instrument_tables.yml +74 -0
- data/documents/2.2/child_or_parent_instrument_tables.yml +98 -0
- data/documents/3.0/child_or_parent_instrument_tables.yml +119 -0
- data/documents/3.1/child_or_parent_instrument_tables.yml +187 -0
- data/documents/3.2/child_or_parent_instrument_tables.yml +192 -0
- data/documents/scan_p_ids_for_children.rb +39 -0
- data/lib/ncs_navigator/mdes/code_list.rb +94 -0
- data/lib/ncs_navigator/mdes/differences/collection.rb +47 -0
- data/lib/ncs_navigator/mdes/differences/collection_criterion.rb +59 -0
- data/lib/ncs_navigator/mdes/differences/entry.rb +48 -0
- data/lib/ncs_navigator/mdes/differences/value.rb +7 -0
- data/lib/ncs_navigator/mdes/differences/value_criterion.rb +58 -0
- data/lib/ncs_navigator/mdes/differences.rb +12 -0
- data/lib/ncs_navigator/mdes/source_documents.rb +27 -0
- data/lib/ncs_navigator/mdes/specification.rb +45 -0
- data/lib/ncs_navigator/mdes/transmission_table.rb +61 -0
- data/lib/ncs_navigator/mdes/variable.rb +58 -4
- data/lib/ncs_navigator/mdes/variable_type.rb +27 -62
- data/lib/ncs_navigator/mdes/version.rb +1 -1
- data/lib/ncs_navigator/mdes.rb +5 -1
- data/spec/differences_matchers.rb +40 -0
- data/spec/ncs_navigator/mdes/code_list_spec.rb +178 -0
- data/spec/ncs_navigator/mdes/source_documents_spec.rb +14 -0
- data/spec/ncs_navigator/mdes/specification_spec.rb +30 -0
- data/spec/ncs_navigator/mdes/transmission_table_spec.rb +77 -0
- data/spec/ncs_navigator/mdes/variable_spec.rb +244 -0
- data/spec/ncs_navigator/mdes/variable_type_spec.rb +161 -40
- data/spec/spec_helper.rb +6 -0
- metadata +24 -5
@@ -29,10 +29,19 @@ module NcsNavigator::Mdes
|
|
29
29
|
# table.)
|
30
30
|
attr_accessor :variables
|
31
31
|
|
32
|
+
##
|
33
|
+
# @see #child_instrument_table?
|
34
|
+
# @return [void]
|
35
|
+
attr_writer :child_instrument_table
|
36
|
+
|
32
37
|
def initialize(name)
|
33
38
|
@name = name
|
34
39
|
end
|
35
40
|
|
41
|
+
def variables
|
42
|
+
@variables ||= []
|
43
|
+
end
|
44
|
+
|
36
45
|
##
|
37
46
|
# Search for a variable by name.
|
38
47
|
#
|
@@ -110,5 +119,57 @@ module NcsNavigator::Mdes
|
|
110
119
|
def operational_table?
|
111
120
|
!instrument_table?
|
112
121
|
end
|
122
|
+
|
123
|
+
##
|
124
|
+
# Is this a child instrument data table? (As opposed to a parent instrument
|
125
|
+
# data table or neither.)
|
126
|
+
#
|
127
|
+
# This reports the type of participant whose p_id should go in this table's
|
128
|
+
# p_id variable.
|
129
|
+
#
|
130
|
+
# Return values:
|
131
|
+
#
|
132
|
+
# * `true`: The p_id should be a child's p_id.
|
133
|
+
# * `false`: The p_id should be a parent's p_id.
|
134
|
+
# * `nil`: The table isn't an instrument data table, or it doesn't have a p_id
|
135
|
+
# variable, or the childness of the p_id isn't known.
|
136
|
+
#
|
137
|
+
# @return [true,false,nil]
|
138
|
+
def child_instrument_table?
|
139
|
+
@child_instrument_table
|
140
|
+
end
|
141
|
+
|
142
|
+
##
|
143
|
+
# Is this a parent instrument data table? (As opposed to a child instrument
|
144
|
+
# data table or neither.)
|
145
|
+
#
|
146
|
+
# This reports the type of participant whose p_id should go in this table's
|
147
|
+
# p_id variable.
|
148
|
+
#
|
149
|
+
# Return values:
|
150
|
+
#
|
151
|
+
# * `true`: The p_id should be a parent's p_id.
|
152
|
+
# * `false`: The p_id should be a child's p_id.
|
153
|
+
# * `nil`: The table isn't an instrument data table, or it doesn't have a p_id
|
154
|
+
# variable, or the childness of the p_id isn't known.
|
155
|
+
#
|
156
|
+
# @return [true,false,nil]
|
157
|
+
def parent_instrument_table?
|
158
|
+
child_instrument_table?.nil? ? nil : !child_instrument_table?
|
159
|
+
end
|
160
|
+
|
161
|
+
# @private
|
162
|
+
DIFF_CRITERIA = {
|
163
|
+
:name => Differences::ValueCriterion.new,
|
164
|
+
:variables => Differences::CollectionCriterion.new(:name)
|
165
|
+
}
|
166
|
+
|
167
|
+
##
|
168
|
+
# Computes the differences between this table and the other.
|
169
|
+
#
|
170
|
+
# @return [Differences::Entry,nil]
|
171
|
+
def diff(other_table, options={})
|
172
|
+
Differences::Entry.compute(self, other_table, DIFF_CRITERIA, options)
|
173
|
+
end
|
113
174
|
end
|
114
175
|
end
|
@@ -111,10 +111,6 @@ module NcsNavigator::Mdes
|
|
111
111
|
@name = name
|
112
112
|
end
|
113
113
|
|
114
|
-
def constraints
|
115
|
-
@constraints ||= []
|
116
|
-
end
|
117
|
-
|
118
114
|
##
|
119
115
|
# Is a value for the variable mandatory for a valid submission?
|
120
116
|
#
|
@@ -205,5 +201,63 @@ module NcsNavigator::Mdes
|
|
205
201
|
end
|
206
202
|
end
|
207
203
|
end
|
204
|
+
|
205
|
+
# @private
|
206
|
+
class EmbeddedVariableTypeCriterion
|
207
|
+
def apply(vt1, vt2, diff_options)
|
208
|
+
cvt1 = vt1 || VariableType.new
|
209
|
+
cvt2 = vt2 || VariableType.new
|
210
|
+
|
211
|
+
|
212
|
+
if cvt1.name && cvt2.name && cvt1.name == cvt2.name
|
213
|
+
# If they are named and have the same name, the differences will
|
214
|
+
# be reported once under the specification's entry for the named type.
|
215
|
+
nil
|
216
|
+
else
|
217
|
+
cvt1.diff(cvt2, diff_options)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def diff_criteria(diff_options={})
|
223
|
+
base = {
|
224
|
+
:name => Differences::ValueCriterion.new,
|
225
|
+
:type => EmbeddedVariableTypeCriterion.new,
|
226
|
+
:pii => Differences::ValueCriterion.new,
|
227
|
+
:omittable? => Differences::ValueCriterion.new(:comparator => :predicate),
|
228
|
+
:nillable? => Differences::ValueCriterion.new(:comparator => :predicate),
|
229
|
+
:table_reference => Differences::ValueCriterion.new(
|
230
|
+
:value_extractor => lambda { |o| o ? o.name : nil }
|
231
|
+
)
|
232
|
+
}
|
233
|
+
|
234
|
+
if diff_options[:strict]
|
235
|
+
base[:status] = Differences::ValueCriterion.new
|
236
|
+
else
|
237
|
+
base[:status] = Differences::ValueCriterion.new(
|
238
|
+
:comparator => lambda { |left, right|
|
239
|
+
no_change_changes = [
|
240
|
+
[:new, :active],
|
241
|
+
[:new, :modified],
|
242
|
+
[:active, :modified],
|
243
|
+
[:modified, :active]
|
244
|
+
]
|
245
|
+
|
246
|
+
no_change_changes.include?([left, right]) || (left == right)
|
247
|
+
}
|
248
|
+
)
|
249
|
+
end
|
250
|
+
|
251
|
+
base
|
252
|
+
end
|
253
|
+
protected :diff_criteria
|
254
|
+
|
255
|
+
##
|
256
|
+
# Computes the differences between this variable and the other.
|
257
|
+
#
|
258
|
+
# @return [Differences::Entry,nil]
|
259
|
+
def diff(other_variable, options={})
|
260
|
+
Differences::Entry.compute(self, other_variable, diff_criteria(options), options)
|
261
|
+
end
|
208
262
|
end
|
209
263
|
end
|
@@ -127,70 +127,35 @@ module NcsNavigator::Mdes
|
|
127
127
|
"#<#{self.class} #{attrs.join(' ')}>"
|
128
128
|
end
|
129
129
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
attr_accessor :label
|
154
|
-
|
155
|
-
##
|
156
|
-
# @return [String] the MDES's globally-unique identifier for
|
157
|
-
# this coded value.
|
158
|
-
attr_accessor :global_value
|
159
|
-
|
160
|
-
##
|
161
|
-
# @return [String] the name of MDES's master code list from
|
162
|
-
# which this value is derived.
|
163
|
-
attr_accessor :master_cl
|
164
|
-
|
165
|
-
class << self
|
166
|
-
##
|
167
|
-
# Creates a new instance from a `xs:enumeration` simple type
|
168
|
-
# restriction subelement.
|
169
|
-
#
|
170
|
-
# @param [Nokogiri::XML::Element] enum the `xs:enumeration`
|
171
|
-
# element.
|
172
|
-
# @param [Hash] options
|
173
|
-
# @option options [#warn] :log the logger to which to direct warnings
|
174
|
-
#
|
175
|
-
# @return [CodeListEntry]
|
176
|
-
def from_xsd_enumeration(enum, options={})
|
177
|
-
log = options[:log] || NcsNavigator::Mdes.default_logger
|
178
|
-
|
179
|
-
log.warn("Missing value for code list entry on line #{enum.line}") unless enum['value']
|
180
|
-
|
181
|
-
new(enum['value'] && enum['value'].strip).tap do |cle|
|
182
|
-
cle.label = enum['ncsdoc:label']
|
183
|
-
cle.global_value = enum['ncsdoc:global_value']
|
184
|
-
cle.master_cl = enum['ncsdoc:master_cl']
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
def initialize(value)
|
190
|
-
@value = value
|
130
|
+
def diff_criteria(diff_options={})
|
131
|
+
base = {
|
132
|
+
:name => Differences::ValueCriterion.new,
|
133
|
+
:base_type => Differences::ValueCriterion.new,
|
134
|
+
:pattern => Differences::ValueCriterion.new,
|
135
|
+
:max_length => Differences::ValueCriterion.new,
|
136
|
+
:min_length => Differences::ValueCriterion.new,
|
137
|
+
}
|
138
|
+
|
139
|
+
if diff_options[:strict]
|
140
|
+
base.merge(
|
141
|
+
:code_list_by_value => Differences::CollectionCriterion.new(
|
142
|
+
:value, :collection => :code_list),
|
143
|
+
:code_list_by_label => Differences::CollectionCriterion.new(
|
144
|
+
:label, :collection => :code_list)
|
145
|
+
)
|
146
|
+
else
|
147
|
+
base.merge(
|
148
|
+
:code_list_by_value => Differences::CollectionCriterion.new(
|
149
|
+
:value, :collection => :code_list),
|
150
|
+
:code_list_by_label => Differences::CollectionCriterion.new(
|
151
|
+
:label, :collection => :code_list, :value_extractor => :word_chars_downcase)
|
152
|
+
)
|
191
153
|
end
|
154
|
+
end
|
155
|
+
protected :diff_criteria
|
192
156
|
|
193
|
-
|
157
|
+
def diff(other_type, options={})
|
158
|
+
Differences::Entry.compute(self, other_type, diff_criteria(options), options)
|
194
159
|
end
|
195
160
|
end
|
196
161
|
end
|
data/lib/ncs_navigator/mdes.rb
CHANGED
@@ -4,6 +4,8 @@ module NcsNavigator
|
|
4
4
|
module Mdes
|
5
5
|
autoload :VERSION, 'ncs_navigator/mdes/version'
|
6
6
|
|
7
|
+
autoload :CodeList, 'ncs_navigator/mdes/code_list'
|
8
|
+
autoload :CodeListEntry, 'ncs_navigator/mdes/code_list'
|
7
9
|
autoload :SourceDocuments, 'ncs_navigator/mdes/source_documents'
|
8
10
|
autoload :Specification, 'ncs_navigator/mdes/specification'
|
9
11
|
autoload :TransmissionTable, 'ncs_navigator/mdes/transmission_table'
|
@@ -12,6 +14,8 @@ module NcsNavigator
|
|
12
14
|
|
13
15
|
autoload :DispositionCode, 'ncs_navigator/mdes/disposition_code'
|
14
16
|
|
17
|
+
autoload :Differences, 'ncs_navigator/mdes/differences'
|
18
|
+
|
15
19
|
##
|
16
20
|
# @return the default logger for this module when no other one is
|
17
21
|
# specified. It logs to standard error.
|
@@ -22,7 +26,7 @@ module NcsNavigator
|
|
22
26
|
|
23
27
|
##
|
24
28
|
# @return [Mdes::Specification] a new {Mdes::Specification} for the given
|
25
|
-
# version. See {Specification#initialize} for accepted options.
|
29
|
+
# version. See {Mdes::Specification#initialize} for accepted options.
|
26
30
|
def self.Mdes(version, options={})
|
27
31
|
Mdes::Specification.new(version, options)
|
28
32
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rspec/expectations'
|
2
|
+
|
3
|
+
module NcsNavigator::Mdes::Spec::Matchers
|
4
|
+
class ValueDiffMatcher
|
5
|
+
attr_reader :left, :right, :actual
|
6
|
+
|
7
|
+
def initialize(left, right)
|
8
|
+
@left = left
|
9
|
+
@right = right
|
10
|
+
end
|
11
|
+
|
12
|
+
def left_matches?(actual)
|
13
|
+
left == actual.left
|
14
|
+
end
|
15
|
+
|
16
|
+
def right_matches?(actual)
|
17
|
+
right == actual.right
|
18
|
+
end
|
19
|
+
|
20
|
+
def matches?(actual)
|
21
|
+
@actual = actual
|
22
|
+
actual && left_matches?(actual) && right_matches?(actual)
|
23
|
+
end
|
24
|
+
|
25
|
+
def failure_message_for_should
|
26
|
+
if (!actual)
|
27
|
+
"expected a difference but got none"
|
28
|
+
else
|
29
|
+
[
|
30
|
+
("expected left=#{left.inspect} but was #{actual.left.inspect}" unless left_matches?(actual)),
|
31
|
+
("expected right=#{right.inspect} but was #{actual.right.inspect}" unless right_matches?(actual))
|
32
|
+
].compact.join(' and ')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def be_a_value_diff(left, right)
|
38
|
+
ValueDiffMatcher.new(left, right)
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
module NcsNavigator::Mdes
|
6
|
+
describe CodeListEntry do
|
7
|
+
describe '.from_xsd_enumeration' do
|
8
|
+
def code_list_entry(xml_s)
|
9
|
+
CodeListEntry.from_xsd_enumeration(schema_element(xml_s), :log => logger)
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:missing) {
|
13
|
+
code_list_entry(<<-XSD)
|
14
|
+
<xs:enumeration value="-4" ncsdoc:label="Missing in Error" ncsdoc:desc="" ncsdoc:global_value="99-4" ncsdoc:master_cl="missing_data"/>
|
15
|
+
XSD
|
16
|
+
}
|
17
|
+
|
18
|
+
describe '#value' do
|
19
|
+
it 'is set' do
|
20
|
+
missing.value.should == "-4"
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'warns when missing' do
|
24
|
+
code_list_entry('<xs:enumeration ncsdoc:label="Foo"/>')
|
25
|
+
logger[:warn].first.should == 'Missing value for code list entry on line 2'
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'with external whitespace on the value' do
|
29
|
+
let(:missing) {
|
30
|
+
code_list_entry(<<-XSD)
|
31
|
+
<xs:enumeration value=" -4 " ncsdoc:label="Missing in Error" ncsdoc:desc="" ncsdoc:global_value="99-4" ncsdoc:master_cl="missing_data"/>
|
32
|
+
XSD
|
33
|
+
}
|
34
|
+
|
35
|
+
it 'removes the whitespace' do
|
36
|
+
missing.value.should == '-4'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#label" do
|
42
|
+
it 'is set' do
|
43
|
+
missing.label.should == "Missing in Error"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#global_value' do
|
48
|
+
it 'is set' do
|
49
|
+
missing.global_value.should == '99-4'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#master_cl' do
|
54
|
+
it 'is set' do
|
55
|
+
missing.master_cl.should == 'missing_data'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#to_s' do
|
61
|
+
it 'is the value' do
|
62
|
+
CodeListEntry.new('14').to_s.should == '14'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#diff' do
|
67
|
+
let(:a) { CodeListEntry.new('A') }
|
68
|
+
let(:aprime) { CodeListEntry.new('A') }
|
69
|
+
|
70
|
+
let(:diff) { a.diff(aprime) }
|
71
|
+
let(:strict_diff) { a.diff(aprime, :strict => true) }
|
72
|
+
|
73
|
+
it 'reports nothing for no differences' do
|
74
|
+
diff.should be_nil
|
75
|
+
end
|
76
|
+
|
77
|
+
describe 'value' do
|
78
|
+
let(:b) { CodeListEntry.new('B') }
|
79
|
+
|
80
|
+
it 'reports a difference' do
|
81
|
+
b.diff(a)[:value].should be_a_value_diff('B', 'A')
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe 'label' do
|
86
|
+
describe 'with a text difference' do
|
87
|
+
before do
|
88
|
+
a.label = 'Aleph'
|
89
|
+
aprime.label = 'Alpha'
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'when not strict, it reports the normalized difference' do
|
93
|
+
diff[:label].should be_a_value_diff('aleph', 'alpha')
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'when strict, it reports the literal difference' do
|
97
|
+
strict_diff[:label].should be_a_value_diff('Aleph', 'Alpha')
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe 'with a whitespace-only difference' do
|
102
|
+
before do
|
103
|
+
a.label = " a\t\tb "
|
104
|
+
aprime.label = 'a b'
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'reports a difference in strict mode' do
|
108
|
+
strict_diff[:label].should be_a_value_diff(a.label, aprime.label)
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'does not report a difference when not strict' do
|
112
|
+
diff.should be_nil
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe 'with a case-only difference' do
|
117
|
+
before do
|
118
|
+
a.label = 'AbcdEf'
|
119
|
+
aprime.label = 'aBCDeF'
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'reports a difference in strict mode' do
|
123
|
+
strict_diff[:label].should be_a_value_diff(a.label, aprime.label)
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'does not report a difference when not strict' do
|
127
|
+
diff.should be_nil
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe 'with a punctuation-only difference' do
|
132
|
+
before do
|
133
|
+
a.label = 'a,b,|c[at+]-'
|
134
|
+
aprime.label = 'a!b*&c$#at'
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'reports a difference in strict mode' do
|
138
|
+
strict_diff[:label].should be_a_value_diff(a.label, aprime.label)
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'does not report a difference when not strict' do
|
142
|
+
diff.should be_nil
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe 'global_value' do
|
148
|
+
before do
|
149
|
+
a.global_value = '0'
|
150
|
+
aprime.global_value = '-0'
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'reports a difference in strict mode' do
|
154
|
+
strict_diff[:global_value].should be_a_value_diff('0', '-0')
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'does not report a difference otherwise' do
|
158
|
+
diff.should be_nil
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe 'master_cl' do
|
163
|
+
before do
|
164
|
+
a.master_cl = 'C'
|
165
|
+
aprime.master_cl = 'Cprime'
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'reports a difference in strict mode' do
|
169
|
+
strict_diff[:master_cl].should be_a_value_diff('C', 'Cprime')
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'does not report a difference otherwise' do
|
173
|
+
diff.should be_nil
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -71,6 +71,16 @@ module NcsNavigator::Mdes
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
+
describe '#child_or_parent_instrument_tables' do
|
75
|
+
let(:property) { :child_or_parent_instrument_tables }
|
76
|
+
|
77
|
+
it_behaves_like 'an absolutizing path accessor'
|
78
|
+
|
79
|
+
it 'is optional' do
|
80
|
+
SourceDocuments.new.child_or_parent_instrument_tables.should be_nil
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
74
84
|
describe '.get' do
|
75
85
|
shared_examples 'version docs' do
|
76
86
|
subject { SourceDocuments.get(version) }
|
@@ -83,6 +93,10 @@ module NcsNavigator::Mdes
|
|
83
93
|
subject.disposition_codes.should =~ %r{#{version}/disposition_codes.yml$}
|
84
94
|
end
|
85
95
|
|
96
|
+
it 'has the correct path for the parent-child instrument tables list' do
|
97
|
+
subject.child_or_parent_instrument_tables.should =~ %r{#{version}/child_or_parent_instrument_tables.yml$}
|
98
|
+
end
|
99
|
+
|
86
100
|
it 'is of the specified version' do
|
87
101
|
subject.version.should == version
|
88
102
|
end
|
@@ -53,6 +53,18 @@ module NcsNavigator::Mdes
|
|
53
53
|
lambda { table.instrument_table? }.should_not raise_error
|
54
54
|
end
|
55
55
|
end
|
56
|
+
|
57
|
+
it 'knows the mother-childness of all p_id-bearing instrument tables' do
|
58
|
+
p_id_instrument_tables = tables.select { |t| t.instrument_table? && t.variables.collect(&:name).include?('p_id') }
|
59
|
+
p_id_instrument_tables.
|
60
|
+
reject { |t| [true, false].include?(t.child_instrument_table?) }.
|
61
|
+
collect { |t| t.name }.should == []
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'has some child and some parent instrument data tables' do
|
65
|
+
index = tables.each_with_object(Hash.new(0)) { |t, acc| acc[t.child_instrument_table?] += 1 }
|
66
|
+
index.keys.sort_by { |k| k.inspect }.should == [false, nil, true]
|
67
|
+
end
|
56
68
|
end
|
57
69
|
|
58
70
|
context 'in version 1.2' do
|
@@ -275,5 +287,23 @@ module NcsNavigator::Mdes
|
|
275
287
|
include_examples 'types fully resolved'
|
276
288
|
end
|
277
289
|
end
|
290
|
+
|
291
|
+
describe '#diff' do
|
292
|
+
let(:diff) {
|
293
|
+
Specification.new('2.0').diff(Specification.new('2.1'))
|
294
|
+
}
|
295
|
+
|
296
|
+
it 'finds different spec versions' do
|
297
|
+
diff[:specification_version].should be_a_value_diff('2.0.01.02', '2.1.00.00')
|
298
|
+
end
|
299
|
+
|
300
|
+
it 'finds different tables' do
|
301
|
+
diff[:transmission_tables].right_only.should include('preg_visit_1_saq_3')
|
302
|
+
end
|
303
|
+
|
304
|
+
it 'finds different types' do
|
305
|
+
diff[:types].right_only.should include('person_partcpnt_reltnshp_cl5')
|
306
|
+
end
|
307
|
+
end
|
278
308
|
end
|
279
309
|
end
|
@@ -179,5 +179,82 @@ XSD
|
|
179
179
|
end
|
180
180
|
end
|
181
181
|
end
|
182
|
+
|
183
|
+
describe 'parent or child instrument table accessors' do
|
184
|
+
let(:t) { TransmissionTable.new('T') }
|
185
|
+
|
186
|
+
it 'is not a parent table when it is a child table' do
|
187
|
+
t.child_instrument_table = true
|
188
|
+
t.should_not be_a_parent_instrument_table
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'is a parent table when it is definitely not a child table' do
|
192
|
+
t.child_instrument_table = false
|
193
|
+
t.should be_a_parent_instrument_table
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'is not known whether it is a parent instrument table when it is not known whether it is a child instrument table' do
|
197
|
+
t.child_instrument_table = nil
|
198
|
+
t.parent_instrument_table?.should be_nil
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
describe '#diff' do
|
203
|
+
let(:a) { TransmissionTable.new('A') }
|
204
|
+
let(:aprime) { TransmissionTable.new('A') }
|
205
|
+
|
206
|
+
describe 'name' do
|
207
|
+
let(:b) { TransmissionTable.new('B') }
|
208
|
+
|
209
|
+
it 'reports a difference when they are different' do
|
210
|
+
a.diff(b)[:name].should be_a_value_diff('A', 'B')
|
211
|
+
end
|
212
|
+
|
213
|
+
it 'reports nothing when they are the same' do
|
214
|
+
a.diff(aprime).should be_nil
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe 'variables' do
|
219
|
+
let(:v1) { Variable.new('V1') }
|
220
|
+
let(:v1prime) { Variable.new('V1') }
|
221
|
+
let(:v2) { Variable.new('V2') }
|
222
|
+
let(:v3) { Variable.new('V3') }
|
223
|
+
|
224
|
+
let(:diff) { a.diff(aprime) }
|
225
|
+
|
226
|
+
before do
|
227
|
+
a.variables << v1
|
228
|
+
aprime.variables << v1prime
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'lists variables which are in the lefthand side only' do
|
232
|
+
a.variables << v2 << v3
|
233
|
+
aprime.variables << v3
|
234
|
+
|
235
|
+
diff[:variables].left_only.should == ['V2']
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'lists variables which are in the righthand side only' do
|
239
|
+
aprime.variables << v3
|
240
|
+
|
241
|
+
diff[:variables].right_only.should == ['V3']
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'provides detailed differences for variables which are different' do
|
245
|
+
v1.pii = :possible
|
246
|
+
a.variables << v1
|
247
|
+
|
248
|
+
v1prime.pii = true
|
249
|
+
aprime.variables << v1prime
|
250
|
+
|
251
|
+
diff[:variables].entry_differences['V1'][:pii].should be_a_value_diff(:possible, true)
|
252
|
+
end
|
253
|
+
|
254
|
+
it 'does not list variables which are the same' do
|
255
|
+
diff.should be_nil
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
182
259
|
end
|
183
260
|
end
|