topographer 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +20 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +38 -0
  7. data/Rakefile +1 -0
  8. data/lib/Topographer/exceptions.rb +4 -0
  9. data/lib/Topographer/importer.rb +57 -0
  10. data/lib/Topographer/importer/helpers.rb +18 -0
  11. data/lib/Topographer/importer/helpers/write_log_to_csv.rb +85 -0
  12. data/lib/Topographer/importer/importable.rb +5 -0
  13. data/lib/Topographer/importer/input.rb +5 -0
  14. data/lib/Topographer/importer/input/base.rb +13 -0
  15. data/lib/Topographer/importer/input/roo.rb +28 -0
  16. data/lib/Topographer/importer/input/source_data.rb +8 -0
  17. data/lib/Topographer/importer/logger.rb +8 -0
  18. data/lib/Topographer/importer/logger/base.rb +69 -0
  19. data/lib/Topographer/importer/logger/fatal_error_entry.rb +19 -0
  20. data/lib/Topographer/importer/logger/file.rb +0 -0
  21. data/lib/Topographer/importer/logger/log_entry.rb +34 -0
  22. data/lib/Topographer/importer/logger/simple.rb +27 -0
  23. data/lib/Topographer/importer/mapper.rb +161 -0
  24. data/lib/Topographer/importer/mapper/default_field_mapping.rb +22 -0
  25. data/lib/Topographer/importer/mapper/field_mapping.rb +55 -0
  26. data/lib/Topographer/importer/mapper/ignored_field_mapping.rb +10 -0
  27. data/lib/Topographer/importer/mapper/result.rb +21 -0
  28. data/lib/Topographer/importer/mapper/validation_field_mapping.rb +36 -0
  29. data/lib/Topographer/importer/strategy.rb +7 -0
  30. data/lib/Topographer/importer/strategy/base.rb +42 -0
  31. data/lib/Topographer/importer/strategy/create_or_update_record.rb +50 -0
  32. data/lib/Topographer/importer/strategy/import_new_record.rb +17 -0
  33. data/lib/Topographer/importer/strategy/import_status.rb +28 -0
  34. data/lib/Topographer/importer/strategy/update_record.rb +33 -0
  35. data/lib/Topographer/version.rb +3 -0
  36. data/lib/topographer.rb +6 -0
  37. data/spec/Cartographer/importer/helpers/write_log_to_csv_spec.rb +69 -0
  38. data/spec/Cartographer/importer/helpers_spec.rb +33 -0
  39. data/spec/Cartographer/importer/importable_spec.rb +13 -0
  40. data/spec/Cartographer/importer/importer_spec.rb +132 -0
  41. data/spec/Cartographer/importer/logger/base_spec.rb +12 -0
  42. data/spec/Cartographer/importer/logger/fatal_error_entry_spec.rb +31 -0
  43. data/spec/Cartographer/importer/logger/simple_spec.rb +53 -0
  44. data/spec/Cartographer/importer/mapper/default_field_mapping_spec.rb +41 -0
  45. data/spec/Cartographer/importer/mapper/field_mapping_spec.rb +126 -0
  46. data/spec/Cartographer/importer/mapper/validation_field_mapping_spec.rb +42 -0
  47. data/spec/Cartographer/importer/mapper_spec.rb +318 -0
  48. data/spec/Cartographer/importer/strategy/base_spec.rb +43 -0
  49. data/spec/Cartographer/importer/strategy/create_or_update_record_spec.rb +46 -0
  50. data/spec/Cartographer/importer/strategy/import_new_records_spec.rb +66 -0
  51. data/spec/Cartographer/importer/strategy/import_status_spec.rb +24 -0
  52. data/spec/Cartographer/importer/strategy/mapped_model.rb +41 -0
  53. data/spec/Cartographer/importer/strategy/update_record_spec.rb +45 -0
  54. data/spec/spec_helper.rb +1 -0
  55. data/topographer.gemspec +26 -0
  56. metadata +175 -0
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe Importer::Mapper::DefaultFieldMapping do
4
+ let(:static_mapping) do
5
+ Importer::Mapper::DefaultFieldMapping.new('field1') do
6
+ 10+5
7
+ end
8
+ end
9
+ let(:failed_static_mapping) do
10
+ Importer::Mapper::DefaultFieldMapping.new('field1') do
11
+ raise 'FAILURE'
12
+ end
13
+ end
14
+
15
+ let(:result) { Importer::Mapper::Result.new('test') }
16
+ let(:result2) { Importer::Mapper::Result.new('test') }
17
+ describe '#initialize' do
18
+ it 'should not create a static mapping without a behavior block' do
19
+ expect { Importer::Mapper::DefaultFieldMapping.new('broken mapping') }.
20
+ to raise_error(Topographer::InvalidMappingError)
21
+ end
22
+ end
23
+ describe '#process_input' do
24
+ it 'should return the result of the behavior block' do
25
+ static_mapping.process_input({}, result)
26
+ expect(result.errors?).to be_false
27
+ expect(result.data['field1']).to be 15
28
+ end
29
+ it 'should record any exceptions that occur within the block as errors' do
30
+ failed_static_mapping.process_input({}, result)
31
+ expect(result.errors?).to be_true
32
+ expect(result.errors.values).to include('FAILURE')
33
+ end
34
+ it 'should not rescue Exceptions that do not inherit from standard error' do
35
+ mapper = Importer::Mapper::DefaultFieldMapping.new('output_column') do
36
+ raise Exception, 'Field1 MUST BE 4'
37
+ end
38
+ expect{ mapper.process_input({'field1' => false}, result) }.to raise_error(Exception)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,126 @@
1
+ require 'spec_helper'
2
+
3
+ describe Importer::Mapper::FieldMapping do
4
+ let(:required_simple_mapping) { Importer::Mapper::FieldMapping.new(true, ['field1'], 'output_column') }
5
+ let(:required_simple_mapping_with_validation) do
6
+ Importer::Mapper::FieldMapping.new(true, ['field1'], 'output_column') do |input|
7
+ if input['field1'] != 4
8
+ raise 'Field1 MUST BE 4'
9
+ end
10
+ end
11
+ end
12
+ let(:required_complex_mapping) do
13
+ Importer::Mapper::FieldMapping.new(true, ['field1', 'field2', 'field3'], 'output_column') do |input|
14
+ if input['field1'] != 4
15
+ raise 'Field1 MUST BE 4'
16
+ end
17
+ input.values.flatten.inject(0) {|sum, x| sum+x}
18
+ end
19
+ end
20
+ let(:optional_simple_mapping) { Importer::Mapper::FieldMapping.new(false, 'field1', 'output_column') }
21
+ let(:optional_complex_mapping) do
22
+ Importer::Mapper::FieldMapping.new(false, ['field1', 'field2', 'field3'], 'output_column') do |input|
23
+ if input['field1'] != 4
24
+ raise 'Field1 MUST BE 4'
25
+ end
26
+ input.values.flatten.inject(0) {|sum, x| sum+x}
27
+ end
28
+ end
29
+ let(:valid_input) do
30
+ {'field1' => 4, 'field2' => 5, 'field3' => 6}
31
+ end
32
+ let(:invalid_complex_input) do
33
+ {'field1' => 3, 'field2' => 4, 'field3' => 5}
34
+ end
35
+ let(:result) { Importer::Mapper::Result.new('test') }
36
+ describe '#process_input' do
37
+ context 'required mappings' do
38
+ it 'maps required simple mappings when input is valid' do
39
+ required_simple_mapping.process_input(valid_input, result)
40
+ expect(result.errors?).to be_false
41
+ expect(result.data['output_column']).to eql(4)
42
+ end
43
+ it 'maps required complex mappings when input is valid' do
44
+ required_complex_mapping.process_input(valid_input, result)
45
+ expect(result.errors?).to be_false
46
+ expect(result.data['output_column']).to eql(15)
47
+ end
48
+ it 'returns an error for required simple mappings when the input key is missing' do
49
+ required_simple_mapping.process_input({}, result)
50
+ expect(result.errors?).to be_true
51
+ expect(result.errors.values).to include('Missing required input(s): `field1` for `output_column`')
52
+ expect(result.data.empty?).to be_true
53
+ end
54
+ it 'returns an error for required simple mappings when the input data is blank' do
55
+ required_simple_mapping.process_input({'field1' => nil}, result)
56
+ expect(result.errors?).to be_true
57
+ expect(result.errors.values).to include('Missing required input(s): `field1` for `output_column`')
58
+ expect(result.data['output_column']).to be_nil
59
+ end
60
+ it 'returns an error for required simple mappings when the mapping block raises an exception' do
61
+ required_simple_mapping_with_validation.process_input({'field1' => 3}, result)
62
+ expect(result.errors?).to be_true
63
+ expect(result.errors.values).to include('Field1 MUST BE 4')
64
+ expect(result.data.empty?).to be_true
65
+ end
66
+ it 'returns an error for required complex mappings when the input key is missing' do
67
+ required_complex_mapping.process_input({'field1' => 4}, result)
68
+ expect(result.errors?).to be_true
69
+ expect(result.errors.values).to include('Missing required input(s): `field2, field3` for `output_column`')
70
+ expect(result.data.empty?).to be_true
71
+ end
72
+ it 'returns an error for required complex mappings when the mapping block raises an exception' do
73
+ required_complex_mapping.process_input(invalid_complex_input, result)
74
+ expect(result.errors?).to be_true
75
+ expect(result.errors.values).to include('Field1 MUST BE 4')
76
+ expect(result.data.empty?).to be_true
77
+ end
78
+ end
79
+ context 'optional mappings' do
80
+ it 'maps optional simple mappings when input is valid' do
81
+ optional_simple_mapping.process_input(valid_input, result)
82
+ expect(result.errors?).to be_false
83
+ expect(result.data['output_column']).to eql(4)
84
+ end
85
+ it 'maps optional complex mappings when input is valid' do
86
+ optional_complex_mapping.process_input(valid_input, result)
87
+ expect(result.errors?).to be_false
88
+ expect(result.data['output_column']).to eql(15)
89
+ end
90
+ it 'does not return an error for optional simple mappings when the input key is missing' do
91
+ optional_simple_mapping.process_input({}, result)
92
+ expect(result.errors?).to be_false
93
+ expect(result.data.empty?).to be_true
94
+ end
95
+ it 'does not return an error for optional simple mappings when the input data is blank' do
96
+ optional_simple_mapping.process_input({'field1' => nil}, result)
97
+ expect(result.errors?).to be_false
98
+ expect(result.data['output_column']).to be_nil
99
+ end
100
+ it 'does not return an error for optional complex mappings when an input key is missing' do
101
+ optional_complex_mapping.process_input({'field1' => 4}, result)
102
+ expect(result.errors?).to be_false
103
+ expect(result.data.empty?).to be_true
104
+ end
105
+ it 'returns an error for optional complex mappings when the mapping block raises an exception' do
106
+ optional_complex_mapping.process_input(invalid_complex_input, result)
107
+ expect(result.errors?).to be_true
108
+ expect(result.errors.values).to include('Field1 MUST BE 4')
109
+ expect(result.data.empty?).to be_true
110
+ end
111
+ end
112
+ it 'maps data when the result of the mapping is a false value' do
113
+ #required_simple_mapping.stub(:apply_mapping).and_return(false)
114
+ required_simple_mapping.process_input({'field1' => false}, result)
115
+ expect(result.errors?).to be_false
116
+ expect(result.data['output_column']).to eql(false)
117
+ end
118
+ it 'should not rescue Exceptions that do not inherit from standard error' do
119
+ mapper = Importer::Mapper::FieldMapping.new(true, 'field1', 'output_column') do |input|
120
+ raise Exception, 'Field1 MUST BE 4'
121
+ end
122
+ expect{ mapper.process_input({'field1' => false}, result) }.to raise_error(Exception)
123
+ end
124
+
125
+ end
126
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe Importer::Mapper::ValidationFieldMapping do
4
+ let(:validation_mapping) do
5
+ Importer::Mapper::ValidationFieldMapping.new('test mapping', ['field1', 'field2', 'field3']) do |input|
6
+ sum = input.values.flatten.inject(0) {|sum, x| sum+x}
7
+ raise 'Sum must be 15' if sum != 15
8
+ end
9
+ end
10
+ let(:valid_input) do
11
+ {'field1' => 4, 'field2' => 5, 'field3' => 6}
12
+ end
13
+ let(:invalid_input) do
14
+ {'field1' => 3, 'field2' => 4, 'field3' => 5}
15
+ end
16
+ let(:result) { Importer::Mapper::Result.new('test') }
17
+ describe '#initialize' do
18
+ it 'should not create a validation mapping without a behavior block' do
19
+ expect { Importer::Mapper::ValidationFieldMapping.new('test mapping', ['field1', 'field2', 'field3']) }.
20
+ to raise_error(Topographer::InvalidMappingError)
21
+ end
22
+ end
23
+ describe '#process_input' do
24
+ it 'should not return an error if the validation block passes' do
25
+ validation_mapping.process_input(valid_input, result)
26
+ expect(result.errors?).to be_false
27
+ expect(result.data.blank?).to be_true
28
+ end
29
+ it 'should return an error if the validation block raises an error' do
30
+ validation_mapping.process_input(invalid_input, result)
31
+ expect(result.errors?).to be_true
32
+ expect(result.errors.values).to include('Sum must be 15')
33
+ end
34
+ it 'should not rescue Exceptions that do not inherit from standard error' do
35
+ mapper = Importer::Mapper::ValidationFieldMapping.new('test mapping', ['field1', 'field2', 'field3']) do |input|
36
+ sum = input.values.flatten.inject(0) {|sum, x| sum+x}
37
+ raise Exception, 'Sum must be 15' if sum != 15
38
+ end
39
+ expect{ mapper.process_input(invalid_input, result) }.to raise_error(Exception)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,318 @@
1
+ require 'spec_helper'
2
+
3
+ describe Importer::Mapper do
4
+ describe '.build_mapper' do
5
+ describe 'required mappings' do
6
+ it 'can require a one to one field mapping' do
7
+ mapper = Importer::Mapper.build_mapper(Object) do |m|
8
+ m.required_mapping 'Field1', 'field_1'
9
+ end
10
+ mapper.required_columns.should include("Field1")
11
+ mapper.output_fields.should include('field_1')
12
+ end
13
+ it 'can require a many to one field mapping' do
14
+ mapper = Importer::Mapper.build_mapper(Object) do |m|
15
+ m.required_mapping ['Field1', 'Field2'], 'field_1'
16
+ end
17
+ mapper.required_columns.should include("Field1", "Field2")
18
+ mapper.output_fields.should include('field_1')
19
+ end
20
+ it 'cannot require a one to many field mapping' do
21
+ expect { mapper = Importer::Mapper.build_mapper(Object) do |m|
22
+ m.required_mapping 'Field1', ['field_1', 'field_2']
23
+ end
24
+ }.to raise_error(Topographer::InvalidMappingError)
25
+ end
26
+ end
27
+ describe 'optional mappings' do
28
+ it 'can create an optional one to one field mapping' do
29
+ mapper = Importer::Mapper.build_mapper(Object) do |m|
30
+ m.optional_mapping 'Field1', 'field_1'
31
+ end
32
+ mapper.optional_columns.should include("Field1")
33
+ mapper.output_fields.should include('field_1')
34
+ end
35
+ it 'can create an optional many to one field mapping' do
36
+ mapper = Importer::Mapper.build_mapper(Object) do |m|
37
+ m.optional_mapping ['Field1', 'Field2'], 'field_1'
38
+ end
39
+ mapper.optional_columns.should include("Field1", "Field2")
40
+ mapper.output_fields.should include('field_1')
41
+ end
42
+ it 'cannot create an optional one to many field mapping' do
43
+ expect { mapper = Importer::Mapper.build_mapper(Object) do |m|
44
+ m.optional_mapping 'Field1', ['field_1', 'field_2']
45
+ end
46
+ }.to raise_error(Topographer::InvalidMappingError)
47
+ end
48
+ end
49
+ describe 'ignored mappings' do
50
+ it 'can ignore a column' do
51
+ mapper = Importer::Mapper.build_mapper(Object) do |m|
52
+ m.ignored_column 'Field1'
53
+ end
54
+ mapper.ignored_columns.should include('Field1')
55
+ mapper.output_fields.should be_empty
56
+ end
57
+
58
+ it 'raises an error when adding a mapping whose output is already an output of another mapping' do
59
+ expect { Importer::Mapper.build_mapper(Object) do |m|
60
+ m.optional_mapping 'Field1', 'field_1'
61
+ m.required_mapping 'Field2', 'field_1'
62
+ end }.to raise_error(Topographer::InvalidMappingError)
63
+ end
64
+
65
+ it 'raises an error when adding a ignored column, which is already an input of another mapping' do
66
+ expect { Importer::Mapper.build_mapper(Object) do |m|
67
+ m.optional_mapping 'Field1', 'field_1'
68
+ m.ignored_column 'Field1'
69
+ end }.to raise_error(Topographer::InvalidMappingError)
70
+ end
71
+
72
+ it 'raises an error when adding a mapped column which has already been ignored' do
73
+ expect { Importer::Mapper.build_mapper(Object) do |m|
74
+ m.ignored_column 'Field1'
75
+ m.optional_mapping 'Field1', 'field_1'
76
+ end }.to raise_error(Topographer::InvalidMappingError)
77
+ end
78
+ end
79
+
80
+ describe 'validation mappings' do
81
+ it 'can create a single column validation' do
82
+ mapper = Importer::Mapper.build_mapper(Object) do |m|
83
+ m.validation_field 'Field 1 Validation', 'Field1' do |input|
84
+ raise 'No Input' unless input
85
+ end
86
+ end
87
+ expect(mapper.validation_columns).to include('Field1')
88
+ expect(mapper.output_fields.empty?).to be_true
89
+ end
90
+ it 'can create a multicolumn validation' do
91
+ mapper = Importer::Mapper.build_mapper(Object) do |m|
92
+ m.validation_field 'Multicolumn Validation', ['Field1', 'Field2'] do |input|
93
+ raise 'No Input' unless input
94
+ end
95
+ end
96
+ expect(mapper.validation_columns).to eql(['Field1', 'Field2'])
97
+ expect(mapper.output_fields.empty?).to be_true
98
+ end
99
+ it 'raises an error if a validation name is repeated' do
100
+ expect {
101
+ mapper = Importer::Mapper.build_mapper(Object) do |m|
102
+ m.validation_field 'Field 1 Validation', 'Field1' do |input|
103
+ raise 'No Input' unless input
104
+ end
105
+ m.validation_field('Field 1 Validation', 'Field1') { |input| raise 'Test Error' }
106
+ end
107
+ }.to raise_error( Topographer::InvalidMappingError )
108
+ end
109
+ end
110
+
111
+ describe 'static mappings' do
112
+ it 'can create a static mapping' do
113
+ mapper = Importer::Mapper.build_mapper(Object) do |m|
114
+ m.default_value 'Field1' do
115
+ 34
116
+ end
117
+ end
118
+ expect(mapper.default_fields).to eql(['Field1'])
119
+ expect(mapper.output_fields).to eql(['Field1'])
120
+ end
121
+ it 'cannot create a static mapping to many columns' do
122
+ expect { mapper = Importer::Mapper.build_mapper(Object) do |m|
123
+ m.default_value ['Field1', 'Field2'] do
124
+ 34
125
+ end
126
+ end }.to raise_error(Topographer::InvalidMappingError)
127
+ end
128
+ it 'cannot add a static mapping to a field that has already been mapped' do
129
+ expect { mapper = Importer::Mapper.build_mapper(Object) do |m|
130
+ m.required_mapping 'Field1', 'field1'
131
+ m.default_value 'field1' do
132
+ 34
133
+ end
134
+ end }.to raise_error(Topographer::InvalidMappingError)
135
+ end
136
+ end
137
+
138
+ it 'associates the model class with the mapper instance' do
139
+ mapper = Importer::Mapper.build_mapper(Object) do |m|
140
+ m.ignored_column 'Field1'
141
+ m.optional_mapping 'Field2', 'field_1'
142
+ end
143
+ expect(mapper.model_class).to be Object
144
+ end
145
+ end
146
+
147
+ describe '#key_field' do
148
+ let(:mapper) { Importer::Mapper.new(Object) }
149
+ it 'should add a key field to the list of key fields' do
150
+ mapper.key_field 'Field1'
151
+ expect(mapper.key_fields).to eql(['Field1'])
152
+ end
153
+ it 'should not allow multiple key fields at one time' do
154
+ expect {
155
+ mapper.key_field ['Field1', 'Field2']
156
+ }.to raise_error(Topographer::InvalidMappingError)
157
+ end
158
+ it 'should not allow the same key field more than once' do
159
+ expect {
160
+ mapper.key_field 'Field1'
161
+ mapper.key_field 'Field1'
162
+ }.to raise_error(Topographer::InvalidMappingError)
163
+ end
164
+ end
165
+
166
+ describe '#input_structure_valid?' do
167
+ let(:mapper) do
168
+ Importer::Mapper.build_mapper(Object) do |m|
169
+ m.required_mapping 'Field1', 'field1'
170
+ m.required_mapping 'Field2', 'field_4'
171
+ m.optional_mapping 'Field3', 'field_6'
172
+ m.validation_field('test validation', 'Field4') { |input| raise 'FAILURE' if !input }
173
+ m.ignored_column 'Field5'
174
+ end
175
+ end
176
+
177
+ let(:valid_input_structure_with_options) { ['Field1', 'Field2', 'Field3', 'Field4'] }
178
+ let(:valid_input_structure_without_options) { ['Field1', 'Field2', 'Field4'] }
179
+ let(:missing_required_column_structure) { ['Field1', 'Field3'] }
180
+ let(:missing_validation_column_structure) { ['Field1', 'Field2', 'Field3'] }
181
+ let(:bad_column_structure) { ['Field1', 'UnknownField', 'Field2', 'Field4'] }
182
+
183
+ it 'returns false if required fields are missing' do
184
+ expect(mapper.input_structure_valid?(missing_required_column_structure)).to be_false
185
+ end
186
+ it 'returns false if a validation field is missing' do
187
+ expect(mapper.input_structure_valid?(missing_validation_column_structure)).to be_false
188
+ end
189
+ it 'returns true if all of the required fields are present' do
190
+ expect(mapper.input_structure_valid?(valid_input_structure_without_options)).to be_true
191
+ end
192
+ it 'returns true if all the required and optional fields are present' do
193
+ expect(mapper.input_structure_valid?(valid_input_structure_with_options)).to be_true
194
+ end
195
+ it 'returns true regardless of whether ignored fields are present' do
196
+ expect(mapper.input_structure_valid?(valid_input_structure_with_options)).to be_true
197
+ expect(mapper.input_structure_valid?(valid_input_structure_with_options+['Field5'])).to be_true
198
+ end
199
+ it 'returns false if there are any extra fields that have not been ignored' do
200
+ mapper.input_structure_valid?(bad_column_structure).should be_false
201
+ end
202
+ end
203
+
204
+ describe '#bad_columns' do
205
+ let(:mapper) do
206
+ Importer::Mapper.build_mapper(Object) do |m|
207
+ m.required_mapping 'Field1', 'field1'
208
+ m.required_mapping 'Field2', 'field_4'
209
+ m.validation_field('test validation 2', 'Field2') { |input| raise 'FAILURE' if !input }
210
+ m.optional_mapping 'Field3', 'field_6'
211
+ m.validation_field('test validation', 'Field4') { |input| raise 'FAILURE' if !input }
212
+ m.ignored_column 'Field5'
213
+ end
214
+ end
215
+ let(:bad_column_structure) { ['Field1', 'Bad Field', 'Field3'] }
216
+
217
+ it 'should return bad column names' do
218
+ mapper.input_structure_valid?(bad_column_structure)
219
+ expect(mapper.bad_columns).to eql(['Bad Field'])
220
+ end
221
+ end
222
+
223
+ describe '#missing_columns' do
224
+ let(:mapper) do
225
+ Importer::Mapper.build_mapper(Object) do |m|
226
+ m.required_mapping 'Field1', 'field1'
227
+ m.required_mapping 'Field2', 'field_4'
228
+ m.optional_mapping 'Field3', 'field_6'
229
+ m.validation_field('test validation', 'Field4') { |input| raise 'FAILURE' if !input }
230
+ m.ignored_column 'Field5'
231
+ end
232
+ end
233
+ let(:missing_column_structure) { ['Field1'] }
234
+
235
+ it 'should return missing column names' do
236
+ mapper.input_structure_valid?(missing_column_structure)
237
+ expect(mapper.missing_columns).to eql(['Field2', 'Field4'])
238
+ end
239
+ end
240
+
241
+ describe '#map_input' do
242
+ let(:mapper) do
243
+ Importer::Mapper.build_mapper(Object) do |m|
244
+ m.required_mapping 'Field1', 'field_1'
245
+ m.required_mapping ['Field1', 'Field2'], 'field_2'
246
+ m.validation_field('Field2 Validation', 'Field2') { |input| raise 'FAILURE' if input['Field2'] != 'datum2'}
247
+ m.required_mapping('Field1', 'field_3') { |x| x['Field1'].length }
248
+ m.required_mapping(['Field1', 'Field3'], 'field_4') { |x| x['Field1'].length * x['Field3'] }
249
+ m.default_value('static_field') { 34 }
250
+ m.optional_mapping('Field4', 'field_5')
251
+ end
252
+ end
253
+ let(:valid_input) do
254
+ double 'SourceData',
255
+ source_identifier: 'row1',
256
+ data: {'Field1' => 'datum1',
257
+ 'Field2' => 'datum2',
258
+ 'Field3' => 6}
259
+ end
260
+
261
+ let(:invalid_data_input) do
262
+ double 'SourceData',
263
+ source_identifier: 'row1',
264
+ data: {'Field1' => 'datum1',
265
+ 'Field2' => 'bad_field2_data',
266
+ 'Field3' => 6}
267
+ end
268
+
269
+ let(:missing_field_input) do
270
+ double 'SourceData',
271
+ source_identifier: 'row1',
272
+ data: {'Field1' => 'datum1',
273
+ 'Field2' => 'datum2'}
274
+ end
275
+
276
+ let(:result) do
277
+ mapper.map_input(valid_input)
278
+ end
279
+
280
+
281
+ it 'maps one to one field information' do
282
+ expect(result.data['field_1']).to eql('datum1')
283
+ end
284
+
285
+ it 'maps many to one field information' do
286
+ expect(result.data['field_2']).to eql('datum1, datum2')
287
+ end
288
+
289
+ it 'maps one to one field information with complex behavior' do
290
+ expect(result.data['field_3']).to eql(6)
291
+ end
292
+
293
+ it 'maps many to one field information with complex behavior' do
294
+ expect(result.data['field_4']).to eql(36)
295
+ end
296
+
297
+ it 'maps static fields' do
298
+ expect(result.data['static_field']).to eql(34)
299
+ end
300
+
301
+ it 'returns an error if required field is missing in input data' do
302
+ invalid_field_result = mapper.map_input(missing_field_input)
303
+ expect(invalid_field_result.errors?).to be_true
304
+ expect(invalid_field_result.errors['field_4']).to include('Missing required input(s): `Field3` for `field_4`')
305
+ end
306
+
307
+ it 'returns an error if a validation does not pass' do
308
+ invalid_data_result = mapper.map_input(invalid_data_input)
309
+ expect(invalid_data_result.errors?).to be_true
310
+ expect(invalid_data_result.errors['Field2 Validation']).to include('FAILURE')
311
+
312
+ end
313
+
314
+ it 'does not return an error if an optional field is missing in the input data' do
315
+ expect(result.errors?).to be_false
316
+ end
317
+ end
318
+ end