ddr-models 2.5.3 → 2.6.0.rc1

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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/users/sessions_controller.rb +0 -5
  3. data/config/initializers/devise.rb +3 -2
  4. data/config/initializers/rsolr_monkey_patches.rb +7 -0
  5. data/config/initializers/subscriptions.rb +0 -2
  6. data/ddr-models.gemspec +2 -1
  7. data/lib/ddr/actions/virus_check.rb +0 -1
  8. data/lib/ddr/auth.rb +0 -4
  9. data/lib/ddr/auth/ability_definitions/role_based_ability_definitions.rb +9 -16
  10. data/lib/ddr/derivatives/generator.rb +0 -2
  11. data/lib/ddr/derivatives/png_generator.rb +2 -4
  12. data/lib/ddr/derivatives/ptif_generator.rb +6 -7
  13. data/lib/ddr/index/fields.rb +18 -2
  14. data/lib/ddr/jobs.rb +0 -4
  15. data/lib/ddr/managers.rb +0 -1
  16. data/lib/ddr/managers/derivatives_manager.rb +3 -4
  17. data/lib/ddr/managers/workflow_manager.rb +3 -0
  18. data/lib/ddr/models.rb +6 -3
  19. data/lib/ddr/models/base.rb +13 -0
  20. data/lib/ddr/models/has_admin_metadata.rb +4 -20
  21. data/lib/ddr/models/indexing.rb +16 -0
  22. data/lib/ddr/models/solr_document.rb +8 -0
  23. data/lib/ddr/models/version.rb +1 -1
  24. data/lib/ddr/models/year_facet.rb +60 -118
  25. data/spec/auth/ability_spec.rb +1 -1
  26. data/spec/auth/roles/role_spec.rb +9 -9
  27. data/spec/index/fields_spec.rb +96 -0
  28. data/spec/models/active_fedora_datastream_spec.rb +6 -5
  29. data/spec/models/has_admin_metadata_spec.rb +49 -125
  30. data/spec/models/indexing_spec.rb +50 -18
  31. data/spec/models/solr_document_spec.rb +28 -0
  32. data/spec/models/year_facet_spec.rb +49 -22
  33. data/spec/support/shared_examples_for_ddr_models.rb +54 -2
  34. metadata +21 -8
  35. data/lib/ddr/jobs/permanent_id.rb +0 -35
  36. data/lib/ddr/managers/permanent_id_manager.rb +0 -93
@@ -20,12 +20,14 @@ module Ddr
20
20
  ACCESS_ROLE => roles.to_json,
21
21
  ADMIN_SET => admin_set,
22
22
  ADMIN_SET_TITLE => admin_set_title,
23
+ ARRANGER_FACET => desc_metadata_values('arranger'),
23
24
  ASPACE_ID => aspace_id,
24
25
  ATTACHED_FILES_HAVING_CONTENT => attached_files_having_content.keys,
25
26
  BOX_NUMBER_FACET => desc_metadata_values('box_number'),
26
27
  CATEGORY_FACET => desc_metadata_values('category'),
27
28
  COLLECTION_TITLE => collection_title,
28
29
  COMPANY_FACET => desc_metadata_values('company'),
30
+ COMPOSER_FACET => desc_metadata_values('composer'),
29
31
  CONTRIBUTOR_FACET => contributor,
30
32
  CREATOR_FACET => creator,
31
33
  DATE_FACET => date,
@@ -34,33 +36,47 @@ module Ddr
34
36
  DISPLAY_FORMAT => display_format,
35
37
  DOI => adminMetadata.doi,
36
38
  EAD_ID => ead_id,
39
+ ENGRAVER_FACET => desc_metadata_values('engraver'),
37
40
  FOLDER_FACET => desc_metadata_values('folder'),
38
41
  FORMAT_FACET => format,
42
+ GENRE_FACET => desc_metadata_values('genre'),
39
43
  IDENTIFIER_ALL => all_identifiers,
44
+ ILLUSTRATED_FACET => desc_metadata_values('illustrated'),
45
+ ILLUSTRATOR_FACET => desc_metadata_values('illustrator'),
46
+ INSTRUMENTATION_FACET => desc_metadata_values('instrumentation'),
40
47
  INTERNAL_URI => internal_uri,
48
+ INTERVIEWER_NAME_FACET => desc_metadata_values('interviewer_name'),
41
49
  IS_LOCKED => is_locked,
