rets 0.1.0

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.
@@ -0,0 +1,452 @@
1
+ require "helper"
2
+
3
+ class TestMetadata < Test::Unit::TestCase
4
+ def setup
5
+ @root = Rets::Metadata::Root.new
6
+ end
7
+
8
+ def test_metadata_root_fetch_sources_returns_hash_of_metadata_types
9
+ types = []
10
+ fake_fetcher = lambda do |type|
11
+ types << type
12
+ end
13
+
14
+ @root.fetch_sources(&fake_fetcher)
15
+
16
+ assert_equal(Rets::Metadata::METADATA_TYPES, types)
17
+ end
18
+
19
+ def test_metadata_root_intialized_with_block
20
+ external = false
21
+ Rets::Metadata::Root.new { |source| external = true }
22
+ assert external
23
+ end
24
+
25
+ def test_metadata_root_build_tree
26
+ resource = stub(:id => "X")
27
+ Rets::Metadata::Resource.stubs(:build => resource)
28
+ resource_fragment = stub(:resource_fragment)
29
+ resource_container = stub(:rows => [resource_fragment])
30
+ @root.stubs(:metadata_types => { :resource => [resource_container] })
31
+ assert_equal({"x" => resource}, @root.build_tree)
32
+ assert_equal(resource, @root.build_tree["X"])
33
+ end
34
+
35
+ def test_metadata_root_version
36
+ @root.instance_variable_set("@metadata_types", {:system => [stub(:version => "1")]})
37
+ assert_equal "1", @root.version
38
+ end
39
+
40
+ def test_metadata_root_date
41
+ @root.instance_variable_set("@metadata_types", {:system => [stub(:date => "1")]})
42
+ assert_equal "1", @root.date
43
+ end
44
+
45
+ def test_metadata_root_different_version
46
+ @root.stubs(:version).returns("1.2.2")
47
+ @root.stubs(:date).returns("1")
48
+
49
+ current_version = "1.2.3"
50
+ current_timestamp = "1"
51
+
52
+ assert !@root.current?(current_timestamp, current_version)
53
+ end
54
+
55
+ def test_metadata_root_same_version
56
+ @root.stubs(:version).returns("1.2.2")
57
+ @root.stubs(:date).returns("1")
58
+
59
+ current_version = "1.2.2"
60
+ current_timestamp = "2"
61
+
62
+ assert @root.current?(current_timestamp, current_version)
63
+ end
64
+
65
+ def test_metadata_root_no_version_same_timestamp
66
+ @root.stubs(:version).returns("")
67
+ @root.stubs(:date).returns("1")
68
+
69
+ current_version = "1.2.3"
70
+ current_timestamp = "1"
71
+
72
+ assert @root.current?(current_timestamp, current_version)
73
+ end
74
+
75
+ def test_metadata_root_current
76
+ @root.stubs(:version).returns("1.2.2")
77
+ @root.stubs(:date).returns("1")
78
+
79
+ current_timestamp = "1"
80
+ current_version = "1.2.2"
81
+
82
+ assert @root.current?(current_timestamp, current_version)
83
+ end
84
+
85
+ # missing timestamp - this happens in violation of the spec.
86
+ def test_metadata_root_current_ignores_missing_timestamp
87
+ @root.stubs(:version).returns("1.2.2")
88
+ @root.stubs(:date).returns("1")
89
+
90
+ current_timestamp = nil
91
+ current_version = "1.2.2"
92
+
93
+ assert @root.current?(current_timestamp, current_version)
94
+ end
95
+
96
+ # missing version - this happens in violation of the spec.
97
+ def test_metadata_root_current_ignores_missing_version
98
+ @root.stubs(:version).returns("1.2.2")
99
+ @root.stubs(:date).returns("1")
100
+
101
+ current_timestamp = "1"
102
+ current_version = nil
103
+
104
+ assert @root.current?(current_timestamp, current_version)
105
+ end
106
+
107
+ def test_metadata_root_metadata_types_constructs_a_hash_of_metadata_types_from_sources
108
+ test_sources = { "X" => "Y", "Z" => "W" }
109
+ @root.stubs(:sources => test_sources, :build_containers => "Y--")
110
+ @root.metadata_types = nil
111
+ Nokogiri.stubs(:parse => "Y-")
112
+ assert_equal({:x => "Y--", :z => "Y--"}, @root.metadata_types)
113
+ end
114
+
115
+ def test_metadata_root_build_containers_selects_correct_tags
116
+ doc = "<RETS><METADATA-FOO></METADATA-FOO><MET-FOO></MET-FOO><METADATA-BAR /></RETS>"
117
+
118
+ @root.expects(:build_container).with { |fragment| fragment.name == "METADATA-FOO" }
119
+ @root.expects(:build_container).with { |fragment| fragment.name == "METADATA-BAR" }
120
+
121
+ @root.build_containers(Nokogiri.parse(doc))
122
+ end
123
+
124
+ def test_metadata_root_build_container_uses_row_containers_for_resource
125
+ doc = Nokogiri.parse(METADATA_RESOURCE).xpath("//METADATA-RESOURCE").first
126
+
127
+ container = @root.build_container(doc)
128
+
129
+ assert_instance_of Rets::Metadata::Containers::ResourceContainer, container
130
+
131
+ assert_equal 13, container.resources.size
132
+
133
+ resource = container.resources.first
134
+
135
+ assert_equal "ActiveAgent", resource["StandardName"]
136
+ end
137
+
138
+ def test_metadata_root_build_container_uses_system_container_for_system
139
+ doc = Nokogiri.parse(METADATA_SYSTEM).xpath("//METADATA-SYSTEM").first
140
+
141
+ container = @root.build_container(doc)
142
+ assert_instance_of Rets::Metadata::Containers::SystemContainer, container
143
+ end
144
+
145
+ def test_metadata_root_build_container_uses_base_container_for_unknown_metadata_types
146
+ doc = Nokogiri.parse(METADATA_UNKNOWN).xpath("//METADATA-FOO").first
147
+
148
+ container = @root.build_container(doc)
149
+ assert_instance_of Rets::Metadata::Containers::Container, container
150
+ end
151
+
152
+ def test_metadata_uses
153
+ #TODO
154
+ end
155
+
156
+ def test_resource_initialize
157
+ fragment = { "ResourceID" => 'r' }
158
+ resource = Rets::Metadata::Resource.new(fragment)
159
+ assert_equal('r', resource.id)
160
+ assert_equal([], resource.rets_classes)
161
+ end
162
+
163
+ def test_resource_build_lookup_tree
164
+ metadata = stub(:metadata)
165
+ resource = stub(:resource)
166
+
167
+ Rets::Metadata::Resource.expects(:find_lookup_containers).
168
+ with(metadata, resource).
169
+ returns([stub(:lookups => [{"LookupName" => "Foo"}])])
170
+
171
+ Rets::Metadata::Resource.expects(:find_lookup_type_containers).
172
+ with(metadata, resource, "Foo").
173
+ returns([stub(:lookup_types => [{"Value" => "111", "LongValue" => "Bar"}])])
174
+
175
+ tree = Rets::Metadata::Resource.build_lookup_tree(resource, metadata)
176
+
177
+ assert_equal ["Foo"], tree.keys
178
+ assert_equal 1, tree["Foo"].size
179
+
180
+ lookup_type = tree["Foo"].first
181
+
182
+ assert_equal "111", lookup_type.value
183
+ assert_equal "Bar", lookup_type.long_value
184
+ end
185
+
186
+ def test_resource_build_classes
187
+ resource = stub(:resource)
188
+ metadata = stub(:metadata)
189
+ rets_class = stub(:rets_class)
190
+ rets_class_fragment = stub(:rets_class_fragment)
191
+
192
+ Rets::Metadata::RetsClass.expects(:build).with(rets_class_fragment, resource, metadata).returns(rets_class)
193
+ Rets::Metadata::Resource.expects(:find_rets_classes).with(metadata, resource).returns([rets_class_fragment])
194
+
195
+ classes = Rets::Metadata::Resource.build_classes(resource, metadata)
196
+ assert([rets_class], classes)
197
+ end
198
+
199
+ def test_resource_build
200
+ fragment = { "ResourceID" => "test" }
201
+
202
+ lookup_types = stub(:lookup_types)
203
+ classes = stub(:classes)
204
+ metadata = stub(:metadata)
205
+
206
+ Rets::Metadata::Resource.stubs(:build_lookup_tree => lookup_types)
207
+ Rets::Metadata::Resource.stubs(:build_classes => classes)
208
+
209
+ resource = Rets::Metadata::Resource.build(fragment, metadata)
210
+
211
+ assert_equal(lookup_types, resource.lookup_types)
212
+ assert_equal(classes, resource.rets_classes)
213
+ end
214
+
215
+ def test_resource_find_lookup_containers
216
+ resource = stub(:id => "id")
217
+ metadata = { :lookup => [stub(:resource => "id"), stub(:resource => "id"), stub(:resource => "a")] }
218
+
219
+ lookup_containers = Rets::Metadata::Resource.find_lookup_containers(metadata, resource)
220
+
221
+ assert_equal(2, lookup_containers.size)
222
+ assert_equal(["id", "id"], lookup_containers.map(&:resource))
223
+ end
224
+
225
+ def test_resource_find_lookup_type_containers
226
+ resource = stub(:id => "id")
227
+ metadata = { :lookup_type => [stub(:resource => "id", :lookup => "look"),
228
+ stub(:resource => "id", :lookup => "look"),
229
+ stub(:resource => "id", :lookup => "not_look"),
230
+ stub(:resource => "a", :lookup => "look"),
231
+ stub(:resource => "a", :lookup => "not_look")
232
+ ]}
233
+
234
+ lookup_type_containers = Rets::Metadata::Resource.find_lookup_type_containers(metadata, resource, "look")
235
+
236
+ assert_equal(2, lookup_type_containers.size)
237
+ assert_equal(["id", "id"], lookup_type_containers.map(&:resource))
238
+ end
239
+
240
+ def test_resource_find_rets_classes
241
+ resource = stub(:id => "id")
242
+ rets_classes = stub(:rets_classes)
243
+
244
+ metadata = { :class => [stub(:resource => "id", :classes => rets_classes),
245
+ stub(:resource => "id", :classes => rets_classes),
246
+ stub(:resource => "a")]}
247
+
248
+ assert_equal(rets_classes, Rets::Metadata::Resource.find_rets_classes(metadata, resource))
249
+ end
250
+
251
+ def test_resource_find_rets_class
252
+ resource = Rets::Metadata::Resource.new({})
253
+ value = mock(:name => "test")
254
+
255
+ resource.expects(:rets_classes).returns([value])
256
+ assert_equal(value, resource.find_rets_class("test"))
257
+ end
258
+
259
+ def test_lookup_type_initialize
260
+ fragment = { "Value" => 'a', "ShortValue" => 'b', "LongValue" => 'c' }
261
+
262
+ lookup_type = Rets::Metadata::LookupType.new(fragment)
263
+
264
+ assert_equal('a', lookup_type.value)
265
+ assert_equal('b', lookup_type.short_value)
266
+ assert_equal('c', lookup_type.long_value)
267
+ end
268
+ def test_rets_class_find_table
269
+ rets_class = Rets::Metadata::RetsClass.new({}, "resource")
270
+ value = mock(:name => "test")
271
+
272
+ rets_class.expects(:tables).returns([value])
273
+ assert_equal(value, rets_class.find_table("test"))
274
+ end
275
+
276
+ def test_rets_class_find_table_container
277
+ resource = mock(:id => "a")
278
+ rets_class = mock(:name => "b")
279
+ table = mock(:resource => "a", :class => "b")
280
+
281
+ metadata = { :table => [table] }
282
+
283
+ assert_equal(table, Rets::Metadata::RetsClass.find_table_container(metadata, resource, rets_class))
284
+ end
285
+
286
+ def test_rets_class_build
287
+ resource = stub(:resource)
288
+ table_fragment = stub(:fragment)
289
+ table_container = stub(:tables => [table_fragment])
290
+ table = stub(:table)
291
+
292
+ Rets::Metadata::TableFactory.expects(:build).with(table_fragment, resource).returns(table)
293
+ Rets::Metadata::RetsClass.expects(:find_table_container).returns(table_container)
294
+
295
+ rets_class = Rets::Metadata::RetsClass.build({}, resource, "")
296
+
297
+ assert_equal(rets_class.tables, [table])
298
+ end
299
+
300
+ def test_rets_class_build_when_find_table_container_returns_nil
301
+ new_rets_class = stub(:new_rets_class)
302
+ Rets::Metadata::RetsClass.stubs(:new => new_rets_class)
303
+ Rets::Metadata::RetsClass.stubs(:find_table_container => nil)
304
+ Rets::Metadata::RetsClass.build({}, "", "")
305
+ end
306
+
307
+
308
+ def test_rets_class_initialize
309
+ fragment = { "ClassName" => "A" }
310
+ rets_class = Rets::Metadata::RetsClass.new(fragment, "resource")
311
+
312
+ assert_equal("A", rets_class.name)
313
+ assert_equal("resource", rets_class.resource)
314
+ assert_equal([], rets_class.tables)
315
+ end
316
+
317
+ def test_table_factory_creates_lookup_table
318
+ assert_instance_of Rets::Metadata::LookupTable, Rets::Metadata::TableFactory.build({"LookupName" => "Foo", "Interpretation" => "Lookup"}, nil)
319
+ end
320
+
321
+ def test_table_factory_creates_table
322
+ assert_instance_of Rets::Metadata::Table, Rets::Metadata::TableFactory.build({"LookupName" => "", "Interpretation" => ""}, nil)
323
+ end
324
+
325
+ def test_table_factory_enum
326
+ assert Rets::Metadata::TableFactory.enum?("LookupName" => "Foo", "Interpretation" => "Lookup")
327
+ assert !Rets::Metadata::TableFactory.enum?("LookupName" => "", "Interpretation" => "SomethingElse")
328
+ assert !Rets::Metadata::TableFactory.enum?("LookupName" => "Foo", "Interpretation" => "")
329
+ assert !Rets::Metadata::TableFactory.enum?("LookupName" => "", "Interpretation" => "SomethingElse")
330
+ end
331
+
332
+ def test_lookup_table_initialize
333
+ fragment = { "SystemName" => "A", "Interpretation" => "B", "LookupName" => "C" }
334
+
335
+ lookup_table = Rets::Metadata::LookupTable.new(fragment, "Foo")
336
+
337
+ assert_equal("Foo", lookup_table.resource)
338
+ assert_equal("A", lookup_table.name)
339
+ assert_equal("C", lookup_table.lookup_name)
340
+ assert_equal("B", lookup_table.interpretation)
341
+ end
342
+
343
+ def test_lookup_table_resolve_returns_empty_array_when_value_is_empty_and_is_multi?
344
+
345
+ lookup_table = Rets::Metadata::LookupTable.new({}, nil)
346
+ lookup_table.stubs(:multi? => true)
347
+
348
+ assert_equal [], lookup_table.resolve("")
349
+ end
350
+
351
+ def test_lookup_table_resolve_returns_single_value_if_not_multi
352
+ lookup_table = Rets::Metadata::LookupTable.new({}, nil)
353
+ lookup_table.stubs(:multi? => false)
354
+
355
+ lookup_table.expects(:lookup_type).with("A,B").returns(mock(:long_value => "AaaBbb"))
356
+
357
+ assert_equal "AaaBbb", lookup_table.resolve("A,B")
358
+ end
359
+
360
+ def test_lookup_table_resolve_returns_multi_value_array_when_multi
361
+ fragment = { "Interpretation" => "LookupMulti" }
362
+
363
+ lookup_table = Rets::Metadata::LookupTable.new(fragment, nil)
364
+
365
+ lookup_table.expects(:lookup_type).with("A").returns(mock(:long_value => "Aaa"))
366
+ lookup_table.expects(:lookup_type).with("B").returns(mock(:long_value => "Bbb"))
367
+
368
+ assert_equal ["Aaa", "Bbb"], lookup_table.resolve("A,B")
369
+ end
370
+
371
+ #Sandicor does this :|
372
+ def test_lookup_table_resolve_returns_multi_value_array_when_multi_with_quoted_values
373
+ fragment = { "Interpretation" => "LookupMulti" }
374
+
375
+ lookup_table = Rets::Metadata::LookupTable.new(fragment, nil)
376
+
377
+ lookup_table.expects(:lookup_type).with("A").returns(mock(:long_value => "Aaa"))
378
+ lookup_table.expects(:lookup_type).with("B").returns(mock(:long_value => "Bbb"))
379
+
380
+ assert_equal ["Aaa", "Bbb"], lookup_table.resolve(%q["A","B"])
381
+ end
382
+
383
+ # This scenario is unfortunately common.
384
+ def test_lookup_table_resolve_returns_nil_when_lookup_type_is_not_present_for_multi_value
385
+ fragment = { "Interpretation" => "LookupMulti" }
386
+
387
+ lookup_table = Rets::Metadata::LookupTable.new(fragment, nil)
388
+
389
+ lookup_table.expects(:lookup_type).with("A").returns(mock(:long_value => "Aaa"))
390
+ lookup_table.expects(:lookup_type).with("B").returns(nil)
391
+
392
+ lookup_table.expects(:warn).with("Discarding unmappable value of #{"B".inspect}")
393
+
394
+ assert_equal ["Aaa", ""], lookup_table.resolve("A,B")
395
+ end
396
+
397
+ # This scenario is unfortunately common.
398
+ def test_lookup_table_resolve_returns_nil_when_lookup_type_is_not_present_for_single_value
399
+
400
+ lookup_table = Rets::Metadata::LookupTable.new({}, nil)
401
+ lookup_table.stubs(:multi? => true)
402
+
403
+ lookup_table.expects(:lookup_type).with("A").returns(nil)
404
+
405
+ lookup_table.expects(:warn).with("Discarding unmappable value of #{"A".inspect}")
406
+
407
+ assert_equal [""], lookup_table.resolve("A")
408
+ end
409
+
410
+ def test_table_initialize
411
+ fragment = { "DataType" => "A", "SystemName" => "B" }
412
+
413
+ table = Rets::Metadata::Table.new(fragment)
414
+ assert_equal("A", table.type)
415
+ assert_equal("B", table.name)
416
+ end
417
+
418
+ def test_table_resolve_returns_empty_string_when_value_nil
419
+ table = Rets::Metadata::Table.new({})
420
+
421
+ assert_equal "", table.resolve(nil)
422
+ end
423
+
424
+ def test_table_resolve_passes_values_straight_through
425
+ table = Rets::Metadata::Table.new({})
426
+
427
+ assert_equal "Foo", table.resolve("Foo")
428
+ end
429
+
430
+ def test_table_resolve_passes_values_strips_extra_whitspace
431
+ table = Rets::Metadata::Table.new({})
432
+
433
+ assert_equal "Foo", table.resolve(" Foo ")
434
+ end
435
+
436
+ def test_root_can_be_serialized
437
+ sources = { :x => "a" }
438
+
439
+ @root.sources = sources
440
+
441
+ assert_equal sources, @root.marshal_dump
442
+ end
443
+
444
+ def test_root_can_be_unserialized
445
+ sources = { :x => "a" }
446
+
447
+ @root.marshal_load(sources)
448
+
449
+ assert_equal sources, @root.sources
450
+ end
451
+
452
+ end
@@ -0,0 +1,71 @@
1
+ require "helper"
2
+
3
+ class TestParserCompact < Test::Unit::TestCase
4
+ def test_parse_document_raises_on_invalid_delimiter
5
+ assert_raise Rets::Parser::Compact::InvalidDelimiter do
6
+ Rets::Parser::Compact.parse_document(INVALID_DELIMETER)
7
+ end
8
+ end
9
+
10
+ def test_parse_document_uses_default_delimiter_when_none_provided
11
+ # we assert that the delimeter character getting to parse is a tab
12
+ # even though COMPACT defines no delimiter tag
13
+ Rets::Parser::Compact.expects(:parse).with("A\tB", "1\t2", /\t/)
14
+ Rets::Parser::Compact.expects(:parse).with("A\tB", "4\t5", /\t/)
15
+ Rets::Parser::Compact.parse_document(COMPACT)
16
+ end
17
+
18
+ def test_parse_document_delegates_to_parse
19
+ result = Rets::Parser::Compact.parse_document(COMPACT)
20
+
21
+ assert_equal([{"A" => "1", "B" => "2"}, {"A" => "4", "B" => "5"}], result)
22
+ end
23
+
24
+ def test_parser_rejects_empty_key_value_pairs
25
+ result = Rets::Parser::Compact.parse_document(METADATA_OBJECT)
26
+
27
+ result.each do |row|
28
+ assert !row.any? { |k,v| k.to_s.size == 0 }, "Should not contain empty keys"
29
+ end
30
+ end
31
+
32
+ def test_parse_returns_key_value_pairs
33
+ result = Rets::Parser::Compact.parse("A\tB", "1\t2")
34
+
35
+ assert_equal({"A" => "1", "B" => "2"}, result)
36
+ end
37
+
38
+ # RMLS does this. :|
39
+ def test_remaining_columns_produce_empty_string_values
40
+ columns = "A B C D"
41
+ data = "1 2"
42
+
43
+ assert_equal({"A" => "1", "B" => "2", "C" => "", "D" => ""}, Rets::Parser::Compact.parse(columns, data, / /))
44
+ end
45
+
46
+ def test_leading_empty_columns_are_preserved_with_delimiter
47
+ columns = "A\tB\tC\tD"
48
+ data = "\t\t3\t4" # first two columns are empty data.
49
+
50
+ assert_equal({"A" => "", "B" => "", "C" => "3", "D" => "4"}, Rets::Parser::Compact.parse(columns, data, /\t/))
51
+ end
52
+
53
+ def test_parse_only_accepts_regexp
54
+ assert_raises ArgumentError do
55
+ Rets::Parser::Compact.parse("a", "b", " ")
56
+ end
57
+ end
58
+
59
+ def test_parse_example
60
+ rows = Rets::Parser::Compact.parse_document(Nokogiri.parse(SAMPLE_COMPACT))
61
+
62
+ assert_equal "7", rows.first["MetadataEntryID"]
63
+ end
64
+
65
+ def test_parse_example_2
66
+ rows = Rets::Parser::Compact.parse_document(Nokogiri.parse(SAMPLE_COMPACT_2))
67
+
68
+ assert_equal "", rows.first["ModTimeStamp"]
69
+ end
70
+
71
+ end