bento_search 0.9.0 → 1.0.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,240 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <xs:schema targetNamespace="http://www.w3.org/2005/Atom" elementFormDefault="qualified"
3
+ attributeFormDefault="unqualified"
4
+ xmlns:atom="http://www.w3.org/2005/Atom" xmlns:xs="http://www.w3.org/2001/XMLSchema">
5
+ <xs:annotation>
6
+ <xs:documentation>
7
+ This version of the Atom schema is based on version 1.0 of the format specifications,
8
+ found here http://www.atomenabled.org/developers/syndication/atom-format-spec.php.
9
+ </xs:documentation>
10
+ </xs:annotation>
11
+ <xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/03/xml.xsd" />
12
+ <xs:annotation>
13
+ <xs:documentation>
14
+ An Atom document may have two root elements, feed and entry, as defined in section 2.
15
+ </xs:documentation>
16
+ </xs:annotation>
17
+ <xs:element name="feed" type="atom:feedType"/>
18
+ <xs:element name="entry" type="atom:entryType"/>
19
+ <xs:complexType name="textType" mixed="true">
20
+ <xs:annotation>
21
+ <xs:documentation>
22
+ The Atom text construct is defined in section 3.1 of the format spec.
23
+ </xs:documentation>
24
+ </xs:annotation>
25
+ <xs:sequence>
26
+ <xs:any namespace="http://www.w3.org/1999/xhtml" minOccurs="0"/>
27
+ </xs:sequence>
28
+ <xs:attribute name="type" >
29
+ <xs:simpleType>
30
+ <xs:restriction base="xs:token">
31
+ <xs:enumeration value="text"/>
32
+ <xs:enumeration value="html"/>
33
+ <xs:enumeration value="xhtml"/>
34
+ </xs:restriction>
35
+ </xs:simpleType>
36
+ </xs:attribute>
37
+ <xs:attributeGroup ref="atom:commonAttributes"/>
38
+ </xs:complexType>
39
+ <xs:complexType name="personType">
40
+ <xs:annotation>
41
+ <xs:documentation>
42
+ The Atom person construct is defined in section 3.2 of the format spec.
43
+ </xs:documentation>
44
+ </xs:annotation>
45
+ <xs:choice minOccurs="1" maxOccurs="unbounded">
46
+ <xs:element name="name" type="xs:string" minOccurs="1" maxOccurs="1" />
47
+ <xs:element name="uri" type="atom:uriType" minOccurs="0" maxOccurs="1" />
48
+ <xs:element name="email" type="atom:emailType" minOccurs="0" maxOccurs="1" />
49
+ <xs:any namespace="##other"/>
50
+ </xs:choice>
51
+ <xs:attributeGroup ref="atom:commonAttributes"/>
52
+ </xs:complexType>
53
+ <xs:simpleType name="emailType">
54
+ <xs:annotation>
55
+ <xs:documentation>
56
+ Schema definition for an email address.
57
+ </xs:documentation>
58
+ </xs:annotation>
59
+ <xs:restriction base="xs:normalizedString">
60
+ <xs:pattern value="\w+@(\w+\.)+\w+" />
61
+ </xs:restriction>
62
+ </xs:simpleType>
63
+ <xs:complexType name="feedType">
64
+ <xs:annotation>
65
+ <xs:documentation>
66
+ The Atom feed construct is defined in section 4.1.1 of the format spec.
67
+ </xs:documentation>
68
+ </xs:annotation>
69
+ <xs:choice minOccurs="3" maxOccurs="unbounded">
70
+ <xs:element name="author" type="atom:personType" minOccurs="0" maxOccurs="unbounded" />
71
+ <xs:element name="category" type="atom:categoryType" minOccurs="0" maxOccurs="unbounded" />
72
+ <xs:element name="contributor" type="atom:personType" minOccurs="0" maxOccurs="unbounded" />
73
+ <xs:element name="generator" type="atom:generatorType" minOccurs="0" maxOccurs="1" />
74
+ <xs:element name="icon" type="atom:iconType" minOccurs="0" maxOccurs="1" />
75
+ <xs:element name="id" type="atom:idType" minOccurs="1" maxOccurs="1" />
76
+ <xs:element name="link" type="atom:linkType" minOccurs="0" maxOccurs="unbounded" />
77
+ <xs:element name="logo" type="atom:logoType" minOccurs="0" maxOccurs="1" />
78
+ <xs:element name="rights" type="atom:textType" minOccurs="0" maxOccurs="1" />
79
+ <xs:element name="subtitle" type="atom:textType" minOccurs="0" maxOccurs="1" />
80
+ <xs:element name="title" type="atom:textType" minOccurs="1" maxOccurs="1" />
81
+ <xs:element name="updated" type="atom:dateTimeType" minOccurs="1" maxOccurs="1" />
82
+ <xs:element name="entry" type="atom:entryType" minOccurs="0" maxOccurs="unbounded" />
83
+ <xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" />
84
+ </xs:choice>
85
+ <xs:attributeGroup ref="atom:commonAttributes"/>
86
+ </xs:complexType>
87
+ <xs:complexType name="entryType">
88
+ <xs:annotation>
89
+ <xs:documentation>
90
+ The Atom entry construct is defined in section 4.1.2 of the format spec.
91
+ </xs:documentation>
92
+ </xs:annotation>
93
+ <xs:choice maxOccurs="unbounded">
94
+ <xs:element name="author" type="atom:personType" minOccurs="0" maxOccurs="unbounded" />
95
+ <xs:element name="category" type="atom:categoryType" minOccurs="0" maxOccurs="unbounded" />
96
+ <xs:element name="content" type="atom:contentType" minOccurs="0" maxOccurs="1" />
97
+ <xs:element name="contributor" type="atom:personType" minOccurs="0" maxOccurs="unbounded" />
98
+ <xs:element name="id" type="atom:idType" minOccurs="1" maxOccurs="1" />
99
+ <xs:element name="link" type="atom:linkType" minOccurs="0" maxOccurs="unbounded" />
100
+ <xs:element name="published" type="atom:dateTimeType" minOccurs="0" maxOccurs="1" />
101
+ <xs:element name="rights" type="atom:textType" minOccurs="0" maxOccurs="1" />
102
+ <xs:element name="source" type="atom:textType" minOccurs="0" maxOccurs="1" />
103
+ <xs:element name="summary" type="atom:textType" minOccurs="0" maxOccurs="1" />
104
+ <xs:element name="title" type="atom:textType" minOccurs="1" maxOccurs="1" />
105
+ <xs:element name="updated" type="atom:dateTimeType" minOccurs="1" maxOccurs="1" />
106
+ <xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
107
+ </xs:choice>
108
+ <xs:attributeGroup ref="atom:commonAttributes"/>
109
+ </xs:complexType>
110
+ <xs:complexType name="contentType" mixed="true">
111
+ <xs:annotation>
112
+ <xs:documentation>
113
+ The Atom content construct is defined in section 4.1.3 of the format spec.
114
+ </xs:documentation>
115
+ </xs:annotation>
116
+ <xs:sequence>
117
+ <xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" />
118
+ </xs:sequence>
119
+ <xs:attribute name="type" type="xs:string"/>
120
+ <xs:attribute name="src" type="xs:anyURI"/>
121
+ <xs:attributeGroup ref="atom:commonAttributes"/>
122
+ </xs:complexType>
123
+ <xs:complexType name="categoryType">
124
+ <xs:annotation>
125
+ <xs:documentation>
126
+ The Atom cagegory construct is defined in section 4.2.2 of the format spec.
127
+ </xs:documentation>
128
+ </xs:annotation>
129
+ <xs:attribute name="term" type="xs:string" use="required"/>
130
+ <xs:attribute name="scheme" type="xs:anyURI" use="optional"/>
131
+ <xs:attribute name="label" type="xs:string" use="optional"/>
132
+ <xs:attributeGroup ref="atom:commonAttributes" />
133
+ </xs:complexType>
134
+ <xs:complexType name="generatorType">
135
+ <xs:annotation>
136
+ <xs:documentation>
137
+ The Atom generator element is defined in section 4.2.4 of the format spec.
138
+ </xs:documentation>
139
+ </xs:annotation>
140
+ <xs:simpleContent>
141
+ <xs:extension base="xs:string">
142
+ <xs:attribute name="uri" use="optional" type="xs:anyURI" />
143
+ <xs:attribute name="version" use="optional" type="xs:string" />
144
+ <xs:attributeGroup ref="atom:commonAttributes"/>
145
+ </xs:extension>
146
+ </xs:simpleContent>
147
+ </xs:complexType>
148
+ <xs:complexType name="iconType">
149
+ <xs:annotation>
150
+ <xs:documentation>
151
+ The Atom icon construct is defined in section 4.2.5 of the format spec.
152
+ </xs:documentation>
153
+ </xs:annotation>
154
+ <xs:simpleContent>
155
+ <xs:extension base="xs:anyURI">
156
+ <xs:attributeGroup ref="atom:commonAttributes"/>
157
+ </xs:extension>
158
+ </xs:simpleContent>
159
+ </xs:complexType>
160
+ <xs:complexType name="idType">
161
+ <xs:annotation>
162
+ <xs:documentation>
163
+ The Atom id construct is defined in section 4.2.6 of the format spec.
164
+ </xs:documentation>
165
+ </xs:annotation>
166
+ <xs:simpleContent>
167
+ <xs:extension base="xs:anyURI">
168
+ <xs:attributeGroup ref="atom:commonAttributes"/>
169
+ </xs:extension>
170
+ </xs:simpleContent>
171
+ </xs:complexType>
172
+ <xs:complexType name="linkType" mixed="true">
173
+ <xs:annotation>
174
+ <xs:documentation>
175
+ The Atom link construct is defined in section 3.4 of the format spec.
176
+ </xs:documentation>
177
+ </xs:annotation>
178
+ <xs:attribute name="href" use="required" type="xs:anyURI" />
179
+ <xs:attribute name="rel" type="xs:string" use="optional"/>
180
+ <xs:attribute name="type" use="optional" type="xs:string" />
181
+ <xs:attribute name="hreflang" use="optional" type="xs:NMTOKEN" />
182
+ <xs:attribute name="title" use="optional" type="xs:string" />
183
+ <xs:attribute name="length" use="optional" type="xs:positiveInteger" />
184
+ <xs:attributeGroup ref="atom:commonAttributes"/>
185
+ </xs:complexType>
186
+ <xs:complexType name="logoType">
187
+ <xs:annotation>
188
+ <xs:documentation>
189
+ The Atom logo construct is defined in section 4.2.8 of the format spec.
190
+ </xs:documentation>
191
+ </xs:annotation>
192
+ <xs:simpleContent>
193
+ <xs:extension base="xs:anyURI">
194
+ <xs:attributeGroup ref="atom:commonAttributes"/>
195
+ </xs:extension>
196
+ </xs:simpleContent>
197
+ </xs:complexType>
198
+ <xs:complexType name="sourceType">
199
+ <xs:annotation>
200
+ <xs:documentation>
201
+ The Atom source construct is defined in section 4.2.11 of the format spec.
202
+ </xs:documentation>
203
+ </xs:annotation>
204
+ <xs:choice maxOccurs="unbounded">
205
+ <xs:element name="author" type="atom:personType" minOccurs="0" maxOccurs="unbounded"/>
206
+ <xs:element name="category" type="atom:categoryType" minOccurs="0" maxOccurs="unbounded"/>
207
+ <xs:element name="contributor" type="atom:personType" minOccurs="0" maxOccurs="unbounded"/>
208
+ <xs:element name="generator" type="atom:generatorType" minOccurs="0" maxOccurs="1"/>
209
+ <xs:element name="icon" type="atom:iconType" minOccurs="0" maxOccurs="1"/>
210
+ <xs:element name="id" type="atom:idType" minOccurs="0" maxOccurs="1"/>
211
+ <xs:element name="link" type="atom:linkType" minOccurs="0" maxOccurs="unbounded"/>
212
+ <xs:element name="logo" type="atom:logoType" minOccurs="0" maxOccurs="1"/>
213
+ <xs:element name="rights" type="atom:textType" minOccurs="0" maxOccurs="1"/>
214
+ <xs:element name="subtitle" type="atom:textType" minOccurs="0" maxOccurs="1"/>
215
+ <xs:element name="title" type="atom:textType" minOccurs="0" maxOccurs="1"/>
216
+ <xs:element name="updated" type="atom:dateTimeType" minOccurs="0" maxOccurs="1"/>
217
+ <xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
218
+ </xs:choice>
219
+ <xs:attributeGroup ref="atom:commonAttributes"/>
220
+ </xs:complexType>
221
+ <xs:complexType name="uriType">
222
+ <xs:simpleContent>
223
+ <xs:extension base="xs:anyURI">
224
+ <xs:attributeGroup ref="atom:commonAttributes"/>
225
+ </xs:extension>
226
+ </xs:simpleContent>
227
+ </xs:complexType>
228
+ <xs:complexType name="dateTimeType">
229
+ <xs:simpleContent>
230
+ <xs:extension base="xs:dateTime">
231
+ <xs:attributeGroup ref="atom:commonAttributes"/>
232
+ </xs:extension>
233
+ </xs:simpleContent>
234
+ </xs:complexType>
235
+ <xs:attributeGroup name="commonAttributes">
236
+ <xs:attribute ref="xml:base" />
237
+ <xs:attribute ref="xml:lang" />
238
+ <xs:anyAttribute namespace="##other"/>
239
+ </xs:attributeGroup>
240
+ </xs:schema>
@@ -14,8 +14,7 @@ class OpenurlCreatorTest < ActiveSupport::TestCase
14
14
  def test_create_article