42
50
  LICENSE => license,
43
51
  LICENSE_DESCRIPTION => rightsMetadata.license.description.first,
44
52
  LICENSE_TITLE => rightsMetadata.license.title.first,
45
53
  LICENSE_URL => rightsMetadata.license.url.first,
54
+ LITHOGRAPHER_FACET => desc_metadata_values('lithographer'),
46
55
  LOCAL_ID => local_id,
56
+ LYRICIST_FACET => desc_metadata_values('lyricist'),
47
57
  MEDIUM_FACET => desc_metadata_values('medium'),
58
+ PERFORMER_FACET => desc_metadata_values('performer'),
48
59
  PERMANENT_ID => permanent_id,
49
60
  PERMANENT_URL => permanent_url,
50
61
  PLACEMENT_COMPANY_FACET => desc_metadata_values('placement_company'),
51
62
  POLICY_ROLE => roles.in_policy_scope.agents,
63
+ PRODUCER_FACET => desc_metadata_values('producer'),
52
64
  PRODUCT_FACET => desc_metadata_values('product'),
53
65
  PUBLICATION_FACET => desc_metadata_values('publication'),
54
66
  PUBLISHER_FACET => publisher,
55
67
  RESEARCH_HELP_CONTACT => research_help_contact,
56
68
  RESOURCE_ROLE => roles.in_resource_scope.agents,
69
+ ROLL_NUMBER_FACET => desc_metadata_values('roll_number'),
57
70
  SERIES_FACET => desc_metadata_values('series'),
58
71
  SETTING_FACET => desc_metadata_values('setting'),
59
72
  SPATIAL_FACET => desc_metadata_values('spatial'),
60
73
  SUBJECT_FACET => subject,
74
+ SUBSERIES_FACET => desc_metadata_values('subseries'),
75
+ TEMPORAL_FACET => desc_metadata_values('temporal'),
61
76
  TITLE => title_display,
62
77
  TONE_FACET => desc_metadata_values('tone'),
63
78
  TYPE_FACET => type,
79
+ VOLUME_FACET => desc_metadata_values('volume'),
64
80
  WORKFLOW_STATE => workflow_state,
65
81
  YEAR_FACET => year_facet,
66
82
  }
@@ -18,6 +18,14 @@ module Ddr::Models
18
18
  end
19
19
  raise NotFound, "SolrDocument not found for \"#{pid_or_uri}\"."
20
20
  end
21
+
22
+ def find_by_permanent_id(ark)
23
+ query = Ddr::Index::Query.new { where permanent_id: ark }
24
+ if doc = query.docs.first
25
+ return doc
26
+ end
27
+ raise NotFound, "SolrDocument not found for permanent id \"#{ark}\"."
28
+ end
21
29
  end
22
30
 
23
31
  def inspect
@@ -1,5 +1,5 @@
1
1
  module Ddr
2
2
  module Models
3
- VERSION = "2.5.3"
3
+ VERSION = "2.6.0.rc1"
4
4
  end
5
5
  end
@@ -1,153 +1,95 @@
1
1
  require "date"
2
+ require "edtf"
2
3
 
3
4
  module Ddr::Models
4
5
  class YearFacet
5
6
 
6
7
  EARLIEST_YEAR = 1000
8
+ LATEST_YEAR = Date.today.year + 100
9
+ VALID_YEARS = (EARLIEST_YEAR..LATEST_YEAR)
10
+ VALUE_SEP = /;/
7
11
 
8
12
  # Between 1965 and 1968
9
13
  BETWEEN = Regexp.new '\A([Bb]etween\s+)(\d{4})(\s+and\s+)(\d{4})\??\z'
10
14
 
