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.
Files changed (35) hide show
  1. data/CHANGELOG.md +16 -0
  2. data/Gemfile +1 -1
  3. data/README.md +15 -5
  4. data/bin/mdes-console +3 -1
  5. data/documents/1.2/child_or_parent_instrument_tables.yml +28 -0
  6. data/documents/2.0/child_or_parent_instrument_tables.yml +68 -0
  7. data/documents/2.1/child_or_parent_instrument_tables.yml +74 -0
  8. data/documents/2.2/child_or_parent_instrument_tables.yml +98 -0
  9. data/documents/3.0/child_or_parent_instrument_tables.yml +119 -0
  10. data/documents/3.1/child_or_parent_instrument_tables.yml +187 -0
  11. data/documents/3.2/child_or_parent_instrument_tables.yml +192 -0
  12. data/documents/scan_p_ids_for_children.rb +39 -0
  13. data/lib/ncs_navigator/mdes/code_list.rb +94 -0
  14. data/lib/ncs_navigator/mdes/differences/collection.rb +47 -0
  15. data/lib/ncs_navigator/mdes/differences/collection_criterion.rb +59 -0
  16. data/lib/ncs_navigator/mdes/differences/entry.rb +48 -0
  17. data/lib/ncs_navigator/mdes/differences/value.rb +7 -0
  18. data/lib/ncs_navigator/mdes/differences/value_criterion.rb +58 -0
  19. data/lib/ncs_navigator/mdes/differences.rb +12 -0
  20. data/lib/ncs_navigator/mdes/source_documents.rb +27 -0
  21. data/lib/ncs_navigator/mdes/specification.rb +45 -0
  22. data/lib/ncs_navigator/mdes/transmission_table.rb +61 -0
  23. data/lib/ncs_navigator/mdes/variable.rb +58 -4
  24. data/lib/ncs_navigator/mdes/variable_type.rb +27 -62
  25. data/lib/ncs_navigator/mdes/version.rb +1 -1
  26. data/lib/ncs_navigator/mdes.rb +5 -1
  27. data/spec/differences_matchers.rb +40 -0
  28. data/spec/ncs_navigator/mdes/code_list_spec.rb +178 -0
  29. data/spec/ncs_navigator/mdes/source_documents_spec.rb +14 -0
  30. data/spec/ncs_navigator/mdes/specification_spec.rb +30 -0
  31. data/spec/ncs_navigator/mdes/transmission_table_spec.rb +77 -0
  32. data/spec/ncs_navigator/mdes/variable_spec.rb +244 -0
  33. data/spec/ncs_navigator/mdes/variable_type_spec.rb +161 -40
  34. data/spec/spec_helper.rb +6 -0
  35. 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
- # A specialization of `Array` for code lists.
132
- #
133
- # @see VariableType#code_list
134
- # @see CodeListEntry
135
- class CodeList < Array
136
- ##
137
- # @return [String,nil] the description of the code list if any.
138
- attr_accessor :description
139
- end
140
-
141
- ##
142
- # A single entry in a code list.
143
- #
144
- # @see VariableType#code_list
145
- # @see CodeList
146
- class CodeListEntry
147
- ##
148
- # @return [String] the local code value for the entry.
149
- attr_reader :value
150
-
151
- ##
152
- # @return [String] the human-readable label for the entry.
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
- alias :to_s :value
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
@@ -1,5 +1,5 @@
1
1
  module NcsNavigator
2
2
  module Mdes
3
- VERSION = '0.11.0'
3
+ VERSION = '0.12.0'
4
4
  end
5
5
  end
@@ -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