15
15
  item = decorated_item(
16
16
  :format => "Article",
17
- :title => "My Title",
18
- :subtitle => "A Nice One",
17
+ :title => "My Title: A Nice One",
19
18
  :year => 2012,
20
19
  :volume => "10",
21
20
  :issue => "1",
@@ -53,8 +52,7 @@ class OpenurlCreatorTest < ActiveSupport::TestCase
53
52
  def test_numeric_conversion
54
53
  item = decorated_item(
55
54
  :format => "Article",
56
- :title => "My Title",
57
- :subtitle => "A Nice One",
55
+ :title => "My Title: A Nice One",
58
56
  :year => 2012,
59
57
  :volume => 10,
60
58
  :issue => 1,
@@ -46,5 +46,64 @@ class RegisterEngineTest < ActiveSupport::TestCase
46
46
  assert_raise(BentoSearch::NoSuchEngine) { BentoSearch.get_engine("not_registered")}
47
47
  end
48
48
 
49
+ test "returns configuration" do
50
+ returned_configuration = BentoSearch.register_engine("test_engine") do |conf|
51
+ conf.engine = "DummyEngine"
52
+ conf.api_key = "dummy"
53
+ end
54
+
55
+ assert_kind_of Confstruct::Configuration, returned_configuration
56
+ end
57
+
58
+ test "can take data argument instead of block" do
59
+ BentoSearch.register_engine("test_engine",
60
+ {:engine => "DummyEngine", :api_key => "dummy"}
61
+ )
62
+
63
+ engine = BentoSearch.get_engine("test_engine")
64
+
65
+ assert_kind_of BentoSearch::DummyEngine, engine
66
+ assert_equal "dummy", engine.configuration.api_key
67
+ end
68
+
69
+ test "block over-rides data argument" do
70
+ args = {:engine => "DummyEngine", :api_key => "dummy", :other_thing => "other_thing"}
71
+
72
+ BentoSearch.register_engine("test_engine", args) do |conf|
73
+ conf.api_key = "new_api_key"
74
+ end
75
+
76
+ engine = BentoSearch.get_engine("test_engine")
77
+
78
+
79
+ assert_equal "new_api_key", engine.configuration.api_key
80
+ assert_equal "other_thing", engine.configuration.other_thing
81
+ end
82
+
83
+ test "use one config as base for another" do
84
+ source_configuration = BentoSearch.register_engine("source_engine") do |conf|
85
+ conf.engine = "DummyEngine"
86
+ conf.api_key = "api_key"
87
+ conf.for_display do |display|
88
+ display.title = "source_title"
89
+ end
90
+ end
91
+
92
+ BentoSearch.register_engine("derived_engine", source_configuration) do |conf|
93
+ conf.for_display do |display|
94
+ display.title = "derived_title"
95
+ end
96
+ end
97
+
98
+ source_engine = BentoSearch.get_engine("source_engine")
99
+ derived_engine = BentoSearch.get_engine("derived_engine")
100
+
101
+ assert_equal "api_key", derived_engine.configuration.api_key
102
+ assert_equal "derived_title", derived_engine.configuration.for_display.title
103
+
104
+ assert_equal "source_title", source_engine.configuration.for_display.title
105
+
106
+ end
107
+
49
108
  end
50
109
 
@@ -169,11 +169,7 @@ class SummonEngineTest < ActiveSupport::TestCase
169
169
 
170
170
  assert_include first.title, '<b class="bento_search_highlight">'
171
171
 
172
- assert first.title.html_safe?, "title is HTML safe"
173
-
174
- assert_present first.custom_data['raw_title']
175
- assert_not_include first.custom_data['raw_title'], '<b class="bento_search_highlight">'
176
-
172
+ assert first.title.html_safe?, "title is HTML safe"
177
173
  end
178
174
 
179
175
  test_with_cassette("live #get(id)", :summon) do
@@ -0,0 +1,281 @@
1
+ require 'test_helper'
2
+
3
+ require 'nokogiri'
4
+
5
+ class AtomResultsTest < ActionView::TestCase
6
+ include ActionView::Helpers::UrlHelper
7
+
8
+ @@namespaces = {
9
+ "atom" => "http://www.w3.org/2005/Atom",
10
+ "opensearch" => "http://a9.com/-/spec/opensearch/1.1/",
11
+ "prism" => "http://prismstandard.org/namespaces/basic/2.1/",
12
+ "dcterms" => "http://purl.org/dc/terms/",
13
+ "bibo" => "http://purl.org/ontology/bibo/"
14
+ }
15
+
16
+ # Instead of using assert_select, we do it ourselves with nokogiri
17
+ # for better namespace control.
18
+ #
19
+ # xml = Nokogiri::XML( rendered )
20
+ # assert_node(xml, "atom:entry") do |matched_nodes|
21
+ # assert matched_node.first["attribute"] == "foo"
22
+ # end
23
+ def assert_node(xml, xpath, options = {})
24
+ result = xml.xpath(xpath, @@namespaces)
25
+
26
+ assert result.length > 0, "Expected xpath '#{xpath}' to match in #{xml.to_s[0..200]}..."
27
+
28
+ if options[:text]
29
+ assert_equal options[:text], result.text.strip, "Expected #{options[:text]} as content of #{result.to_s[0..200]}"
30
+ end
31
+
32
+ yield result if block_given?
33
+ end
34
+
35
+ def setup
36
+ @total_items = 1000
37
+ @start = 6
38
+ @per_page = 15
39
+
40
+
41
+ @engine = BentoSearch::MockEngine.new(:total_items => @total_items)
42
+ @results = @engine.search("some query", :start => @start, :per_page => @per_page)
43
+
44
+ # but fill the first result elements with some non-blank data to test
45
+ @article = BentoSearch::ResultItem.new(
46
+ :title => "An Article", #
47
+ :link => "http://example.org/main_link", #
48
+ :unique_id => "UNIQUE_ID",
49
+ :format => "Article", #
50
+ :format_str => "Uncontrolled format", #
51
+ :language_code => "en", #
52
+ :year => "2004", #
53
+ :volume => "10", #
54
+ :issue => "1", #
55
+ :start_page => "101", #
56
+ :end_page => "110", #
57
+ :source_title => "Journal of Something", #
58
+ :issn => "12345678", #
59
+ :doi => "10.1000/182", #
60
+ :abstract => "This is an abstract with escaped > parts < ", #
61
+ :authors => [ #
62
+ BentoSearch::Author.new(:first => "John", :last => "Smith"),
63
+ BentoSearch::Author.new(:display => "Jones, Jane")
64
+ ],
65
+ :other_links => [ #
66
+ BentoSearch::Link.new(:url => "http://example.org/bare_link"),
67
+ BentoSearch::Link.new(
68
+ :url => "http://example.org/label_and_type",
69
+ :label => "A link somewhere",
70
+ :type => "application/pdf"
71
+ ),
72
+ BentoSearch::Link.new(
73
+ :url => "http://example.org/rel",
74
+ :rel => "something"
75
+ )
76
+ ]
77
+ )
78
+ @article_with_html_abstract = BentoSearch::ResultItem.new(
79
+ :title => "foo",
80
+ :format => "Article",
81
+ :abstract => "This is <b>html</b>".html_safe
82
+ )
83
+ @article_with_full_date = BentoSearch::ResultItem.new(
84
+ :title => "foo",
85
+ :format => "Article",
86
+ :publication_date => Date.new(2011, 5, 6)
87
+ )
88
+ @book = BentoSearch::ResultItem.new(
89
+ :title => "A Book",
90
+ :format => "Book",
91
+ :publisher => "Some publisher",
92
+ :isbn => "123456789X",
93
+ :oclcnum => "12124345",
94
+ :year => "2004"
95
+ )
96
+
97
+
98
+
99
+ @results[0] = @article
100
+ @results[1] = @article_with_html_abstract
101
+ @results[3] = @article_with_full_date
102
+ @results[4] = @book
103
+ end
104
+
105
+ def test_smoke_atom_validate
106
+ # Validate under Atom schema. Should we validate under prism and dc schemas
107
+ # too? Not sure if it makes sense, or if there's even a relevant schema
108
+ # for how we're using em. So of just basic 'smoke' value.
109
+ render :template => "bento_search/atom_results", :locals => {:atom_results => @results}
110
+ xml_response = Nokogiri::XML( rendered ) { |config| config.strict }
111
+
112
+ atom_xsd_filepath = File.expand_path("../../support/atom.xsd.xml", __FILE__)
113
+ schema_xml = Nokogiri::XML(File.read(atom_xsd_filepath))
114
+ # modify to add processContents lax so it'll let us include elements from
115
+ # external namespaces.
116
+ schema_xml.xpath("//xs:any[@namespace='##other']", {"xs" => "http://www.w3.org/2001/XMLSchema"}).each do |node|
117
+ node["processContents"] = "lax"
118
+ end
119
+
120
+ schema = Nokogiri::XML::Schema.from_document( schema_xml )
121
+
122
+ assert_empty schema.validate(xml_response), "Validates with atom XSD schema"
123
+ end
124
+
125
+
126
+ def test_feed_metadata
127
+ render :template => "bento_search/atom_results", :locals => {:atom_results => @results}
128
+ xml_response = Nokogiri::XML( rendered )
129
+
130
+ assert_node(xml_response, "atom:feed") do |feed|
131
+ assert_node(feed, "atom:title")
132
+ assert_node(feed, "atom:author")
133
+ assert_node(feed, "atom:updated")
134
+
135
+ assert_node(feed, "opensearch:totalResults", :text => @total_items.to_s)
136
+ assert_node(feed, "opensearch:startIndex", :text => @start.to_s)
137
+ assert_node(feed, "opensearch:itemsPerPage", :text => @per_page.to_s)
138
+ end
139
+
140
+ end
141
+
142
+ def test_article_entry_example
143
+ render :template => "bento_search/atom_results", :locals => {:atom_results => @results}
144
+ xml_response = Nokogiri::XML( rendered )
145
+
146
+ assert_node(xml_response, "./atom:feed/atom:entry[1]") do |article|
147
+ assert_node(article, "atom:title", :text => @article.title)
148
+ assert_node(article, "prism:coverDate", :text => @article.year)
149
+
150
+ assert_node(article, "prism:issn", :text => @article.issn)
151
+ assert_node(article, "prism:doi", :text => @article.doi)
152
+
153
+ assert_node(article, "prism:volume", :text => @article.volume)
154
+ assert_node(article, "prism:number", :text => @article.issue)
155
+
156
+ assert_node(article, "prism:startingPage", :text => @article.start_page)
157
+ assert_node(article, "prism:endingPage", :text => @article.end_page)
158
+
159
+ assert_node(article, "prism:publicationName", :text => @article.source_title)
160
+
161
+ abstract = article.at_xpath("atom:summary", @@namespaces)
162
+ assert_present abstract, "Has an abstract"
163
+ assert_equal "text", abstract["type"], "Abstract type text"
164
+ assert_equal @article.abstract, abstract.text
165
+
166
+ assert_node(article, "dcterms:language[@vocabulary='http://dbpedia.org/resource/ISO_639-1']", :text => @article.language_iso_639_1)
167
+ assert_node(article, "dcterms:language[@vocabulary='http://dbpedia.org/resource/ISO_639-3']", :text => @article.language_iso_639_3)
168
+ assert_node(article, "dcterms:language[not(@vocabulary)]", :text => @article.language_str)
169
+
170
+ assert_node(article, "dcterms:type[not(@vocabulary)]", :text => @article.format_str)
171
+
172
+ assert_node(article, "dcterms:type[@vocabulary='http://schema.org/']", :text => @article.schema_org_type_url)
173
+ assert_node(article, "dcterms:type[@vocabulary='http://purl.org/NET/bento_search/ontology']", :text => @article.format)
174
+
175
+ # Just make sure right number of author elements, with right structure.
176
+ assert_node(article, "atom:author/atom:name") do |authors|
177
+ assert_equal @article.authors.length, authors.length, "right number of author elements"
178
+ end
179
+
180
+ # Links. Main link is just rel=alternate
181
+ assert_node(article,
182
+ "atom:link[@rel='alternate'][@href='#{@article.link}']")
183
+
184
+ # other links also there, default rel=related
185
+ assert_node(article,
186
+ "atom:link[@rel='related'][@type='application/pdf'][@title='A link somewhere'][@href='http://example.org/label_and_type']")
187
+ assert_node(article,
188
+ "atom:link[@rel='something'][@href='http://example.org/rel']")
189
+ end
190
+
191
+ end
192
+
193
+
194
+ def test_with_unique_id
195
+ @results = @engine.search("find")
196
+ @results[0] = BentoSearch::ResultItem.new(
197
+ :title => "Something",
198
+ :unique_id => "a000:/01",
199
+ :engine_id => "some_engine"
200
+ )
201
+
202
+ render :template => "bento_search/atom_results", :locals => {:atom_results => @results}
203
+ xml_response = Nokogiri::XML( rendered )
204
+
205
+ with_unique_id = xml_response.xpath("./atom:feed/atom:entry", @@namespaces)[0]
206
+
207
+ assert_node(with_unique_id, "atom:id") do |id|
208
+ # based off of engine_id and unique_id
209
+ assert_include id.text, "some_engine"
210
+ assert_include id.text, "a000%3A%2F01"
211
+ end
212
+ end
213
+
214
+ def test_with_html_abstract
215
+ render :template => "bento_search/atom_results", :locals => {:atom_results => @results}
216
+ xml_response = Nokogiri::XML( rendered )
217
+
218
+ with_html_abstract = xml_response.xpath("./atom:feed/atom:entry", @@namespaces)[1]
219
+
220
+ assert_node(with_html_abstract, "atom:summary[@type='html']", :text => @article_with_html_abstract.abstract.to_s)
221
+ end
222
+
223
+ def test_book
224
+ render :template => "bento_search/atom_results", :locals => {:atom_results => @results}
225
+ xml_response = Nokogiri::XML( rendered )
226
+
227
+ book = xml_response.xpath("./atom:feed/atom:entry", @@namespaces)[4]
228
+
229
+ assert_node(book, "dcterms:type[@vocabulary='http://purl.org/NET/bento_search/ontology']", :text => "Book")
230
+ assert_node(book, "dcterms:type[@vocabulary='http://schema.org/']", :text => "http://schema.org/Book")
231
+
232
+ assert_node(book, "dcterms:publisher", :text => @book.publisher)
233
+
234
+ assert_node(book, "prism:isbn", :text => @book.isbn)
235
+
236
+ assert_node(book, "bibo:oclcnum", :text => @book.oclcnum)
237
+ end
238
+
239
+ def test_with_full_date
240
+ render :template => "bento_search/atom_results", :locals => {:atom_results => @results}
241
+ xml_response = Nokogiri::XML( rendered )
242
+
243
+ with_full_date = xml_response.at_xpath("./atom:feed/atom:entry[4]", @@namespaces)
244
+
245
+ assert_node(with_full_date, "prism:coverDate", :text => "2011-05-06")
246
+ end
247
+
248
+ def test_nil_results
249
+ # should render a more or less empty atom response for
250
+ # nil results, convenient to not raise on nil
251
+ render :template => "bento_search/atom_results", :locals => {:atom_results => nil}
252
+ end
253
+
254
+ def test_locals_for_feed_name_and_author
255
+ render( :template => "bento_search/atom_results",
256
+ :locals => {:atom_results => @results,
257
+ :feed_name => "My Feed",
258
+ :feed_author_name => "ACME Seed And Feed Products"}
259
+ )
260
+
261
+ xml_response = Nokogiri::XML( rendered )
262
+
263
+ assert_node(xml_response, "./atom:feed/atom:title", :text => "My Feed")
264
+ assert_node(xml_response, "./atom:feed/atom:author/atom:name", :text => "ACME Seed And Feed Products")
265
+ end
266
+
267
+ def test_html_in_title_stripped
268
+ results = BentoSearch::Results.new
269
+ results << BentoSearch::ResultItem.new(
270
+ :title => "html <b>title</b>".html_safe
271
+ )
272
+
273
+ render(:template => "bento_search/atom_results", :locals => {:atom_results => results})
274
+ xml_response = Nokogiri::XML( rendered )
275
+
276
+ assert_node(xml_response, "./atom:feed/atom:entry[1]/atom:title", :text => "html title")
277
+
278
+ end
279
+
280
+
281
+ end