iiif-presentation 1.0.0 → 1.2.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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +35 -0
- data/.gitignore +1 -0
- data/Gemfile +2 -0
- data/README.md +22 -2
- data/VERSION +1 -1
- data/iiif-presentation.gemspec +1 -1
- data/lib/iiif/hash_behaviours.rb +1 -1
- data/lib/iiif/presentation/canvas.rb +4 -0
- data/lib/iiif/presentation/service.rb +12 -0
- data/lib/iiif/presentation.rb +5 -4
- data/lib/iiif/service.rb +40 -105
- data/lib/iiif/v3/abstract_resource.rb +491 -0
- data/lib/iiif/v3/presentation/annotation.rb +74 -0
- data/lib/iiif/v3/presentation/annotation_collection.rb +38 -0
- data/lib/iiif/v3/presentation/annotation_page.rb +53 -0
- data/lib/iiif/v3/presentation/canvas.rb +82 -0
- data/lib/iiif/v3/presentation/choice.rb +51 -0
- data/lib/iiif/v3/presentation/collection.rb +52 -0
- data/lib/iiif/v3/presentation/image_resource.rb +110 -0
- data/lib/iiif/v3/presentation/manifest.rb +82 -0
- data/lib/iiif/v3/presentation/range.rb +39 -0
- data/lib/iiif/v3/presentation/resource.rb +30 -0
- data/lib/iiif/v3/presentation/sequence.rb +66 -0
- data/lib/iiif/v3/presentation/service.rb +51 -0
- data/lib/iiif/v3/presentation.rb +36 -0
- data/spec/fixtures/v3/manifests/complete_from_spec.json +195 -0
- data/spec/fixtures/v3/manifests/minimal.json +49 -0
- data/spec/fixtures/v3/manifests/service_only.json +14 -0
- data/spec/fixtures/vcr_cassettes/pul_loris_cassette.json +1 -1
- data/spec/fixtures/vcr_cassettes/pul_loris_cassette_v3.json +1 -0
- data/spec/integration/iiif/presentation/image_resource_spec.rb +0 -1
- data/spec/integration/iiif/service_spec.rb +17 -32
- data/spec/integration/iiif/v3/abstract_resource_spec.rb +202 -0
- data/spec/integration/iiif/v3/presentation/image_resource_spec.rb +118 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/unit/iiif/presentation/canvas_spec.rb +0 -1
- data/spec/unit/iiif/presentation/manifest_spec.rb +1 -1
- data/spec/unit/iiif/v3/abstract_resource_define_methods_for_spec.rb +78 -0
- data/spec/unit/iiif/v3/abstract_resource_spec.rb +293 -0
- data/spec/unit/iiif/v3/presentation/annotation_collection_spec.rb +36 -0
- data/spec/unit/iiif/v3/presentation/annotation_page_spec.rb +131 -0
- data/spec/unit/iiif/v3/presentation/annotation_spec.rb +389 -0
- data/spec/unit/iiif/v3/presentation/canvas_spec.rb +337 -0
- data/spec/unit/iiif/v3/presentation/choice_spec.rb +120 -0
- data/spec/unit/iiif/v3/presentation/collection_spec.rb +55 -0
- data/spec/unit/iiif/v3/presentation/image_resource_spec.rb +189 -0
- data/spec/unit/iiif/v3/presentation/manifest_spec.rb +370 -0
- data/spec/unit/iiif/v3/presentation/range_spec.rb +54 -0
- data/spec/unit/iiif/v3/presentation/resource_spec.rb +174 -0
- data/spec/unit/iiif/v3/presentation/sequence_spec.rb +222 -0
- data/spec/unit/iiif/v3/presentation/service_spec.rb +220 -0
- data/spec/unit/iiif/v3/presentation/shared_examples/abstract_resource_only_keys.rb +41 -0
- data/spec/unit/iiif/v3/presentation/shared_examples/any_type_keys.rb +31 -0
- data/spec/unit/iiif/v3/presentation/shared_examples/array_only_keys.rb +40 -0
- data/spec/unit/iiif/v3/presentation/shared_examples/hash_only_keys.rb +40 -0
- data/spec/unit/iiif/v3/presentation/shared_examples/int_only_keys.rb +45 -0
- data/spec/unit/iiif/v3/presentation/shared_examples/numeric_only_keys.rb +45 -0
- data/spec/unit/iiif/v3/presentation/shared_examples/string_only_keys.rb +26 -0
- data/spec/unit/iiif/v3/presentation/shared_examples/uri_only_keys.rb +31 -0
- metadata +82 -11
- data/.travis.yml +0 -11
@@ -0,0 +1,131 @@
|
|
1
|
+
describe IIIF::V3::Presentation::AnnotationPage do
|
2
|
+
|
3
|
+
describe '#required_keys' do
|
4
|
+
it 'id' do
|
5
|
+
expect(subject.required_keys).to include('id')
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#prohibited_keys' do
|
10
|
+
it 'contains the expected key names' do
|
11
|
+
keys = described_class::CONTENT_RESOURCE_PROPERTIES +
|
12
|
+
%w{
|
13
|
+
first
|
14
|
+
last
|
15
|
+
total
|
16
|
+
nav_date
|
17
|
+
viewing_direction
|
18
|
+
start_canvas
|
19
|
+
content_annotations
|
20
|
+
}
|
21
|
+
expect(subject.prohibited_keys).to include(*keys)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#uri_only_keys' do
|
26
|
+
it 'id' do
|
27
|
+
expect(subject.uri_only_keys).to include('id')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#array_only_keys' do
|
32
|
+
it 'items' do
|
33
|
+
expect(subject.array_only_keys).to include('items')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#legal_viewing_hint_values' do
|
38
|
+
it 'contains none' do
|
39
|
+
expect(subject.legal_viewing_hint_values).to contain_exactly('none')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#initialize' do
|
44
|
+
it 'sets type to AnnotationPage by default' do
|
45
|
+
expect(subject['type']).to eq 'AnnotationPage'
|
46
|
+
end
|
47
|
+
it 'allows subclasses to override type' do
|
48
|
+
subclass = Class.new(described_class) do
|
49
|
+
def initialize(hsh={})
|
50
|
+
hsh = { 'type' => 'a:SubClass' }
|
51
|
+
super(hsh)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
sub = subclass.new
|
55
|
+
expect(sub['type']).to eq 'a:SubClass'
|
56
|
+
end
|
57
|
+
it 'allows type to be passed in' do
|
58
|
+
ap = described_class.new('type' => 'bar')
|
59
|
+
expect(ap.type).to eq 'bar'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe '#validate' do
|
64
|
+
it 'raises IllegalValueError if id is not URI' do
|
65
|
+
exp_err_msg = "id value must be a String containing a URI for #{described_class}"
|
66
|
+
subject['id'] = 'foo'
|
67
|
+
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, exp_err_msg)
|
68
|
+
end
|
69
|
+
it 'raises IllegalValueError if id is not http(s)' do
|
70
|
+
subject['id'] = 'ftp://www.example.org'
|
71
|
+
exp_err_msg = "id must be an http(s) URI for #{described_class}"
|
72
|
+
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, exp_err_msg)
|
73
|
+
end
|
74
|
+
it 'raises IllegalValueError for items entry that is not an Annotation' do
|
75
|
+
subject['id'] = 'http://example.com/iiif3/annotation_page/666'
|
76
|
+
subject['items'] = [IIIF::V3::Presentation::ImageResource.new, IIIF::V3::Presentation::Annotation.new]
|
77
|
+
exp_err_msg = "All entries in the items list must be a IIIF::V3::Presentation::Annotation"
|
78
|
+
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, exp_err_msg)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe 'realistic examples' do
|
83
|
+
let(:ap_id) { 'http://example.com/iiif3/annotation_page/666' }
|
84
|
+
let(:anno) { IIIF::V3::Presentation::Annotation.new(
|
85
|
+
'id' => 'http://example.com/anno/666',
|
86
|
+
'target' => 'http://example.com/canvas/abc'
|
87
|
+
)}
|
88
|
+
|
89
|
+
describe 'stanford (purl code)' do
|
90
|
+
let(:anno_page) {
|
91
|
+
anno_page = described_class.new
|
92
|
+
anno_page['id'] = ap_id
|
93
|
+
anno_page.items << anno
|
94
|
+
anno_page
|
95
|
+
}
|
96
|
+
it 'validates' do
|
97
|
+
expect{anno_page.validate}.not_to raise_error
|
98
|
+
end
|
99
|
+
it 'has expected required values' do
|
100
|
+
expect(anno_page.id).to eq ap_id
|
101
|
+
expect(anno_page['type']).to eq 'AnnotationPage'
|
102
|
+
end
|
103
|
+
it 'has expected additional values' do
|
104
|
+
expect(anno_page.items).to eq [anno]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe 'two items' do
|
109
|
+
let(:anno2) { IIIF::V3::Presentation::Annotation.new(
|
110
|
+
'id' => 'http://example.com/anno/333',
|
111
|
+
'target' => 'http://example.com/canvas/abc'
|
112
|
+
)}
|
113
|
+
let(:anno_page) {
|
114
|
+
anno_page = described_class.new
|
115
|
+
anno_page['id'] = ap_id
|
116
|
+
anno_page.items = [anno, anno2]
|
117
|
+
anno_page
|
118
|
+
}
|
119
|
+
it 'validates' do
|
120
|
+
expect{anno_page.validate}.not_to raise_error
|
121
|
+
end
|
122
|
+
it 'has expected required values' do
|
123
|
+
expect(anno_page.id).to eq ap_id
|
124
|
+
expect(anno_page['type']).to eq 'AnnotationPage'
|
125
|
+
end
|
126
|
+
it 'has expected additional values' do
|
127
|
+
expect(anno_page.items).to eq [anno, anno2]
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,389 @@
|
|
1
|
+
describe IIIF::V3::Presentation::Annotation do
|
2
|
+
|
3
|
+
let(:content_id) { 'http://example.org/iiif/book1/res/tei-text-p1.xml' }
|
4
|
+
let(:content_type) { 'dctypes:Text' }
|
5
|
+
let(:mimetype) { 'application/tei+xml' }
|
6
|
+
let(:image_2_api_service) { IIIF::V3::Presentation::Service.new({
|
7
|
+
'id' => content_id,
|
8
|
+
'@id' => content_id,
|
9
|
+
'profile' => IIIF::V3::Presentation::Service::IIIF_IMAGE_V2_LEVEL1_PROFILE
|
10
|
+
})}
|
11
|
+
let(:img_content_resource) { IIIF::V3::Presentation::ImageResource.new(
|
12
|
+
'id' => content_id,
|
13
|
+
'type' => content_type,
|
14
|
+
'format' => mimetype,
|
15
|
+
'service' => image_2_api_service
|
16
|
+
)}
|
17
|
+
|
18
|
+
describe '#required_keys' do
|
19
|
+
%w{ type id motivation target }.each do |k|
|
20
|
+
it k do
|
21
|
+
expect(subject.required_keys).to include(k)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#prohibited_keys' do
|
27
|
+
it 'contains the expected key names' do
|
28
|
+
keys = described_class::PAGING_PROPERTIES +
|
29
|
+
described_class::CONTENT_RESOURCE_PROPERTIES +
|
30
|
+
%w{
|
31
|
+
nav_date
|
32
|
+
viewing_direction
|
33
|
+
start_canvas
|
34
|
+
content_annotations
|
35
|
+
}
|
36
|
+
expect(subject.prohibited_keys).to include(*keys)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#any_type_keys' do
|
41
|
+
it 'body' do
|
42
|
+
expect(subject.any_type_keys).to include('body')
|
43
|
+
end
|
44
|
+
it 'target' do
|
45
|
+
expect(subject.any_type_keys).to include('target')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#uri_only_keys' do
|
50
|
+
it 'id' do
|
51
|
+
expect(subject.uri_only_keys).to include('id')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '#string_only_keys' do
|
56
|
+
it 'time_mode' do
|
57
|
+
expect(subject.string_only_keys).to include('time_mode')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#legal_time_mode_values' do
|
62
|
+
it 'contains the expected values' do
|
63
|
+
expect(subject.legal_time_mode_values).to contain_exactly('trim', 'scale', 'loop')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '#legal_viewing_hint_values' do
|
68
|
+
it 'contains none' do
|
69
|
+
expect(subject.legal_viewing_hint_values).to contain_exactly('none')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#initialize' do
|
74
|
+
it 'sets type to Annotation by default' do
|
75
|
+
expect(subject['type']).to eq 'Annotation'
|
76
|
+
end
|
77
|
+
it 'allows subclasses to override type' do
|
78
|
+
subclass = Class.new(described_class) do
|
79
|
+
def initialize(hsh={})
|
80
|
+
hsh = { 'type' => 'a:SubClass' }
|
81
|
+
super(hsh)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
sub = subclass.new
|
85
|
+
expect(sub['type']).to eq 'a:SubClass'
|
86
|
+
end
|
87
|
+
it 'sets motivation to painting by default' do
|
88
|
+
expect(subject['motivation']).to eq 'painting'
|
89
|
+
end
|
90
|
+
it 'allows motivation to be passed in' do
|
91
|
+
my_anno = described_class.new('motivation' => 'foo')
|
92
|
+
expect(my_anno.motivation).to eq 'foo'
|
93
|
+
end
|
94
|
+
it 'allows type to be passed in' do
|
95
|
+
my_anno = described_class.new('type' => 'bar')
|
96
|
+
expect(my_anno.type).to eq 'bar'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe '#validate' do
|
101
|
+
before(:each) do
|
102
|
+
subject['id'] = 'http://example.org/iiif/anno/1s'
|
103
|
+
subject['target'] = 'foo'
|
104
|
+
end
|
105
|
+
it 'raises IllegalValueError if id is not URI' do
|
106
|
+
exp_err_msg = "id value must be a String containing a URI for #{described_class}"
|
107
|
+
subject['id'] = 'foo'
|
108
|
+
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, exp_err_msg)
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'raises IllegalValueError if time_mode isn\'t an allowable value' do
|
112
|
+
exp_err_msg = "timeMode for #{described_class} must be one of [\"trim\", \"scale\", \"loop\"]."
|
113
|
+
subject['time_mode'] = 'foo'
|
114
|
+
expect { subject.validate }.to raise_error IIIF::V3::Presentation::IllegalValueError, exp_err_msg
|
115
|
+
end
|
116
|
+
|
117
|
+
describe 'body is a kind of IIIF::V3::Presentation::ImageResource' do
|
118
|
+
let(:img_body_anno) {
|
119
|
+
subject['id'] = 'http://example.org/iiif/anno/1s'
|
120
|
+
subject['target'] = 'foo'
|
121
|
+
subject['body'] = img_content_resource
|
122
|
+
subject
|
123
|
+
}
|
124
|
+
it 'raises IllegalValueError if motivation isn\'t "painting"' do
|
125
|
+
exp_err_msg = "#{described_class} motivation must be 'painting' when body is a kind of IIIF::V3::Presentation::ImageResource"
|
126
|
+
img_body_anno['motivation'] = 'foo'
|
127
|
+
expect { img_body_anno.validate }.to raise_error IIIF::V3::Presentation::IllegalValueError, exp_err_msg
|
128
|
+
end
|
129
|
+
let(:img_resource_without_id) {
|
130
|
+
IIIF::V3::Presentation::ImageResource.new(
|
131
|
+
'type' => content_type,
|
132
|
+
'format' => mimetype
|
133
|
+
)}
|
134
|
+
let(:http_uri_err_msg) {
|
135
|
+
"when #{described_class} body is a kind of IIIF::V3::Presentation::ImageResource, ImageResource id must be an http(s) URI"
|
136
|
+
}
|
137
|
+
it 'raises IllegalValueError if no id field in ImageResource' do
|
138
|
+
img_body_anno.body = img_resource_without_id
|
139
|
+
expect { img_body_anno.validate }.to raise_error IIIF::V3::Presentation::IllegalValueError, http_uri_err_msg
|
140
|
+
end
|
141
|
+
it 'raises IllegalValueError if id in ImageResource isn\'t URI' do
|
142
|
+
img_resource_without_id['id'] = 'foo'
|
143
|
+
img_body_anno.body = img_resource_without_id
|
144
|
+
expect { img_body_anno.validate }.to raise_error IIIF::V3::Presentation::IllegalValueError, http_uri_err_msg
|
145
|
+
end
|
146
|
+
it 'raises IllegalValueError if id in ImageResource isn\'t http(s) URI' do
|
147
|
+
img_resource_without_id['id'] = 'ftp://example.com/somewhere'
|
148
|
+
img_body_anno.body = img_resource_without_id
|
149
|
+
expect { img_body_anno.validate }.to raise_error IIIF::V3::Presentation::IllegalValueError, http_uri_err_msg
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe 'realistic examples' do
|
155
|
+
let(:anno_id) { 'http://example.org/iiif/annoation/abc666'}
|
156
|
+
let(:target_id) { 'http://example.org/iiif/canvas/abc666'}
|
157
|
+
|
158
|
+
describe 'stanford (purl code)' do
|
159
|
+
let(:anno) {
|
160
|
+
anno = described_class.new
|
161
|
+
anno['id'] = anno_id
|
162
|
+
anno['target'] = target_id
|
163
|
+
anno.body = img_content_resource
|
164
|
+
anno
|
165
|
+
}
|
166
|
+
it 'validates' do
|
167
|
+
expect{anno.validate}.not_to raise_error
|
168
|
+
end
|
169
|
+
it 'has expected required values' do
|
170
|
+
expect(anno.id).to eq anno_id
|
171
|
+
expect(anno['type']).to eq 'Annotation'
|
172
|
+
expect(anno['motivation']).to eq 'painting'
|
173
|
+
expect(anno['target']).to eq target_id
|
174
|
+
end
|
175
|
+
it 'has expected additional values' do
|
176
|
+
expect(anno['body']).to eq img_content_resource
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe 'from http://prezi3.iiif.io/api/presentation/3.0' do
|
181
|
+
describe 'body is image_resource with height and width' do
|
182
|
+
let(:img_type) { 'dctypes:Image' }
|
183
|
+
let(:img_mime) { 'image/jpeg' }
|
184
|
+
let(:img_h) { 2000 }
|
185
|
+
let(:img_w) { 1500 }
|
186
|
+
let(:img_hw_resource) { IIIF::V3::Presentation::ImageResource.new(
|
187
|
+
'id' => content_id,
|
188
|
+
'type' => img_type,
|
189
|
+
'format' => img_mime,
|
190
|
+
'height' => img_h,
|
191
|
+
'width' => img_w,
|
192
|
+
'service' => image_2_api_service
|
193
|
+
)}
|
194
|
+
let(:my_anno) {
|
195
|
+
anno = described_class.new
|
196
|
+
anno['id'] = anno_id
|
197
|
+
anno['target'] = target_id
|
198
|
+
anno.body = img_hw_resource
|
199
|
+
anno
|
200
|
+
}
|
201
|
+
it 'validates' do
|
202
|
+
expect{my_anno.validate}.not_to raise_error
|
203
|
+
end
|
204
|
+
it 'has expected additional values' do
|
205
|
+
expect(my_anno['body']).to eq img_hw_resource
|
206
|
+
expect(my_anno['body']['height']).to eq img_h
|
207
|
+
expect(my_anno['body']['width']).to eq img_w
|
208
|
+
end
|
209
|
+
|
210
|
+
describe 'and service with height and width and tiles' do
|
211
|
+
let(:tiles_val) { [{"width" => 512, "scaleFactors" => [1,2,4,8,16]}] }
|
212
|
+
let(:service) {
|
213
|
+
s = image_2_api_service
|
214
|
+
s['height'] = 8000
|
215
|
+
s['width'] = 6000
|
216
|
+
s['tiles'] = tiles_val
|
217
|
+
s
|
218
|
+
}
|
219
|
+
it 'validates' do
|
220
|
+
img_hw_resource['service'] = service
|
221
|
+
expect{my_anno.validate}.not_to raise_error
|
222
|
+
end
|
223
|
+
it "body['service'] has expected additional values'" do
|
224
|
+
expect(my_anno['body']['service']).to eq service
|
225
|
+
expect(my_anno['body']['service']['height']).to eq 8000
|
226
|
+
expect(my_anno['body']['service']['width']).to eq 6000
|
227
|
+
expect(my_anno['body']['service']['tiles']).to eq tiles_val
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
describe 'from digerati' do
|
234
|
+
describe 'anno body is audio' do
|
235
|
+
let(:body_id) { 'http://example.org/iiif/foo2.mp3' }
|
236
|
+
let(:body_type) { 'Audio' }
|
237
|
+
let(:audio_res) { IIIF::V3::Presentation::Resource.new(
|
238
|
+
'id' => body_id,
|
239
|
+
'type' => body_type
|
240
|
+
)}
|
241
|
+
let(:my_anno) {
|
242
|
+
anno = described_class.new
|
243
|
+
anno['id'] = anno_id
|
244
|
+
anno['target'] = target_id
|
245
|
+
anno.body = audio_res
|
246
|
+
anno
|
247
|
+
}
|
248
|
+
it 'validates' do
|
249
|
+
expect{my_anno.validate}.not_to raise_error
|
250
|
+
end
|
251
|
+
it 'has expected required values' do
|
252
|
+
expect(my_anno['type']).to eq 'Annotation'
|
253
|
+
expect(my_anno.id).to eq anno_id
|
254
|
+
expect(my_anno['motivation']).to eq 'painting'
|
255
|
+
expect(my_anno['target']).to eq target_id
|
256
|
+
end
|
257
|
+
it 'has expected additional values' do
|
258
|
+
expect(my_anno['body']).to eq audio_res
|
259
|
+
expect(my_anno['body']['type']).to eq body_type
|
260
|
+
expect(my_anno['body']['id']).to eq body_id
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
describe 'anno body is video' do
|
265
|
+
let(:body_id) { 'http://example.org/foo.webm' }
|
266
|
+
let(:body_type) { 'Video' }
|
267
|
+
let(:body_mime) { 'video/webm' }
|
268
|
+
let(:video_res) { IIIF::V3::Presentation::Resource.new(
|
269
|
+
'id' => body_id,
|
270
|
+
'type' => body_type,
|
271
|
+
'format' => body_mime
|
272
|
+
)}
|
273
|
+
let(:my_anno) {
|
274
|
+
anno = described_class.new
|
275
|
+
anno['id'] = anno_id
|
276
|
+
anno['target'] = target_id
|
277
|
+
anno.body = video_res
|
278
|
+
anno
|
279
|
+
}
|
280
|
+
it 'validates' do
|
281
|
+
expect{my_anno.validate}.not_to raise_error
|
282
|
+
end
|
283
|
+
it 'has expected body values' do
|
284
|
+
expect(my_anno['body']).to eq video_res
|
285
|
+
expect(my_anno['body']['type']).to eq body_type
|
286
|
+
expect(my_anno['body']['id']).to eq body_id
|
287
|
+
expect(my_anno['body']['format']).to eq body_mime
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
describe 'anno body is 3d object' do
|
292
|
+
let(:body_id) { 'http://files.universalviewer.io/manifests/nelis/animal-skull/animal-skull.json' }
|
293
|
+
let(:body_type) { 'PhysicalObject' }
|
294
|
+
let(:body_mime) { 'application/vnd.threejs+json' }
|
295
|
+
let(:body_label) { 'Animal Skull' }
|
296
|
+
let(:body_res) { IIIF::V3::Presentation::Resource.new(
|
297
|
+
'id' => body_id,
|
298
|
+
'type' => body_type,
|
299
|
+
'format' => body_mime,
|
300
|
+
'label' => body_label
|
301
|
+
)}
|
302
|
+
let(:my_anno) {
|
303
|
+
anno = described_class.new
|
304
|
+
anno['id'] = anno_id
|
305
|
+
anno['target'] = target_id
|
306
|
+
anno.body = body_res
|
307
|
+
anno
|
308
|
+
}
|
309
|
+
it 'validates' do
|
310
|
+
expect{my_anno.validate}.not_to raise_error
|
311
|
+
end
|
312
|
+
it 'has expected body values' do
|
313
|
+
expect(my_anno['body']).to eq body_res
|
314
|
+
expect(my_anno['body']['type']).to eq body_type
|
315
|
+
expect(my_anno['body']['id']).to eq body_id
|
316
|
+
expect(my_anno['body']['format']).to eq body_mime
|
317
|
+
expect(my_anno['body']['label']).to eq body_label
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
describe 'anno body is pdf' do
|
322
|
+
let(:body_id) { 'http://example.org/iiif/some-document.pdf' }
|
323
|
+
let(:body_type) { 'Document' }
|
324
|
+
let(:body_mime) { 'application/pdf' }
|
325
|
+
let(:body_res) { IIIF::V3::Presentation::Resource.new(
|
326
|
+
'id' => body_id,
|
327
|
+
'type' => body_type,
|
328
|
+
'format' => body_mime
|
329
|
+
)}
|
330
|
+
let(:my_anno) {
|
331
|
+
anno = described_class.new
|
332
|
+
anno['id'] = anno_id
|
333
|
+
anno['target'] = target_id
|
334
|
+
anno.body = body_res
|
335
|
+
anno
|
336
|
+
}
|
337
|
+
it 'validates' do
|
338
|
+
expect{my_anno.validate}.not_to raise_error
|
339
|
+
end
|
340
|
+
it 'has expected body values' do
|
341
|
+
expect(my_anno['body']).to eq body_res
|
342
|
+
expect(my_anno['body']['type']).to eq body_type
|
343
|
+
expect(my_anno['body']['id']).to eq body_id
|
344
|
+
expect(my_anno['body']['format']).to eq body_mime
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
describe 'anno body is choice (of 2 videos)' do
|
349
|
+
let(:body_type) { 'Video' }
|
350
|
+
let(:body1_id) { 'http://example.org/foo.mp4f' }
|
351
|
+
let(:body1_mime) { 'video/mp4; codec..xxxxx' }
|
352
|
+
let(:body1_res) { IIIF::V3::Presentation::Resource.new(
|
353
|
+
'id' => body1_id,
|
354
|
+
'type' => body_type,
|
355
|
+
'format' => body1_mime
|
356
|
+
)}
|
357
|
+
let(:body2_id) { 'http://example.org/foo.webm' }
|
358
|
+
let(:body2_mime) { 'video/webm' }
|
359
|
+
let(:body2_res) { IIIF::V3::Presentation::Resource.new(
|
360
|
+
'id' => body2_id,
|
361
|
+
'type' => body_type,
|
362
|
+
'format' => body2_mime
|
363
|
+
)}
|
364
|
+
let(:body_res) { IIIF::V3::Presentation::Choice.new(
|
365
|
+
'items' => [body1_res, body2_res],
|
366
|
+
'choiceHint' => 'client'
|
367
|
+
)}
|
368
|
+
let(:my_anno) {
|
369
|
+
anno = described_class.new
|
370
|
+
anno['id'] = anno_id
|
371
|
+
anno['target'] = target_id
|
372
|
+
anno.body = body_res
|
373
|
+
anno
|
374
|
+
}
|
375
|
+
it 'validates' do
|
376
|
+
expect{my_anno.validate}.not_to raise_error
|
377
|
+
end
|
378
|
+
it 'has expected body values' do
|
379
|
+
expect(my_anno['body']).to eq body_res
|
380
|
+
expect(my_anno['body'].keys.size).to eq 3
|
381
|
+
expect(my_anno['body']['type']).to eq 'Choice'
|
382
|
+
expect(my_anno['body'].choiceHint).to eq 'client'
|
383
|
+
expect(my_anno['body']['items']).to eq [body1_res, body2_res]
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
end
|