11
- # YYYx (192x)
12
- # YYYX (192X)
13
- # YYY? (192?)
14
- # YYY- (192-)
15
- # YYY-? (192-?)
16
- IN_DECADE = Regexp.new '\A(\d{3})([xX\-]\??|\?)\z'
17
-
18
- # YYxx (19xx)
19
- IN_CENTURY = Regexp.new '\A(\d{2})xx\z'
20
-
21
- # YYY0s (1920s)
22
- # YYY0s? (1920s?)
23
- DECADE = Regexp.new '\A(\d{3}0)s\??\z'
24
-
25
- # YYYY-MM (2010-01)
26
- # YYYY/MM (2010/01)
27
- YEAR_MONTH = Regexp.new '\A(\d{4})[/-](0[1-9]|1[0-2])\z'
28
-
29
- # YYYY-YYYY (1935-2010)
30
- # YYYY/YYYY (1935/2010)
31
- YEAR_RANGE = Regexp.new '\A(\d{4})[/-](\d{4})\z'
32
-
33
- # YYYY (1979)
34
- YEAR = Regexp.new '\A\d{4}\z'
35
-
36
- SQUARE_BRACKETS = Regexp.new '[\[\]]'
37
-
38
- # c. 1920
39
- # ca. 1920
40
- # c1920
15
+ # circa 1920, ca. 1920, c1920 => 1920
41
16
  CIRCA = Regexp.new '\b(circa\s+|ca?\.\s*|c(?=\d{4}[^\d]*))'
42
17
 
43
- class << self
44
- def call(obj)
45
- new(obj).values
46
- end
47
- end
48
-
49
- attr_reader :obj, :values
50
-
51
- def initialize(obj)
52
- @obj = obj
53
- @values = []
54
- facet_values
55
- end
56
-
57
- def facet_values
58
- obj.date.each do |date|
59
- date.split(/;/).each do |value|
60
- clean! value
61
- years = extract_years(value)
62
- validate! years
63
- values.push *years
64
- end
65
- end
66
- end
67
-
68
- def extract_years(value)
69
- years = match_years(value) || parse_year(value)
70
- Array(years)
71
- end
72
-
73
- def clean!(value)
74
- value.strip!
75
- value.gsub! SQUARE_BRACKETS, ""
76
- value.gsub! CIRCA, ""
77
- end
18
+ # 1935-1940 => 1935/1940
19
+ YEAR_RANGE = Regexp.new '(?<=\d{4})-(?=\d{4})'
78
20
 
79
- def validate!(years)
80
- years = years & valid_years.to_a
81
- end
21
+ # 1920s, 1920s?, 192u, 192-, 192-?, 192? => 192x
22
+ DECADE = Regexp.new '(?<=\A\d{3})(-\??|0s\??|u|\?)\z'
82
23
 
83
- def parse_year(value)
84
- Date.parse(value).year
85
- rescue ArgumentError
86
- nil
87
- end
24
+ # 2010/01 => 2010-01
25
+ MONTH = Regexp.new '(?<=\A\d{4})\/(?=\d{2}\z)'
88
26
 
89
- def valid_years
90
- (EARLIEST_YEAR..latest_year)
91
- end
27
+ # 193u/, 193x/ => 1930/
28
+ START_DECADE = Regexp.new '(?<=\d{3})[uxX](?=\/)'
92
29
 
93
- def latest_year
94
- Date.today.year + 100
95
- end
30
+ # /194x, /194u => /1949
31
+ END_DECADE = Regexp.new '(?<=\/\d{3})[uxX]'
96
32
 
97
- def match_years(value)
98
- result = match_year_range(value) ||
99
- match_year_month(value) ||
100
- match_year(value) ||
101
- match_in_decade(value) ||
102
- match_in_century(value) ||
103
- match_decade(value) ||
104
- match_between(value)
105
- first_year, last_year = Array(result).map(&:to_i)
106
- last_year ? (first_year..last_year) : first_year
107
- end
33
+ # 19uu => 19xx
34
+ CENTURY = Regexp.new '(?<=\A\d{2})uu(?=\z)'
108
35
 
109
- def match_year_range(value)
110
- if m = YEAR_RANGE.match(value)
111
- m[1, 2]
112
- end
36
+ def self.call(object)
37
+ new(object).call
113
38
  end
114
39
 
115
- def match_year_month(value)
116
- if m = YEAR_MONTH.match(value)
117
- m[1]
118
- end
119
- end
40
+ attr_reader :object
120
41
 
121
- def match_year(value)
122
- if m = YEAR.match(value)
123
- value
124
- end
42
+ def initialize(object)
43
+ @object = object
125
44
  end
126
45
 
