uformats 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,500 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+ require 'uformats/hreview'
3
+ require 'uformats/hcalendar'
4
+
5
+ class HReviewTest < Test::Unit::TestCase
6
+
7
+ def test_should_find_all_reviews
8
+ html = '<html>' << SOURCES[:cafe_borrone] << SOURCES[:crepes_on_cole] << '</html>'
9
+ doc = REXML::Document.new(html)
10
+ hreviews = []
11
+ Microformats::HReview.each(doc) do |hr|
12
+ hreviews << hr
13
+ end
14
+ assert_equal(2, hreviews.length)
15
+ end
16
+
17
+ def test_should_have_lookup_to_allow_deep_lookups_without_errors
18
+ r = review(:cafe_borrone)
19
+ assert_equal('1010 El Camino Real', r.lookup(:item, :vcard, :adr, :street_address))
20
+ assert_equal('1010 El Camino Real', r.lookup(:item, :vcard, :adrs, 0, :street_address))
21
+ assert_nil(r.lookup(:item, :vcard, :adrs, 0, :post_office_box))
22
+ assert_equal(18, r.lookup(:ratings, 'Food', :score))
23
+ end
24
+
25
+ def test_should_expose_vcard_fn_and_url_at_top_level
26
+ r = review(:cafe_borrone)
27
+ assert_equal(r.item.vcard.fn, r.item.fn)
28
+ assert_equal(r.item.vcard.url, r.item.url)
29
+ assert_equal(r.item.vcard.urls, r.item.urls)
30
+ end
31
+
32
+ def test_should_parse_sample_crepes_on_cole
33
+ r = review(:crepes_on_cole)
34
+ assert_equal(5, r.rating.score)
35
+ assert_equal(5, r.rating.best)
36
+ assert_equal(1, r.rating.worst)
37
+ assert_equal('Crepes on Cole', r.item.fn)
38
+ assert_equal('Crepes on Cole is awesome', r.summary)
39
+ assert_equal('Tantek', r.reviewer.fn)
40
+ assert_equal('2005-04-19T06:00:00Z', r.dtreviewed.utc.xmlschema)
41
+ assert_not_nil(r.description =~ /<p>\s*Crepes on Cole is one of the best/um)
42
+ end
43
+
44
+ def test_should_parse_sample_cafe_borrone
45
+ r = review(:cafe_borrone)
46
+ assert_equal('Cafe Borrone', r.item.fn)
47
+ assert_equal('1010 El Camino Real', r.item.vcard.adr.street_address)
48
+ assert_equal('San Francisco', r.item.vcard.adr.locality)
49
+ assert_equal('CA', r.item.vcard.adr.region)
50
+ assert_equal('94025', r.item.vcard.adr.postal_code)
51
+ assert_equal('+1-650-327-0830', r.item.vcard.tel.value)
52
+ assert_equal('http://cafeborrone.com', r.item.url)
53
+ assert_equal(18, r.ratings['Food'].score)
54
+ assert_equal(30, r.ratings['Food'].best)
55
+ assert_equal(1, r.ratings['Food'].worst)
56
+ assert_equal(19, r.ratings['Ambience'].score)
57
+ assert_equal(30, r.ratings['Ambience'].best)
58
+ assert_equal(15, r.ratings['Service'].score)
59
+ assert_equal(30, r.ratings['Service'].best)
60
+ assert_equal(2, r.ratings['Price'].score)
61
+ assert_equal(5, r.ratings['Price'].best)
62
+ assert_nil(r.rating)
63
+ assert_not_nil(r.description =~ %r!<p>\s+This <abbr class='type' title='business'>!um)
64
+ assert_equal('business', r.type)
65
+ assert_equal('0.2', r.version)
66
+ assert_equal('anonymous', r.reviewer.fn)
67
+ assert_equal(Time.parse('20050428T2130-0700'), r.dtreviewed)
68
+ end
69
+
70
+ def test_should_parse_sample_postal_service
71
+ r = review(:postal_service)
72
+ assert_equal('http://www.amazon.com/exec/obidos/ASIN/B000089CJI/', r.item.url)
73
+ assert_equal('http://images.amazon.com/images/P/B000089CJI.01._SCTHUMBZZZ_.jpg', r.item.photo)
74
+ assert_equal('The Postal Service: Give Up', r.item.fn)
75
+ assert_not_nil(r.description =~ /<p>\s*"The people thought they were just being rewarded/um)
76
+ assert_equal(5, r.rating.score)
77
+ assert_equal(1, r.rating.worst)
78
+ assert_equal(5, r.rating.best)
79
+ assert_equal('Adam Rifkin', r.reviewer.fn)
80
+ assert_equal('http://ifindkarma.com/blog/', r.reviewer.url)
81
+ assert_equal(2005, r.dtreviewed.year)
82
+ assert_equal(2, r.dtreviewed.month)
83
+ end
84
+
85
+ def test_should_parse_sample_hero
86
+ r = review(:hero)
87
+ assert_equal('anonymous', r.reviewer.fn)
88
+ assert_equal('2005-04-18', r.dtreviewed.strftime('%Y-%m-%d'))
89
+ assert_equal('Ying Xiong (HERO)', r.item.fn)
90
+ assert_equal('http://www.imdb.com/title/tt0299977/', r.item.url)
91
+ assert_equal(4, r.rating.score)
92
+ assert_equal(1, r.rating.worst)
93
+ assert_equal(5, r.rating.best)
94
+ assert_not_nil(r.description =~ /This movie has great music and visuals./um)
95
+ end
96
+
97
+ def test_should_parse_multiple_urls_and_photos
98
+ r = review(:multi)
99
+ assert_equal('http://example.com/front.jpg', r.item.photo)
100
+ assert_equal('http://example.com/front.jpg', r.item.photos[0])
101
+ assert_equal('http://example.com/back.jpg', r.item.photos[1])
102
+ assert_equal('http://example.com/one', r.item.url)
103
+ assert_equal('http://example.com/one', r.item.urls[0])
104
+ assert_equal('http://example.com/two', r.item.urls[1])
105
+ end
106
+
107
+ def test_should_detect_invalid_reviews
108
+ assert(!review(:invalid_item).valid?)
109
+ assert(review(:cafe_borrone).valid?)
110
+ assert(review(:event_review_without_vevent).valid?)
111
+ assert(!review(:invalid_type_review).valid?)
112
+ end
113
+
114
+ def test_should_find_identifiers
115
+ r = review(:with_identifiers)
116
+ assert_equal(2, r.item.urls.length)
117
+ assert_equal('urn:ean.ucc:123', r.item.urls[0])
118
+ assert_equal('urn:product/nikon/d70', r.item.urls[1])
119
+ end
120
+
121
+ def test_should_raise_exception_on_unknown_key_as_method
122
+ r = review(:cafe_borrone)
123
+ assert_raises(NoMethodError){ r.frobnitz }
124
+ assert_nothing_raised{ r.item }
125
+ end
126
+
127
+ def test_should_parse_worst_score
128
+ r = review(:with_worst)
129
+ assert_equal(1, r.rating.worst)
130
+ end
131
+
132
+ def test_should_convert_score_to_float
133
+ r = review(:with_worst)
134
+ assert_in_delta(0.75, r.rating.to_f, 0.01)
135
+ end
136
+
137
+ # Version 0.3 changes
138
+
139
+ def test_should_see_version_0_3_review_as_valid
140
+ r = review(:version_0_3)
141
+ assert(r.valid?)
142
+ end
143
+
144
+ def test_should_find_licenses_in_0_3_review
145
+ r = review(:version_0_3)
146
+ assert_equal(1, r.licenses.length)
147
+ assert_in_delta(4.5, r.rating.score, 0.01)
148
+ assert_equal("http://example.com/licenses/only-on-tuesdays-2.1", r.licenses.first)
149
+ assert_equal("http://example.com/licenses/only-on-tuesdays-2.1", r.license)
150
+ end
151
+
152
+ def test_should_require_hcard_for_business_or_person_post_0_3
153
+ assert(!review(:invalid_person_review).valid?)
154
+ assert(review(:valid_person_review_0_2).valid?)
155
+ assert(!review(:invalid_business_review).valid?)
156
+ end
157
+
158
+ def test_should_parse_embedded_hcalendar_event
159
+ r = review(:event_review)
160
+ assert_equal('The Event', r.item.vevent.summary)
161
+ assert_equal('The Location', r.item.vevent.location)
162
+ end
163
+
164
+ def test_should_parse_sample_cafe_borrone_0_3
165
+ r = review(:cafe_borrone_0_3)
166
+ assert_equal('Cafe Borrone', r.item.fn)
167
+ assert_equal('1010 El Camino Real', r.item.vcard.adr.street_address)
168
+ assert_equal('Menlo Park', r.item.vcard.adr.locality)
169
+ assert_equal('CA', r.item.vcard.adr.region)
170
+ assert_equal('94025', r.item.vcard.adr.postal_code)
171
+ assert_equal('+1-650-327-0830', r.item.vcard.tel.value)
172
+ assert_equal('http://cafeborrone.com', r.item.url)
173
+ assert_equal(18, r.ratings['Food'].score)
174
+ assert_equal(30, r.ratings['Food'].best)
175
+ assert_equal(1, r.ratings['Food'].worst)
176
+ assert_equal(19, r.ratings['Ambience'].score)
177
+ assert_equal(30, r.ratings['Ambience'].best)
178
+ assert_equal(15, r.ratings['Service'].score)
179
+ assert_equal(30, r.ratings['Service'].best)
180
+ assert_equal(2, r.ratings['Price'].score)
181
+ assert_equal(5, r.ratings['Price'].best)
182
+ assert_nil(r.rating)
183
+ assert_not_nil(r.description =~ %r!<p>\s+This <abbr class='type' title='business'>!um)
184
+ assert_equal('business', r.type)
185
+ assert_equal('0.3', r.version)
186
+ assert_equal('anonymous', r.reviewer.fn)
187
+ assert_equal(Time.parse('20050428T2130-0700'), r.dtreviewed)
188
+ end
189
+
190
+ def test_should_return_best_and_worst_attributes_of_score_as_integers
191
+ r = Microformats::HReview::Rating.new
192
+ r.best = 10.0
193
+ r.worst = 1.0
194
+ r.score = 9.5
195
+ assert_equal('10', r.best.to_s)
196
+ assert_equal('1', r.worst.to_s)
197
+ assert_equal('9.5', r.score.to_s)
198
+ end
199
+
200
+ def review(name)
201
+ return Microformats::HReview.first(REXML::Document.new(SOURCES[name]))
202
+ end
203
+
204
+ SOURCES = {
205
+ :crepes_on_cole => %{
206
+ <div class="hreview">
207
+ <span><span class="rating">5</span> out of 5 stars</span>
208
+ <h4 class="summary"><span class="item fn">Crepes on Cole</span> is awesome</h4>
209
+ <span>Reviewer: <span class="reviewer fn">Tantek</span> -
210
+ <abbr class="dtreviewed" title="20050418T2300-0700">April 18, 2005</abbr></span>
211
+ <blockquote class="description"><p>
212
+ Crepes on Cole is one of the best little creperies in San Francisco.
213
+ Excellent food and service. Plenty of tables in a variety of sizes
214
+ for parties large and small. Window seating makes for excellent
215
+ people watching to/from the N-Judah which stops right outside.
216
+ I've had many fun social gatherings here, as well as gotten
217
+ plenty of work done thanks to neighborhood WiFi.
218
+ </p></blockquote>
219
+ <p>Visit date: <span>April 2005</span></p>
220
+ <p>Food eaten: <span>Florentine crepe</span></p>
221
+ </div>},
222
+ :cafe_borrone => %{
223
+ <div class="hreview">
224
+ <div class="item vcard">
225
+ <div class="fn org summary">Cafe Borrone</div>
226
+ <span class="adr">
227
+ <span class="street-address">1010 El Camino Real</span>,
228
+ <span class="locality">San Francisco</span>,
229
+ <span class="region">CA</span>
230
+ <span class="postal-code">94025</span>,
231
+ </span>
232
+ <span class="tel"><span class="voice work">+1-650-327-0830</span></span>;
233
+ <a class="url" href="http://cafeborrone.com">cafeborrone.com</a>
234
+ </div>
235
+ <ul class="categories">
236
+ <li><a href="http://en.wikipedia.org/wiki/Food" rel="tag">
237
+ Food: <span class="rating">18</span>/<span class="best">30</span></a>;</li>
238
+ <li><a href="http://flickr.com/photos/tags/Ambience" rel="tag">
239
+ Ambience: <span class="rating">19</span>/<span class="best">30</span></a>;</li>
240
+ <li><a href="http://en.wikipedia.org/wiki/Service" rel="tag">
241
+ Service: <span class="rating">15</span>/<span class="best">30</span></a>;</li>
242
+ <li><a href="http://en.wikipedia.org/wiki/Price" rel="tag">
243
+ Price: <abbr class="rating" title="2">$$</abbr>...</a></li>
244
+ </ul>
245
+ <blockquote class="description"><p>
246
+ This <abbr class="type" title="business">
247
+ <a href="http://en.wikipedia.org/wiki/cafe" rel="tag">cafe</a></abbr>
248
+ is a welcoming oasis on the Peninsula.
249
+ It even has a fountain outside which nearly eliminates
250
+ the sounds of El Camino traffic. Next door to a superb indy bookstore,
251
+ Cafe Borrone is an ideal spot to grab a
252
+ <a href="http://en.wikipedia.org/wiki/coffee" rel="tag">coffee</a>
253
+ or a meal to accompany a newly purchased book or imported periodical.
254
+ <a href="http://technorati.com/tag/soup" rel="tag">Soups</a> and
255
+ <a href="http://technorati.com/tag/sandwich" rel="tag">sandwich</a>
256
+ specials rotate daily. The corn chowder with croutons and big chunks of cheese
257
+ goes especially well with a freshly toasted mini-baguette. Evenings are
258
+ often crowded and may require sharing a table with a perfect stranger.
259
+ <a href="http://flickr.com/photos/tags/espresso" rel="tag">Espresso</a>
260
+ afficionados will appreciate the
261
+ <a href="http://en.wikipedia.org/wiki/Illy" rel="tag">Illy</a> coffee.
262
+ Noise levels can vary from peaceful in the late mornings to nearly overwhelming on
263
+ <a href="http://en.wikipedia.org/wiki/jazz" rel="tag">jazz</a> band nights.
264
+ </p></blockquote>
265
+ Review (<a href="http://microformats.org/wiki/hreview">
266
+ hReview v<span class="version">0.2</span></a>)
267
+ by <span class="reviewer">anonymous</span>,
268
+ <abbr class="dtreviewed" title="20050428T2130-0700">April 28th, 2005</abbr>.
269
+ </div>},
270
+ :cafe_borrone_0_3 => %{
271
+ <div class="hreview">
272
+ <div class="item vcard">
273
+ <div class="fn org summary">Cafe Borrone</div>
274
+ <span class="adr">
275
+ <span class="street-address">1010 El Camino Real</span>,
276
+ <span class="locality">Menlo Park</span>,
277
+ <span class="region">CA</span>
278
+ <span class="postal-code">94025</span>,
279
+ </span>
280
+ <span class="tel">+1-650-327-0830</span>;
281
+ <a class="url" href="http://cafeborrone.com">cafeborrone.com</a>
282
+ </div>
283
+ <ul class="categories">
284
+ <li class="rating"><a href="http://en.wikipedia.org/wiki/Food" rel="tag">
285
+ Food: <span class="value">18</span>/<span class="best">30</span></a>;</li>
286
+ <li class="rating"><a href="http://flickr.com/photos/tags/Ambience" rel="tag">
287
+ Ambience: <span class="value">19</span>/<span class="best">30</span></a>;</li>
288
+ <li class="rating"><a href="http://en.wikipedia.org/wiki/Service" rel="tag">
289
+ Service: <span class="value">15</span>/<span class="best">30</span></a>;</li>
290
+ <li class="rating"><a href="http://en.wikipedia.org/wiki/Price" rel="tag">
291
+ Price: <abbr class="value" title="2">$$</abbr>...</a></li>
292
+ </ul>
293
+ <div class="description"><p>
294
+ This <abbr class="type" title="business">
295
+ <a href="http://en.wikipedia.org/wiki/cafe" rel="tag">cafe</a></abbr>
296
+ is a welcoming oasis on the Peninsula.
297
+ It even has a fountain outside which nearly eliminates
298
+ the sounds of El Camino traffic. Next door to a superb indy bookstore,
299
+ Cafe Borrone is an ideal spot to grab a
300
+ <a href="http://en.wikipedia.org/wiki/coffee" rel="tag">coffee</a>
301
+ or a meal to accompany a newly purchased book or imported periodical.
302
+ <a href="http://technorati.com/tag/soup" rel="tag">Soups</a> and
303
+ <a href="http://technorati.com/tag/sandwich" rel="tag">sandwich</a>
304
+ specials rotate daily. The corn chowder with croutons and big chunks of cheese
305
+ goes especially well with a freshly toasted mini-baguette. Evenings are
306
+ often crowded and may require sharing a table with a perfect stranger.
307
+ <a href="http://flickr.com/photos/tags/espresso" rel="tag">Espresso</a>
308
+ afficionados will appreciate the
309
+ <a href="http://en.wikipedia.org/wiki/Illy" rel="tag">Illy</a> coffee.
310
+ Noise levels can vary from peaceful in the late mornings to nearly overwhelming on
311
+ <a href="http://en.wikipedia.org/wiki/jazz" rel="tag">jazz</a> band nights.
312
+ </p></div>
313
+ Review (<a href="http://microformats.org/wiki/hreview">
314
+ hReview v<span class="version">0.3</span></a>)
315
+ by <span class="reviewer vcard"><span class="fn">anonymous</span></span>,
316
+ <abbr class="dtreviewed" title="20050428T2130-0700">April 28th, 2005</abbr>.
317
+ </div>},
318
+ :postal_service => %{
319
+ <div class="hreview">
320
+ <a class="item url" href="http://www.amazon.com/exec/obidos/ASIN/B000089CJI/">
321
+ <img src="http://images.amazon.com/images/P/B000089CJI.01._SCTHUMBZZZ_.jpg"
322
+ alt="Album cover photo: The Postal Service: Give Up. "
323
+ class="photo" />
324
+ <span class="fn">The Postal Service: Give Up</span></a>
325
+ <blockquote class="description"><p>
326
+ "The people thought they were just being rewarded for treating others
327
+ as they like to be treated, for obeying stop signs and curing diseases,
328
+ for mailing letters with the address of the sender... Don't wake me,
329
+ I plan on sleeping in..."
330
+ </p><p>
331
+ "Nothing Better" is a great track on this album, too...
332
+ </p></blockquote>
333
+ (<abbr class="rating" title="5">*****</abbr>)
334
+ <p class="reviewer vcard">Review by
335
+ <a class="url fn" href="http://ifindkarma.com/blog/">Adam Rifkin</a>,
336
+ <abbr class="dtreviewed" title="200502">February 2005</abbr>
337
+ </p>
338
+ </div>},
339
+ :hero => %{
340
+ <div class="hreview">
341
+ <span class="reviewer">
342
+ <span class="fn">anonymous</span>,
343
+ <abbr class="dtreviewed" title="20050418">April 18th, 2005</abbr>
344
+ </span>
345
+ <div class="item">
346
+ <a lang="zh" class="url fn" href="http://www.imdb.com/title/tt0299977/">
347
+ Ying Xiong (<span lang="en">HERO</span>)
348
+ </a>
349
+ </div>
350
+ <div>Rating: <span class="rating">4</span> out of 5</div>
351
+ <blockquote class="description"><p>
352
+ This movie has great music and visuals.
353
+ </p></blockquote>
354
+ </div>},
355
+ :multi => %{
356
+ <div class='hreview'>
357
+ <span class='version'>0.2</span>
358
+ <p class="reviewer fn">Reviewer</p>
359
+ <abbr class="dtreviewed" title="20010101">2001-01-01</abbr>
360
+ <span class='type'>product</span>
361
+ <div class='item'>
362
+ <img class="photo" src="http://example.com/front.jpg" alt="front view" />
363
+ <img class="photo" src="http://example.com/back.jpg" alt="back view" />
364
+ <span class='fn'>item_fn</span>
365
+ <ul class='identifiers'>
366
+ <li><a class='url' href='http://example.com/one'>item_url1</a></li>
367
+ <li><a class='url' href='http://example.com/two'>item_url2</a></li>
368
+ </ul>
369
+ </div>},
370
+ :invalid_item => %{
371
+ <div class="hreview">
372
+ <span class="reviewer">
373
+ <span class="fn">anonymous</span>,
374
+ <abbr class="dtreviewed" title="20050418">April 18th, 2005</abbr>
375
+ </span>
376
+ <div>Rating: <span class="rating">4</span> out of 5</div>
377
+ <blockquote class="description"><p>
378
+ This movie has great music and visuals.
379
+ </p></blockquote>
380
+ </div>},
381
+ :with_identifiers => %{
382
+ <div class='hreview'>
383
+ <span class='version' style='display:none'>0.2</span>
384
+ <span class='type' style='display:none'>product</span>
385
+ <div class='item'>
386
+ <span class='fn'>asd</span>
387
+ <ul class='identifiers'>
388
+ <li><a class='url' href='urn:ean.ucc:123'>urn:ean.ucc:123</a></li>
389
+ <li><a class='url' href='urn:product/nikon/d70'>urn:product/nikon/d70</a></li>
390
+ </ul>
391
+ </div>
392
+ <div class='description'>dsa</div>
393
+ Rated <span class='rating'>1</span>
394
+ by <span class='reviewer fn'>chris</span>
395
+ on <abbr class='dtreviewed' title='2006-01-12T16:09:00+00:00'>Jan 12, 2006</abbr>
396
+ </div>},
397
+ :version_0_3 => %{
398
+ <div>
399
+ <a href="http://example.com/licenses/dont-find-me" rel="license">No!</a>
400
+ <div class="hreview">
401
+ <a href="http://example.com/licenses/only-on-tuesdays-2.1" rel="license">Only on Tuesdays 2.1</a>
402
+ <div class="item">
403
+ <a class="url fn" href="http://example.com/item">
404
+ Item Name
405
+ </a>
406
+ </div>
407
+ <div>Rating: <span class="rating">4.5</span> out of 5</div>
408
+ <blockquote class="description"><p>
409
+ Description.
410
+ </p></blockquote>
411
+ </div>
412
+ </div>
413
+ },
414
+ :with_worst => %{
415
+ <div class="hreview">
416
+ <div class="item fn">Foo</div>
417
+ <div>Rating: <span class="rating">4</span> (<span class="worst">1</span>-<span class="best">5</span>)</div>
418
+ <blockquote class="description"><p>
419
+ Description.
420
+ </p></blockquote>
421
+ </div>
422
+ },
423
+ :event_review => %{
424
+ <div class="hreview">
425
+ <span class='type' style='display:none'>event</span>
426
+ <span class="reviewer vcard">
427
+ <span class="fn">John Doe</span>,
428
+ <abbr class="dtreviewed" title="20050418">April 18th, 2005</abbr>
429
+ </span>
430
+ <span class="item vevent">
431
+ <a class="url" href="http://www.example.com/event">
432
+ <span class="summary">The Event</span>:
433
+ at <span class="location">The Location</span>
434
+ </a>
435
+ </span>
436
+ <div>Rating: <span class="rating">4</span> out of 5</div>
437
+ <blockquote class="description"><p>
438
+ Description.
439
+ </p></blockquote>
440
+ </div>
441
+ },
442
+ :event_review_without_vevent => %{
443
+ <div class="hreview">
444
+ <span class='type' style='display:none'>event</span>
445
+ <span class="reviewer vcard">
446
+ <span class="fn">John Doe</span>,
447
+ <abbr class="dtreviewed" title="20050418">April 18th, 2005</abbr>
448
+ </span>
449
+ <span class="item fn">The Event</span>
450
+ <div>Rating: <span class="rating">4</span> out of 5</div>
451
+ <blockquote class="description"><p>
452
+ Description.
453
+ </p></blockquote>
454
+ </div>
455
+ },
456
+ :invalid_person_review => %{
457
+ <div class="hreview">
458
+ <span class="version">0.3</span>
459
+ <span class='type'>person</span>
460
+ <span class="item fn">John Doe</span>
461
+ <div>Rating: <span class="rating">4</span> out of 5</div>
462
+ <blockquote class="description"><p>
463
+ Description.
464
+ </p></blockquote>
465
+ </div>
466
+ },
467
+ :valid_person_review_0_2 => %{
468
+ <div class="hreview">
469
+ <span class="version">0.2</span>
470
+ <span class='type'>person</span>
471
+ <span class="item fn">John Doe</span>
472
+ <div>Rating: <span class="rating">4</span> out of 5</div>
473
+ <blockquote class="description"><p>
474
+ Description.
475
+ </p></blockquote>
476
+ </div>
477
+ },
478
+ :invalid_business_review => %{
479
+ <div class="hreview">
480
+ <span class='type'>business</span>
481
+ <span class="item fn">John Doe, Inc.</span>
482
+ <div>Rating: <span class="rating">4</span> out of 5</div>
483
+ <blockquote class="description"><p>
484
+ Description.
485
+ </p></blockquote>
486
+ </div>
487
+ },
488
+ :invalid_type_review => %{
489
+ <div class="hreview">
490
+ <span class='type'>foo</span>
491
+ <span class="item fn">Item Name</span>
492
+ <div>Rating: <span class="rating">4</span> out of 5</div>
493
+ <blockquote class="description"><p>
494
+ Description.
495
+ </p></blockquote>
496
+ </div>
497
+ },
498
+ }
499
+
500
+ end