127
- def match_in_decade(value)
128
- if m = IN_DECADE.match(value)
129
- [ "#{m[1]}0", "#{m[1]}9" ]
46
+ def call
47
+ source_dates.each_with_object([]) do |date, facet_values|
48
+ date.split(VALUE_SEP).each do |value|
49
+ value.strip!
50
+ edtf_date = convert_to_edtf(value)
51
+ years = Array(edtf_years(edtf_date))
52
+ years.select! { |year| VALID_YEARS.include?(year) }
53
+ facet_values.push(*years)
54
+ end
130
55
  end
131
56
  end
132
57
 
133
- def match_in_century(value)
134
- if m = IN_CENTURY.match(value)
135
- [ "#{m[1]}00", "#{m[1]}99" ]
136
- end
137
- end
58
+ private
138
59
 
139
- def match_decade(value)
140
- if m = DECADE.match(value)
141
- [ m[1], m[1].sub(/0\z/, "9") ]
142
- end
60
+ def source_dates
61
+ object.descMetadata.date
143
62
  end
144
63
 
145
- def match_between(value)
64
+ def convert_to_edtf(value)
146
65
  if m = BETWEEN.match(value)
147
66
  value.sub! m[1], "" # [Bb]etween
148
- value.sub! m[3], "-" # and
149
- match_year_range(value)
67
+ value.sub! m[3], "/" # and
150
68
  end
69
+ substitutions.reduce(value) { |memo, (regexp, repl)| memo.gsub(regexp, repl) }
70
+ end
71
+
72
+ def substitutions
73
+ [
74
+ [ CIRCA, "" ],
75
+ [ YEAR_RANGE, "/" ],
76
+ [ DECADE, "x" ],
77
+ [ MONTH, "-" ],
78
+ [ START_DECADE, "0" ],
79
+ [ END_DECADE, "9" ],
80
+ [ CENTURY, "xx" ],
81
+ ]
82
+ end
83
+
84
+ def edtf_years(value)
85
+ case parsed = EDTF.parse!(value)
86
+ when Date, EDTF::Season
87
+ parsed.year
88
+ when EDTF::Set, EDTF::Interval, EDTF::Epoch
89
+ parsed.map(&:year).uniq
90
+ end
91
+ rescue ArgumentError # EDTF cannot parse
92
+ nil
151
93
  end
152
94
 
153
95
  end
@@ -297,7 +297,7 @@ module Ddr::Auth
297
297
  let(:cache_key) { obj }
298
298
  let(:perm_obj) { SolrDocument.new({"id"=>"test:1"}) }
299
299
  before do
300
- allow_any_instance_of(RoleBasedAbilityDefinitions).to receive(:permissions_doc).with(obj) { perm_obj }
300
+ allow(SolrDocument).to receive(:find).with("test:1") { perm_obj }
301
301
  end
302
302
  it_behaves_like "it has role based abilities"
303
303
  end
@@ -42,19 +42,19 @@ module Ddr::Auth
42
42
 
43
43
  describe "validation" do
44
44
  it "should require the presence of an agent" do
45
- expect { described_class.build(type: "Curator", scope: "resource") }.to raise_error
46
- expect { described_class.build(type: "Curator", agent: nil, scope: "resource") }.to raise_error
47
- expect { described_class.build(type: "Curator", agent: "", scope: "resource") }.to raise_error
45
+ expect { described_class.build(type: "Curator", scope: "resource") }.to raise_error(Ddr::Models::Error)
46
+ expect { described_class.build(type: "Curator", agent: nil, scope: "resource") }.to raise_error(Ddr::Models::Error)
47
+ expect { described_class.build(type: "Curator", agent: "", scope: "resource") }.to raise_error(Ddr::Models::Error)
48
48
  end
49
49
  it "should require a valid scope" do
50
- expect { described_class.build(type: "Curator", agent: agent, scope: "") }.to raise_error
51
- expect { described_class.build(type: "Curator", agent: agent, scope: "other") }.to raise_error
50
+ expect { described_class.build(type: "Curator", agent: agent, scope: "") }.to raise_error(Ddr::Models::Error)
51
+ expect { described_class.build(type: "Curator", agent: agent, scope: "other") }.to raise_error(Ddr::Models::Error)
52
52
  end
53
53
  it "should require a valid type" do
54
- expect { described_class.build(agent: agent, scope: "policy") }.to raise_error
55
- expect { described_class.build(type: nil, agent: agent, scope: "policy") }.to raise_error
56
- expect { described_class.build(type: "", agent: agent, scope: "policy") }.to raise_error
57
- expect { described_class.build(type: "Invalid", agent: agent, scope: "policy") }.to raise_error
54
+ expect { described_class.build(agent: agent, scope: "policy") }.to raise_error(Ddr::Models::Error)
55
+ expect { described_class.build(type: nil, agent: agent, scope: "policy") }.to raise_error(Ddr::Models::Error)
56
+ expect { described_class.build(type: "", agent: agent, scope: "policy") }.to raise_error(Ddr::Models::Error)
57
+ expect { described_class.build(type: "Invalid", agent: agent, scope: "policy") }.to raise_error(Ddr::Models::Error)
58
58
  end
59
59
  end
60
60
 
@@ -56,6 +56,12 @@ module Ddr::Index
56
56
  its(:heading) { is_expected.to eq "admin_set" }
57
57
  end
58
58
 
59
+ describe "ARRANGER_FACET" do
60
+ subject { Fields::ARRANGER_FACET }
61
+ its(:label) { is_expected.to eq "Arranger Facet" }
62
+ its(:heading) { is_expected.to eq "arranger_facet" }
63
+ end
64
+
59
65
  describe "ASPACE_ID" do
60
66
  subject { Fields::ASPACE_ID }
61
67
  its(:label) { is_expected.to eq "ArchivesSpace ID" }
@@ -74,6 +80,12 @@ module Ddr::Index
74
80
  its(:heading) { is_expected.to eq "company_facet" }
75
81
  end
76
82
 
83
+ describe "COMPOSER_FACET" do
84
+ subject { Fields::COMPOSER_FACET }
85
+ its(:label) { is_expected.to eq "Composer Facet" }
86
+ its(:heading) { is_expected.to eq "composer_facet" }
87
+ end
88
+
77
89
  describe "DOI" do
78
90
  subject { Fields::DOI }
79
91
  its(:label) { is_expected.to eq "DOI" }
@@ -86,18 +98,66 @@ module Ddr::Index
86
98
  its(:heading) { is_expected.to eq "ead_id" }
87
99
  end
88
100
 
101
+ describe "ENGRAVER FACET" do
102
+ subject { Fields::ENGRAVER_FACET }
103
+ its(:label) { is_expected.to eq "Engraver Facet" }
104
+ its(:heading) { is_expected.to eq "engraver_facet" }
105
+ end
106
+
89
107
  describe "FOLDER_FACET" do
90
108
  subject { Fields::FOLDER_FACET }
91
109
  its(:label) { is_expected.to eq "Folder Facet" }
92
110
  its(:heading) { is_expected.to eq "folder_facet" }
93
111
  end
94
112
 
113
+ describe "GENRE_FACET" do
114
+ subject { Fields::GENRE_FACET }
115
+ its(:label) { is_expected.to eq "Genre Facet" }
116
+ its(:heading) { is_expected.to eq "genre_facet" }
117
+ end
118
+
95
119
  describe "LOCAL_ID" do
96
120
  subject { Fields::LOCAL_ID }
97
121
  its(:label) { is_expected.to eq "Local ID" }
98
122
  its(:heading) { is_expected.to eq "local_id" }
99
123
  end
100
124
 
125
+ describe "ILLUSTRATED_FACET" do
126
+ subject { Fields::ILLUSTRATED_FACET }
127
+ its(:label) { is_expected.to eq "Illustrated Facet" }
128
+ its(:heading) { is_expected.to eq "illustrated_facet" }
129
+ end
130
+
131
+ describe "ILLUSTRATOR_FACET" do
132
+ subject { Fields::ILLUSTRATOR_FACET }
133
+ its(:label) { is_expected.to eq "Illustrator Facet" }
134
+ its(:heading) { is_expected.to eq "illustrator_facet" }
135
+ end
136
+
137
+ describe "INSTRUMENTATION_FACET" do
138
+ subject { Fields::INSTRUMENTATION_FACET }
139
+ its(:label) { is_expected.to eq "Instrumentation Facet" }
140
+ its(:heading) { is_expected.to eq "instrumentation_facet" }
141
+ end
142
+
143
+ describe "INTERVIEWER_NAME_FACET" do
144
+ subject { Fields::INTERVIEWER_NAME_FACET }
145
+ its(:label) { is_expected.to eq "Interviewer Name Facet" }
146
+ its(:heading) { is_expected.to eq "interviewer_name_facet" }
147
+ end
148
+
149
+ describe "LITHOGRAPHER_FACET" do
150
+ subject { Fields::LITHOGRAPHER_FACET }
151
+ its(:label) { is_expected.to eq "Lithographer Facet" }
152
+ its(:heading) { is_expected.to eq "lithographer_facet" }
153
+ end
154
+
155
+ describe "LYRICIST_FACET" do
156
+ subject { Fields::LYRICIST_FACET }
157
+ its(:label) { is_expected.to eq "Lyricist Facet" }
158
+ its(:heading) { is_expected.to eq "lyricist_facet" }
159
+ end
160
+
101
161
  describe "MEDIUM_FACET" do
102
162
  subject { Fields::MEDIUM_FACET }
103
163
  its(:label) { is_expected.to eq "Medium Facet" }
@@ -116,6 +176,12 @@ module Ddr::Index
116
176
  its(:heading) { is_expected.to eq "modification_date" }
117
177
  end
118
178
 
179
+ describe "PERFORMER_FACET" do
180
+ subject { Fields::PERFORMER_FACET }
181
+ its(:label) { is_expected.to eq "Performer Facet" }
182
+ its(:heading) { is_expected.to eq "performer_facet" }
183
+ end
184
+
119
185
  describe "PERMANENT_ID" do
120
186
  subject { Fields::PERMANENT_ID }
121
187
  its(:label) { is_expected.to eq "Permanent ID" }
@@ -134,6 +200,12 @@ module Ddr::Index
134
200
  its(:heading) { is_expected.to eq "placement_company_facet" }
135
201
  end
136
202
 
203
+ describe "PRODUCER_FACET" do
204
+ subject { Fields::PRODUCER_FACET }
205
+ its(:label) { is_expected.to eq "Producer Facet" }
206
+ its(:heading) { is_expected.to eq "producer_facet" }
207
+ end
208
+
137
209
  describe "PRODUCT_FACET" do
138
210
  subject { Fields::PRODUCT_FACET }
139
211
  its(:label) { is_expected.to eq "Product Facet" }
@@ -146,12 +218,24 @@ module Ddr::Index
146
218
  its(:heading) { is_expected.to eq "publication_facet" }
147
219
  end
148
220
 
221
+ describe "ROLL_NUMBER_FACET" do
222
+ subject { Fields::ROLL_NUMBER_FACET }
223
+ its(:label) { is_expected.to eq "Roll Number Facet" }
224
+ its(:heading) { is_expected.to eq "roll_number_facet" }
225
+ end
226
+
149
227
  describe "SETTING_FACET" do
150
228
  subject { Fields::SETTING_FACET }
151
229
  its(:label) { is_expected.to eq "Setting Facet" }
152
230
  its(:heading) { is_expected.to eq "setting_facet" }
153
231
  end
154
232
 
233
+ describe "SUBSERIES_FACET" do
234
+ subject { Fields::SUBSERIES_FACET }
235
+ its(:label) { is_expected.to eq "Subseries Facet" }
236
+ its(:heading) { is_expected.to eq "subseries_facet" }
237
+ end
238
+
155
239
  describe "TECHMD_COLOR_SPACE" do
156
240
  subject { Fields::TECHMD_COLOR_SPACE }
157
241
  its(:label) { is_expected.to eq "Color Space" }
@@ -242,11 +326,23 @@ module Ddr::Index
242
326
  its(:heading) { is_expected.to eq "well_formed" }
243
327
  end
244
328
 
329
+ describe "TEMPORAL_FACET" do
330
+ subject { Fields::TEMPORAL_FACET }
331
+ its(:label) { is_expected.to eq "Temporal Facet" }
332
+ its(:heading) { is_expected.to eq "temporal_facet" }
333
+ end
334
+
245
335
  describe "TONE_FACET" do
246
336
  subject { Fields::TONE_FACET }
247
337
  its(:label) { is_expected.to eq "Tone Facet" }
248
338
  its(:heading) { is_expected.to eq "tone_facet" }
249
339
  end
340
+
341
+ describe "VOLUME_FACET" do
342
+ subject { Fields::VOLUME_FACET }
343
+ its(:label) { is_expected.to eq "Volume Facet" }
344
+ its(:heading) { is_expected.to eq "volume_facet" }
345
+ end
250
346
  end
251
347
 
252
348
  end