hydra-works 0.0.1 → 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.
- checksums.yaml +4 -4
- data/.gitignore +3 -1
- data/.travis.yml +2 -5
- data/Gemfile +1 -3
- data/README.md +28 -13
- data/hydra-works.gemspec +4 -3
- data/lib/hydra/works.rb +7 -57
- data/lib/hydra/works/models/concerns/block_child_objects.rb +16 -0
- data/lib/hydra/works/models/concerns/collection_behavior.rb +27 -2
- data/lib/hydra/works/models/concerns/generic_file/contained_files.rb +5 -13
- data/lib/hydra/works/models/concerns/generic_file/derivatives.rb +9 -13
- data/lib/hydra/works/models/concerns/generic_file/mime_types.rb +14 -9
- data/lib/hydra/works/models/concerns/generic_file/versioned_content.rb +18 -0
- data/lib/hydra/works/models/concerns/generic_file/virus_check.rb +48 -0
- data/lib/hydra/works/models/concerns/generic_file_behavior.rb +24 -1
- data/lib/hydra/works/models/concerns/generic_work_behavior.rb +32 -3
- data/lib/hydra/works/models/generic_file.rb +3 -0
- data/lib/hydra/works/services/generic_file/add_file_to_generic_file.rb +127 -0
- data/lib/hydra/works/services/generic_file/generate/thumbnail.rb +1 -2
- data/lib/hydra/works/services/generic_file/persist_derivative.rb +22 -0
- data/lib/hydra/works/services/generic_file/upload_file.rb +11 -19
- data/lib/hydra/works/version.rb +1 -1
- data/lib/hydra/works/vocab/works_terms.rb +1 -1
- data/spec/fixtures/Example.ogg +0 -0
- data/spec/fixtures/charter.docx +0 -0
- data/spec/fixtures/countdown.avi +0 -0
- data/spec/fixtures/image.jp2 +0 -0
- data/spec/fixtures/piano_note.wav +0 -0
- data/spec/fixtures/test5.mp3 +0 -0
- data/spec/fixtures/world.png +0 -0
- data/spec/hydra/works/models/collection_spec.rb +499 -16
- data/spec/hydra/works/models/concerns/block_child_objects_spec.rb +19 -0
- data/spec/hydra/works/models/concerns/{file → generic_file}/contained_files_spec.rb +20 -17
- data/spec/hydra/works/models/concerns/generic_file/mime_types_spec.rb +76 -0
- data/spec/hydra/works/models/concerns/generic_file/versioned_content_spec.rb +32 -0
- data/spec/hydra/works/models/concerns/generic_file/virus_check_spec.rb +50 -0
- data/spec/hydra/works/models/concerns/generic_file_behavior_spec.rb +1 -1
- data/spec/hydra/works/models/generic_file_spec.rb +201 -14
- data/spec/hydra/works/models/generic_work_spec.rb +530 -14
- data/spec/hydra/works/services/generic_file/add_file_to_generic_file_spec.rb +110 -0
- data/spec/hydra/works/services/generic_file/upload_file_spec.rb +45 -28
- data/spec/hydra/works/services/persist_derivatives_spec.rb +93 -0
- data/spec/hydra/works_spec.rb +35 -35
- data/spec/spec_helper.rb +6 -0
- metadata +56 -95
- data/lib/hydra/works/models/concerns/aggregates_collections.rb +0 -16
- data/lib/hydra/works/models/concerns/aggregates_generic_files.rb +0 -20
- data/lib/hydra/works/models/concerns/aggregates_generic_works.rb +0 -20
- data/lib/hydra/works/processor.rb +0 -9
- data/lib/hydra/works/services/collection/add_collection.rb +0 -19
- data/lib/hydra/works/services/collection/add_generic_work.rb +0 -19
- data/lib/hydra/works/services/collection/add_related_object.rb +0 -19
- data/lib/hydra/works/services/collection/get_collections.rb +0 -17
- data/lib/hydra/works/services/collection/get_generic_works.rb +0 -17
- data/lib/hydra/works/services/collection/get_related_objects.rb +0 -17
- data/lib/hydra/works/services/collection/remove_collection.rb +0 -19
- data/lib/hydra/works/services/collection/remove_generic_work.rb +0 -20
- data/lib/hydra/works/services/collection/remove_related_object.rb +0 -19
- data/lib/hydra/works/services/generic_file/add_file.rb +0 -55
- data/lib/hydra/works/services/generic_file/add_generic_file.rb +0 -19
- data/lib/hydra/works/services/generic_file/add_original_file.rb +0 -11
- data/lib/hydra/works/services/generic_file/add_related_object.rb +0 -19
- data/lib/hydra/works/services/generic_file/add_versioned_original_file.rb +0 -10
- data/lib/hydra/works/services/generic_file/get_generic_files.rb +0 -17
- data/lib/hydra/works/services/generic_file/get_related_objects.rb +0 -17
- data/lib/hydra/works/services/generic_file/remove_generic_file.rb +0 -20
- data/lib/hydra/works/services/generic_file/remove_related_object.rb +0 -19
- data/lib/hydra/works/services/generic_work/add_generic_file.rb +0 -19
- data/lib/hydra/works/services/generic_work/add_generic_work.rb +0 -19
- data/lib/hydra/works/services/generic_work/add_related_object.rb +0 -19
- data/lib/hydra/works/services/generic_work/get_generic_files.rb +0 -17
- data/lib/hydra/works/services/generic_work/get_generic_works.rb +0 -17
- data/lib/hydra/works/services/generic_work/get_related_objects.rb +0 -17
- data/lib/hydra/works/services/generic_work/move_generic_file.rb +0 -19
- data/lib/hydra/works/services/generic_work/remove_generic_file.rb +0 -20
- data/lib/hydra/works/services/generic_work/remove_generic_work.rb +0 -20
- data/lib/hydra/works/services/generic_work/remove_related_object.rb +0 -19
- data/spec/hydra/works/services/collection/add_collection_spec.rb +0 -166
- data/spec/hydra/works/services/collection/add_generic_work_spec.rb +0 -155
- data/spec/hydra/works/services/collection/add_related_object_spec.rb +0 -149
- data/spec/hydra/works/services/collection/get_collections_spec.rb +0 -35
- data/spec/hydra/works/services/collection/get_generic_works_spec.rb +0 -35
- data/spec/hydra/works/services/collection/get_related_objects_spec.rb +0 -49
- data/spec/hydra/works/services/collection/remove_collection_spec.rb +0 -133
- data/spec/hydra/works/services/collection/remove_generic_work_spec.rb +0 -133
- data/spec/hydra/works/services/collection/remove_related_object_spec.rb +0 -128
- data/spec/hydra/works/services/generic_file/add_file_spec.rb +0 -28
- data/spec/hydra/works/services/generic_file/add_generic_file_spec.rb +0 -174
- data/spec/hydra/works/services/generic_file/add_related_object_spec.rb +0 -150
- data/spec/hydra/works/services/generic_file/get_generic_files_spec.rb +0 -19
- data/spec/hydra/works/services/generic_file/get_related_objects_spec.rb +0 -45
- data/spec/hydra/works/services/generic_file/remove_generic_file_spec.rb +0 -124
- data/spec/hydra/works/services/generic_file/remove_related_object_spec.rb +0 -123
- data/spec/hydra/works/services/generic_work/add_generic_file_spec.rb +0 -156
- data/spec/hydra/works/services/generic_work/add_generic_work_spec.rb +0 -157
- data/spec/hydra/works/services/generic_work/add_related_object_spec.rb +0 -148
- data/spec/hydra/works/services/generic_work/get_generic_files_spec.rb +0 -35
- data/spec/hydra/works/services/generic_work/get_generic_works_spec.rb +0 -35
- data/spec/hydra/works/services/generic_work/get_related_objects_spec.rb +0 -46
- data/spec/hydra/works/services/generic_work/move_generic_file_spec.rb +0 -21
- data/spec/hydra/works/services/generic_work/remove_generic_file_spec.rb +0 -132
- data/spec/hydra/works/services/generic_work/remove_generic_work_spec.rb +0 -133
- data/spec/hydra/works/services/generic_work/remove_related_object_spec.rb +0 -128
@@ -18,13 +18,42 @@ module Hydra::Works
|
|
18
18
|
|
19
19
|
included do
|
20
20
|
type [RDFVocabularies::PCDMTerms.Object,WorksVocabularies::WorksTerms.GenericWork]
|
21
|
-
include Hydra::Works::
|
22
|
-
|
21
|
+
include Hydra::Works::BlockChildObjects
|
22
|
+
|
23
|
+
filters_association :members, as: :child_generic_works, condition: :works_generic_work?
|
24
|
+
filters_association :members, as: :generic_files, condition: :works_generic_file?
|
23
25
|
end
|
24
26
|
|
25
27
|
def contains= files
|
26
28
|
raise NoMethodError, "works can not directly contain files. You must add a GenericFile to the work's members and add files to that GenericFile."
|
27
29
|
end
|
28
30
|
|
31
|
+
# @return [Boolean] whether this instance is a Hydra::Works Collection.
|
32
|
+
def works_collection?
|
33
|
+
false
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [Boolean] whether this instance is a Hydra::Works Generic Work.
|
37
|
+
def works_generic_work?
|
38
|
+
true
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [Boolean] whether this instance is a Hydra::Works Generic File.
|
42
|
+
def works_generic_file?
|
43
|
+
false
|
44
|
+
end
|
45
|
+
|
46
|
+
def parents
|
47
|
+
aggregated_by
|
48
|
+
end
|
49
|
+
|
50
|
+
def parent_generic_works
|
51
|
+
aggregated_by.select { |parent| parent.class.included_modules.include?(Hydra::Works::GenericWorkBehavior) }
|
52
|
+
end
|
53
|
+
|
54
|
+
def parent_collections
|
55
|
+
aggregated_by.select { |parent| parent.class.included_modules.include?(Hydra::Works::CollectionBehavior) }
|
56
|
+
end
|
57
|
+
|
29
58
|
end
|
30
|
-
end
|
59
|
+
end
|
@@ -7,6 +7,9 @@ module Hydra::Works
|
|
7
7
|
autoload :Derivatives, 'hydra/works/models/concerns/generic_file/derivatives'
|
8
8
|
autoload :MimeTypes, 'hydra/works/models/concerns/generic_file/mime_types'
|
9
9
|
autoload :ContainedFiles, 'hydra/works/models/concerns/generic_file/contained_files'
|
10
|
+
autoload :VersionedContent, 'hydra/works/models/concerns/generic_file/versioned_content'
|
11
|
+
autoload :VirusCheck, 'hydra/works/models/concerns/generic_file/virus_check'
|
12
|
+
|
10
13
|
|
11
14
|
# Base class for creating objects that behave like Hydra::Works::GenericFiles
|
12
15
|
class Base < ActiveFedora::Base
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module Hydra::Works
|
2
|
+
class AddFileToGenericFile
|
3
|
+
|
4
|
+
# Adds a file to the generic_file
|
5
|
+
# @param [Hydra::PCDM::GenericFile::Base] generic_file the file will be added to
|
6
|
+
# @param [IO,File,Rack::Multipart::UploadedFile, #read] object that will be the contents. If file responds to :mime_type, :content_type, :original_name, or :original_filename, those will be called to provide metadata.
|
7
|
+
# @param [RDF::URI or String] type URI for the RDF.type that identifies the file's role within the generic_file
|
8
|
+
# @param [Boolean] update_existing whether to update an existing file if there is one. When set to true, performs a create_or_update. When set to false, always creates a new file within generic_file.files.
|
9
|
+
# @param [Boolean] versioning whether to create new version entries (only applicable if +type+ corresponds to a versionable file)
|
10
|
+
|
11
|
+
def self.call(generic_file, file, type, update_existing: true, versioning: true)
|
12
|
+
raise ArgumentError, "supplied object must be a generic file" unless generic_file.works_generic_file?
|
13
|
+
raise ArgumentError, "supplied file must respond to read" unless file.respond_to? :read
|
14
|
+
|
15
|
+
# TODO required as a workaround for https://github.com/projecthydra/active_fedora/pull/858
|
16
|
+
generic_file.save unless generic_file.persisted?
|
17
|
+
|
18
|
+
updater_class = versioning ? VersioningUpdater : Updater
|
19
|
+
updater = updater_class.new(generic_file, type, update_existing)
|
20
|
+
status = updater.update(file)
|
21
|
+
status ? generic_file : false
|
22
|
+
end
|
23
|
+
|
24
|
+
class Updater
|
25
|
+
attr_reader :generic_file, :current_file
|
26
|
+
|
27
|
+
def initialize(generic_file, type, update_existing)
|
28
|
+
@generic_file = generic_file
|
29
|
+
@current_file = find_or_create_file(type, update_existing)
|
30
|
+
end
|
31
|
+
|
32
|
+
# @param [#read] file object that will be interrogated using the methods: :path, :original_name, :original_filename, :mime_type, :content_type
|
33
|
+
# None of the attribute description methods are required.
|
34
|
+
def update(file)
|
35
|
+
attach_attributes(file)
|
36
|
+
persist
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def persist
|
42
|
+
if current_file.new_record?
|
43
|
+
# persist current_file and its membership in generic_file.files container
|
44
|
+
generic_file.save
|
45
|
+
else
|
46
|
+
# we updated the content of an existing file, so we need to save the file explicitly
|
47
|
+
current_file.save
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def attach_attributes(file)
|
52
|
+
current_file.content = file
|
53
|
+
current_file.original_name = determine_original_name(file)
|
54
|
+
current_file.mime_type = determine_mime_type(file)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Return mime_type based on methods available to file
|
58
|
+
# @param object for mimetype to be determined. Attempts to use methods: :mime_type, :content_type, and :path.
|
59
|
+
def determine_mime_type(file)
|
60
|
+
if file.respond_to? :mime_type
|
61
|
+
return file.mime_type
|
62
|
+
elsif file.respond_to? :content_type
|
63
|
+
return file.content_type
|
64
|
+
elsif file.respond_to? :path
|
65
|
+
return Hydra::PCDM::GetMimeTypeForFile.call(file.path)
|
66
|
+
else
|
67
|
+
return "application/octet-stream"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Return original_name based on methods available to file
|
72
|
+
# @param object for original name to be determined. Attempts to use methods: :original_name, :original_filename, and :path.
|
73
|
+
def determine_original_name(file)
|
74
|
+
if file.respond_to? :original_name
|
75
|
+
return file.original_name
|
76
|
+
elsif file.respond_to? :original_filename
|
77
|
+
return file.original_filename
|
78
|
+
elsif file.respond_to? :path
|
79
|
+
return ::File.basename(file.path)
|
80
|
+
else
|
81
|
+
return ""
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# @param [Symbol, RDF::URI] the type of association or filter to use
|
86
|
+
# @param [true, false] update_existing when true, try to retrieve existing element before building one
|
87
|
+
def find_or_create_file(type, update_existing)
|
88
|
+
if type.instance_of? Symbol
|
89
|
+
association = generic_file.association(type)
|
90
|
+
raise ArgumentError, "you're attempting to add a file to a generic_file using '#{type}' association but the generic_file does not have an association called '#{type}''" unless association
|
91
|
+
|
92
|
+
current_file = association.reader if update_existing
|
93
|
+
current_file ||= association.build
|
94
|
+
else
|
95
|
+
current_file = generic_file.filter_files_by_type(type_to_uri(type)).first if update_existing
|
96
|
+
unless current_file
|
97
|
+
generic_file.files.build
|
98
|
+
current_file = generic_file.files.last
|
99
|
+
Hydra::PCDM::AddTypeToFile.call(current_file, type_to_uri(type))
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns appropriate URI for the requested type
|
105
|
+
# * Converts supported symbols to corresponding URIs
|
106
|
+
# * Converts URI strings to RDF::URI
|
107
|
+
# * Returns RDF::URI objects as-is
|
108
|
+
def type_to_uri(type)
|
109
|
+
case type
|
110
|
+
when ::RDF::URI
|
111
|
+
type
|
112
|
+
when String
|
113
|
+
::RDF::URI(type)
|
114
|
+
else
|
115
|
+
raise ArgumentError, "Invalid file type. You must submit a URI or a symbol."
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class VersioningUpdater < Updater
|
121
|
+
def update(*)
|
122
|
+
super && current_file.create_version
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
@@ -7,8 +7,7 @@ module Hydra::Works
|
|
7
7
|
|
8
8
|
# Always replace the thumbnail with whatever is from the original file
|
9
9
|
if object.thumbnail.nil?
|
10
|
-
object.
|
11
|
-
AddTypeToFile.call(object.files.last, ::RDF::URI("http://pcdm.org/ThumbnailImage"))
|
10
|
+
object.build_thumbnail
|
12
11
|
end
|
13
12
|
|
14
13
|
object.create_derivatives
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'hydra/derivatives'
|
2
|
+
|
3
|
+
module Hydra::Works
|
4
|
+
class PersistDerivative < Hydra::Derivatives::PersistOutputFileService
|
5
|
+
|
6
|
+
##
|
7
|
+
# Persists a derivative to a GenericFile
|
8
|
+
# This Service conforms to the signature of `Hydra::Derivatives::PersistOutputFileService`.
|
9
|
+
# The purpose of this Service is for use as an alternative to the default Hydra::Derivatives::PersistOutputFileService. It's necessary because the default behavior in Hydra::Derivatives assumes that you're using LDP Basic Containment. Hydra::Works::GenericFiles use IndirectContainment. This Service handles that case.
|
10
|
+
# This service will always update existing and does not do versioning of persisted files.
|
11
|
+
#
|
12
|
+
# @param [Hydra::Works::GenericFile::Base] object the file will be added to
|
13
|
+
# @param [#read or String] file the derivative filestream optionally responds to :mime_type
|
14
|
+
# @param [String] extract file type symbol (e.g. :thumbnail) from Hydra::Derivatives created destination_name
|
15
|
+
|
16
|
+
def self.call(object, file, destination_name)
|
17
|
+
type = destination_name.gsub(/^original_file_/, '').to_sym
|
18
|
+
Hydra::Works::AddFileToGenericFile.call(object, file, type, update_existing: true, versioning: false)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -1,31 +1,23 @@
|
|
1
1
|
module Hydra::Works
|
2
2
|
class UploadFileToGenericFile
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
Hydra::Works::AddOriginalFile.call(object, path)
|
11
|
-
else
|
12
|
-
if replace
|
13
|
-
Hydra::Works::AddOriginalFile.call(object, path, replace)
|
14
|
-
else
|
15
|
-
Hydra::Works::AddVersionedOriginalFile.call(object, path)
|
16
|
-
end
|
17
|
-
end
|
4
|
+
# Sets a file as the primary file (original_file) of the generic_file
|
5
|
+
# @param [Hydra::PCDM::GenericFile::Base] generic_file the file will be added to
|
6
|
+
# @param [IO,File,Rack::Multipart::UploadedFile, #read] object that will be the contents. If file responds to :mime_type or :original_name, those will be called to provide technical metadata.
|
7
|
+
# @param [Array] additional_services (ie Generating Thumbnails) to call with generic_file after adding the file as its original_file
|
8
|
+
# @param [Boolean] update_existing whether to update an existing file if there is one. When set to true, performs a create_or_update. When set to false, always creates a new file within generic_file.files.
|
9
|
+
# @param [Boolean] versioning whether to create new version entries (only applicable if +type+ corresponds to a versionable file)
|
18
10
|
|
19
|
-
|
20
|
-
|
11
|
+
def self.call(generic_file, file, additional_services: [], update_existing: true, versioning: true)
|
12
|
+
Hydra::Works::AddFileToGenericFile.call(generic_file, file, :original_file, update_existing: update_existing, versioning: versioning)
|
21
13
|
|
22
14
|
# Call any additional services
|
23
15
|
additional_services.each do |service|
|
24
|
-
service.call(
|
16
|
+
service.call(generic_file)
|
25
17
|
end
|
26
18
|
|
27
|
-
|
28
|
-
|
19
|
+
generic_file.save
|
20
|
+
generic_file
|
29
21
|
end
|
30
22
|
|
31
23
|
end
|
data/lib/hydra/works/version.rb
CHANGED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -2,40 +2,523 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Hydra::Works::Collection do
|
4
4
|
|
5
|
-
|
6
|
-
let(:collection2) { Hydra::Works::Collection.create }
|
7
|
-
let(:collection3) { Hydra::Works::Collection.create }
|
5
|
+
subject { Hydra::Works::Collection.new }
|
8
6
|
|
9
|
-
let(:
|
10
|
-
let(:
|
7
|
+
let(:collection1) { Hydra::Works::Collection.new }
|
8
|
+
let(:collection2) { Hydra::Works::Collection.new }
|
9
|
+
let(:collection3) { Hydra::Works::Collection.new }
|
10
|
+
|
11
|
+
let(:generic_work1) { Hydra::Works::GenericWork::Base.new }
|
12
|
+
let(:generic_work2) { Hydra::Works::GenericWork::Base.new }
|
13
|
+
let(:generic_work3) { Hydra::Works::GenericWork::Base.new }
|
14
|
+
|
15
|
+
describe '#child_collections' do
|
16
|
+
it 'should return empty array when only generic_works are aggregated' do
|
17
|
+
subject.child_generic_works << generic_work1
|
18
|
+
subject.child_generic_works << generic_work2
|
19
|
+
expect(subject.child_collections ).to eq []
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'with other collections & generic_works' do
|
23
|
+
before do
|
24
|
+
subject.child_collections << collection1
|
25
|
+
subject.child_collections << collection2
|
26
|
+
subject.child_generic_works << generic_work1
|
27
|
+
subject.child_generic_works << generic_work2
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should only return collections' do
|
31
|
+
expect(subject.child_collections ).to eq [collection1,collection2]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#child_collections <<' do
|
37
|
+
context 'with acceptable collections' do
|
38
|
+
context 'with collections and generic_works' do
|
39
|
+
before do
|
40
|
+
subject.child_collections << collection1
|
41
|
+
subject.child_collections << collection2
|
42
|
+
subject.child_generic_works << generic_work1
|
43
|
+
subject.child_generic_works << generic_work2
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should add an generic_work to collection with collections and generic_works' do
|
47
|
+
subject.child_collections << collection3
|
48
|
+
expect( subject.child_collections ).to eq [collection1,collection2,collection3]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'aggregates collections that implement Hydra::Works' do
|
53
|
+
before do
|
54
|
+
class Kollection < ActiveFedora::Base
|
55
|
+
include Hydra::Works::CollectionBehavior
|
56
|
+
end
|
57
|
+
end
|
58
|
+
after { Object.send(:remove_const, :Kollection) }
|
59
|
+
let(:kollection1) { Kollection.new }
|
60
|
+
|
61
|
+
it 'should accept implementing collection as a child' do
|
62
|
+
subject.child_collections << kollection1
|
63
|
+
expect( subject.child_collections ).to eq [kollection1]
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should accept implementing collection as a parent' do
|
67
|
+
subject.child_collections << collection1
|
68
|
+
expect( subject.child_collections ).to eq [collection1]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe 'aggregates collections that extend Hydra::Works' do
|
73
|
+
before do
|
74
|
+
class Cullection < Hydra::Works::Collection
|
75
|
+
end
|
76
|
+
end
|
77
|
+
after { Object.send(:remove_const, :Cullection) }
|
78
|
+
let(:cullection1) { Cullection.new }
|
79
|
+
|
80
|
+
it 'should accept extending collection as a child' do
|
81
|
+
subject.child_collections << cullection1
|
82
|
+
expect( subject.child_collections ).to eq [cullection1]
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should accept extending collection as a parent' do
|
86
|
+
subject.child_collections << collection1
|
87
|
+
expect( subject.child_collections ).to eq [collection1]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'with unacceptable inputs' do
|
93
|
+
before(:all) do
|
94
|
+
@works_collection101 = Hydra::Works::Collection.new
|
95
|
+
@generic_work101 = Hydra::Works::GenericWork::Base.new
|
96
|
+
@generic_file101 = Hydra::Works::GenericFile::Base.new
|
97
|
+
@pcdm_collection101 = Hydra::PCDM::Collection.new
|
98
|
+
@pcdm_object101 = Hydra::PCDM::Object.new
|
99
|
+
@pcdm_file101 = Hydra::PCDM::File.new
|
100
|
+
@non_PCDM_object = "I'm not a PCDM object"
|
101
|
+
@af_base_object = ActiveFedora::Base.new
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'that are unacceptable child collections' do
|
105
|
+
|
106
|
+
let(:error_type1) { ArgumentError }
|
107
|
+
let(:error_message1) { /Hydra::Works::Generic(Work|File)::Base with ID: was expected to works_collection\?, but it was false/ }
|
108
|
+
let(:error_type2) { NoMethodError }
|
109
|
+
let(:error_message2) { /undefined method `works_collection\?' for .*/ }
|
110
|
+
|
111
|
+
it 'should NOT aggregate Hydra::Works::GenericWork in collections aggregation' do
|
112
|
+
expect{ subject.child_collections << @generic_work101 }.to raise_error(error_type1,error_message1)
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should NOT aggregate Hydra::Works::GenericFile in collections aggregation' do
|
116
|
+
expect{ subject.child_collections << @generic_file101 }.to raise_error(error_type1,error_message1)
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'should NOT aggregate Hydra::PCDM::Collections in collections aggregation' do
|
120
|
+
expect{ subject.child_collections << @pcdm_collection101 }.to raise_error(error_type2,error_message2)
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'should NOT aggregate Hydra::PCDM::Objects in collections aggregation' do
|
124
|
+
expect{ subject.child_collections << @pcdm_object101 }.to raise_error(error_type2,error_message2)
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should NOT aggregate Hydra::PCDM::Files in collections aggregation' do
|
128
|
+
expect{ subject.child_collections << @pcdm_file101 }.to raise_error(error_type2,error_message2)
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'should NOT aggregate non-PCDM objects in collections aggregation' do
|
132
|
+
expect{ subject.child_collections << @non_PCDM_object }.to raise_error(error_type2,error_message2)
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'should NOT aggregate AF::Base objects in collections aggregation' do
|
136
|
+
expect{ subject.child_collections << @af_base_object }.to raise_error(error_type2,error_message2)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
describe 'child_collections.delete' do
|
143
|
+
context 'when multiple collections' do
|
144
|
+
before do
|
145
|
+
subject.child_collections << collection1
|
146
|
+
subject.child_collections << collection2
|
147
|
+
subject.child_generic_works << generic_work2
|
148
|
+
subject.child_collections << collection3
|
149
|
+
subject.child_generic_works << generic_work1
|
150
|
+
expect( subject.child_collections ).to eq [collection1,collection2,collection3]
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'should remove first collection' do
|
154
|
+
expect( subject.child_collections.delete collection1 ).to eq [collection1]
|
155
|
+
expect( subject.child_collections ).to eq [collection2,collection3]
|
156
|
+
expect( subject.child_generic_works ).to eq [generic_work2,generic_work1]
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'should remove last collection' do
|
160
|
+
expect( subject.child_collections.delete collection3 ).to eq [collection3]
|
161
|
+
expect( subject.child_collections ).to eq [collection1,collection2]
|
162
|
+
expect( subject.child_generic_works). to eq [generic_work2,generic_work1]
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'should remove middle collection' do
|
166
|
+
expect( subject.child_collections.delete collection2 ).to eq [collection2]
|
167
|
+
expect( subject.child_collections ).to eq [collection1,collection3]
|
168
|
+
expect( subject.child_generic_works). to eq [generic_work2,generic_work1]
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe '#child_generic_works' do
|
174
|
+
it 'should return empty array when only collections are aggregated' do
|
175
|
+
subject.child_collections << collection1
|
176
|
+
subject.child_collections << collection2
|
177
|
+
expect(subject.child_generic_works). to eq []
|
178
|
+
end
|
179
|
+
|
180
|
+
context 'with collections and generic works' do
|
181
|
+
before do
|
182
|
+
subject.child_collections << collection1
|
183
|
+
subject.child_collections << collection2
|
184
|
+
subject.child_generic_works << generic_work1
|
185
|
+
subject.child_generic_works << generic_work2
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'should only return generic works' do
|
189
|
+
expect(subject.child_generic_works). to eq [generic_work1,generic_work2]
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
describe '#child_generic_works <<' do
|
195
|
+
|
196
|
+
context 'with acceptable generic_works' do
|
197
|
+
context 'with collections and generic_works' do
|
198
|
+
before do
|
199
|
+
subject.child_collections << collection1
|
200
|
+
subject.child_collections << collection2
|
201
|
+
subject.child_generic_works << generic_work1
|
202
|
+
subject.child_generic_works << generic_work2
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'should add generic_work to collection with collections and generic_works' do
|
206
|
+
subject.child_generic_works << generic_work3
|
207
|
+
expect( subject.child_generic_works ).to eq [generic_work1,generic_work2,generic_work3]
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
describe 'aggregates generic_works that implement Hydra::Works' do
|
212
|
+
before do
|
213
|
+
class DummyIncWork < ActiveFedora::Base
|
214
|
+
include Hydra::Works::GenericWorkBehavior
|
215
|
+
end
|
216
|
+
end
|
217
|
+
after { Object.send(:remove_const, :DummyIncWork) }
|
218
|
+
let(:iwork1) { DummyIncWork.new }
|
219
|
+
|
220
|
+
it 'should accept implementing generic_work as a child' do
|
221
|
+
subject.child_generic_works << iwork1
|
222
|
+
expect( subject.child_generic_works ).to eq [iwork1]
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
describe 'aggregates generic_works that extend Hydra::Works' do
|
227
|
+
before do
|
228
|
+
class DummyExtWork < Hydra::Works::GenericWork::Base
|
229
|
+
end
|
230
|
+
end
|
231
|
+
after { Object.send(:remove_const, :DummyExtWork) }
|
232
|
+
let(:ework1) { DummyExtWork.new }
|
233
|
+
|
234
|
+
it 'should accept extending generic_work as a child' do
|
235
|
+
subject.child_generic_works << ework1
|
236
|
+
expect( subject.child_generic_works ).to eq [ework1]
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
context 'with unacceptable inputs' do
|
242
|
+
before(:all) do
|
243
|
+
@works_collection101 = Hydra::Works::Collection.new
|
244
|
+
@works_collection102 = Hydra::Works::Collection.new
|
245
|
+
@generic_file101 = Hydra::Works::GenericFile::Base.new
|
246
|
+
@pcdm_collection101 = Hydra::PCDM::Collection.new
|
247
|
+
@pcdm_object101 = Hydra::PCDM::Object.new
|
248
|
+
@pcdm_file101 = Hydra::PCDM::File.new
|
249
|
+
@non_PCDM_object = "I'm not a PCDM object"
|
250
|
+
@af_base_object = ActiveFedora::Base.new
|
251
|
+
end
|
252
|
+
|
253
|
+
context 'that are unacceptable child generic works' do
|
254
|
+
|
255
|
+
let(:error_type1) { ArgumentError }
|
256
|
+
let(:error_message1) { /Hydra::Works::(GenericFile::Base|Collection) with ID: was expected to works_generic_work\?, but it was false/ }
|
257
|
+
let(:error_type2) { NoMethodError }
|
258
|
+
let(:error_message2) { /undefined method `works_generic_work\?' for .*/ }
|
259
|
+
|
260
|
+
it 'should NOT aggregate Hydra::Works::Collection in generic works aggregation' do
|
261
|
+
expect{ subject.child_generic_works << @works_collection101 }.to raise_error(error_type1,error_message1)
|
262
|
+
end
|
263
|
+
|
264
|
+
it 'should NOT aggregate Hydra::Works::GenericFile in generic works aggregation' do
|
265
|
+
expect{ subject.child_generic_works << @generic_file101 }.to raise_error(error_type1,error_message1)
|
266
|
+
end
|
267
|
+
|
268
|
+
it 'should NOT aggregate Hydra::PCDM::Collections in generic works aggregation' do
|
269
|
+
expect{ subject.child_generic_works << @pcdm_collection101 }.to raise_error(error_type2,error_message2)
|
270
|
+
end
|
271
|
+
|
272
|
+
it 'should NOT aggregate Hydra::PCDM::Objects in generic works aggregation' do
|
273
|
+
expect{ subject.child_generic_works << @pcdm_object101 }.to raise_error(error_type2,error_message2)
|
274
|
+
end
|
275
|
+
|
276
|
+
it 'should NOT aggregate Hydra::PCDM::Files in generic works aggregation' do
|
277
|
+
expect{ subject.child_generic_works << @pcdm_file101 }.to raise_error(error_type2,error_message2)
|
278
|
+
end
|
279
|
+
|
280
|
+
it 'should NOT aggregate non-PCDM objects in generic works aggregation' do
|
281
|
+
expect{ subject.child_generic_works << @non_PCDM_object }.to raise_error(error_type2,error_message2)
|
282
|
+
end
|
283
|
+
|
284
|
+
it 'should NOT aggregate AF::Base objects in generic works aggregation' do
|
285
|
+
expect{ subject.child_generic_works << @af_base_object }.to raise_error(error_type2,error_message2)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
describe '#child_generic_works.delete' do
|
292
|
+
context 'when multiple generic works' do
|
293
|
+
before do
|
294
|
+
subject.child_generic_works << generic_work1
|
295
|
+
subject.child_generic_works << generic_work2
|
296
|
+
subject.child_collections << collection2
|
297
|
+
subject.child_generic_works << generic_work3
|
298
|
+
subject.child_collections << collection1
|
299
|
+
expect( subject.child_generic_works). to eq [generic_work1,generic_work2,generic_work3]
|
300
|
+
end
|
301
|
+
|
302
|
+
it 'should remove first generic work' do
|
303
|
+
expect( subject.child_generic_works.delete generic_work1 ).to eq [generic_work1]
|
304
|
+
expect( subject.child_generic_works). to eq [generic_work2,generic_work3]
|
305
|
+
expect( subject.child_collections ).to eq [collection2,collection1]
|
306
|
+
end
|
307
|
+
|
308
|
+
it 'should remove last generic work' do
|
309
|
+
expect( subject.child_generic_works.delete generic_work3 ).to eq [generic_work3]
|
310
|
+
expect( subject.child_generic_works). to eq [generic_work1,generic_work2]
|
311
|
+
expect( subject.child_collections ).to eq [collection2,collection1]
|
312
|
+
end
|
313
|
+
|
314
|
+
it 'should remove middle generic work' do
|
315
|
+
expect( subject.child_generic_works.delete generic_work2 ).to eq [generic_work2]
|
316
|
+
expect( subject.child_generic_works). to eq [generic_work1,generic_work3]
|
317
|
+
expect( subject.child_collections ).to eq [collection2,collection1]
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
describe '#related_objects' do
|
323
|
+
let(:generic_file1) { Hydra::Works::GenericFile::Base.new }
|
324
|
+
let(:object1) { Hydra::PCDM::Object.new }
|
325
|
+
let(:object2) { Hydra::PCDM::Object.new }
|
326
|
+
|
327
|
+
context 'with collections and generic works' do
|
328
|
+
before do
|
329
|
+
subject.child_collections << collection1
|
330
|
+
subject.child_collections << collection2
|
331
|
+
subject.child_generic_works << generic_work1
|
332
|
+
end
|
333
|
+
|
334
|
+
it 'should return empty array when only collections and generic works are aggregated' do
|
335
|
+
expect(subject.related_objects ).to eq []
|
336
|
+
end
|
337
|
+
|
338
|
+
it 'should only return related objects' do
|
339
|
+
subject.related_objects << object2
|
340
|
+
expect(subject.related_objects ).to eq [object2]
|
341
|
+
end
|
342
|
+
|
343
|
+
it 'should return related objects of various types' do
|
344
|
+
subject.related_objects << generic_work2
|
345
|
+
subject.related_objects << generic_file1
|
346
|
+
subject.related_objects << object1
|
347
|
+
subject.save
|
348
|
+
subject.reload
|
349
|
+
expect( subject.related_objects.include? object1 ).to be true
|
350
|
+
expect( subject.related_objects.include? generic_work2 ).to be true
|
351
|
+
expect( subject.related_objects.include? generic_file1 ).to be true
|
352
|
+
expect( subject.related_objects.size ).to eq 3
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
describe '#related_objects <<' do
|
358
|
+
|
359
|
+
context 'with acceptable related objects' do
|
360
|
+
let(:object1) { Hydra::PCDM::Object.new }
|
361
|
+
let(:object2) { Hydra::PCDM::Object.new }
|
362
|
+
let(:generic_file1) { Hydra::Works::GenericFile::Base.new }
|
363
|
+
|
364
|
+
it 'should add various types of related objects to collection' do
|
365
|
+
subject.related_objects << generic_work1
|
366
|
+
subject.related_objects << generic_file1
|
367
|
+
subject.related_objects << object1
|
368
|
+
subject.save
|
369
|
+
subject.reload
|
370
|
+
expect( subject.related_objects.include? generic_work1 ).to be true
|
371
|
+
expect( subject.related_objects.include? generic_file1 ).to be true
|
372
|
+
expect( subject.related_objects.include? object1 ).to be true
|
373
|
+
expect( subject.related_objects.size ).to eq 3
|
374
|
+
end
|
375
|
+
|
376
|
+
context 'with collections and generic_works' do
|
377
|
+
before do
|
378
|
+
subject.child_collections << collection1
|
379
|
+
subject.child_collections << collection2
|
380
|
+
subject.child_generic_works << generic_work1
|
381
|
+
subject.child_generic_works << generic_work2
|
382
|
+
subject.related_objects << object1
|
383
|
+
end
|
384
|
+
|
385
|
+
it 'should add a related object to collection with collections and generic_works' do
|
386
|
+
subject.related_objects << object2
|
387
|
+
subject.save
|
388
|
+
subject.reload
|
389
|
+
expect( subject.related_objects.include? object1 ).to be true
|
390
|
+
expect( subject.related_objects.include? object2 ).to be true
|
391
|
+
expect( subject.related_objects.size ).to eq 2
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
context 'with unacceptable child related objects' do
|
397
|
+
let(:pcdm_collection1) { Hydra::PCDM::Collection.new }
|
398
|
+
let(:pcdm_file1) { Hydra::PCDM::File.new }
|
399
|
+
let(:non_PCDM_object) { "I'm not a PCDM object" }
|
400
|
+
let(:af_base_object) { ActiveFedora::Base.new }
|
401
|
+
|
402
|
+
it 'should NOT aggregate Hydra::Works::Collection in related objects aggregation' do
|
403
|
+
expect{ subject.related_objects << collection1 }.to raise_error(ActiveFedora::AssociationTypeMismatch, /Hydra::Works::Collection:.*> is not a PCDM object./)
|
404
|
+
end
|
405
|
+
|
406
|
+
it 'should NOT aggregate Hydra::PCDM::Collections in related objects aggregation' do
|
407
|
+
expect{ subject.related_objects << pcdm_collection1 }.to raise_error(ActiveFedora::AssociationTypeMismatch, /Hydra::PCDM::Collection:.* is not a PCDM object./)
|
408
|
+
end
|
409
|
+
|
410
|
+
it 'should NOT aggregate Hydra::PCDM::Files in related objects aggregation' do
|
411
|
+
expect{ subject.related_objects << pcdm_file1 }.to raise_error(ActiveFedora::AssociationTypeMismatch, /ActiveFedora::Base.* expected, got Hydra::PCDM::File.*/)
|
412
|
+
end
|
413
|
+
|
414
|
+
it 'should NOT aggregate non-PCDM objects in related objects aggregation' do
|
415
|
+
expect{ subject.related_objects << non_PCDM_object }.to raise_error(ActiveFedora::AssociationTypeMismatch, /ActiveFedora::Base.* expected, got String.*/)
|
416
|
+
end
|
417
|
+
|
418
|
+
it 'should NOT aggregate AF::Base objects in related objects aggregation' do
|
419
|
+
expect{ subject.related_objects << af_base_object }.to raise_error(ActiveFedora::AssociationTypeMismatch, /ActiveFedora::Base.* is not a PCDM object./)
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
context 'with invalid behaviors' do
|
424
|
+
let(:object1) { Hydra::PCDM::Object.new }
|
425
|
+
let(:object2) { Hydra::PCDM::Object.new }
|
426
|
+
|
427
|
+
it 'should NOT allow related objects to repeat' do
|
428
|
+
skip 'skipping this test because issue pcdm#92 needs to be addressed' do
|
429
|
+
subject.related_objects << object1
|
430
|
+
subject.related_objects << object2
|
431
|
+
subject.related_objects << object1
|
432
|
+
related_objects = subject.related_objects
|
433
|
+
expect( related_objects.include? object1 ).to be true
|
434
|
+
expect( related_objects.include? object2 ).to be true
|
435
|
+
expect( related_objects.size ).to eq 2
|
436
|
+
end
|
437
|
+
end
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
describe '#related_objects.delete' do
|
442
|
+
let(:related_object1) { Hydra::PCDM::Object.new }
|
443
|
+
let(:related_work2) { Hydra::Works::GenericWork::Base.new }
|
444
|
+
let(:related_file3) { Hydra::Works::GenericFile::Base.new }
|
445
|
+
let(:related_object4) { Hydra::PCDM::Object.new }
|
446
|
+
let(:related_work5) { Hydra::Works::GenericWork::Base.new }
|
447
|
+
|
448
|
+
context 'when multiple related objects' do
|
449
|
+
before do
|
450
|
+
subject.related_objects << related_object1
|
451
|
+
subject.related_objects << related_work2
|
452
|
+
subject.child_collections << collection2
|
453
|
+
subject.child_generic_works << generic_work1
|
454
|
+
subject.related_objects << related_file3
|
455
|
+
subject.related_objects << related_object4
|
456
|
+
subject.child_collections << collection1
|
457
|
+
subject.related_objects << related_work5
|
458
|
+
expect( subject.related_objects ).to eq [related_object1,related_work2,related_file3,related_object4,related_work5]
|
459
|
+
end
|
460
|
+
|
461
|
+
it 'should remove first related object' do
|
462
|
+
expect( subject.related_objects.delete related_object1 ).to eq [related_object1]
|
463
|
+
expect( subject.related_objects ).to eq [related_work2,related_file3,related_object4,related_work5]
|
464
|
+
expect( subject.child_collections ).to eq [collection2,collection1]
|
465
|
+
expect( subject.child_generic_works). to eq [generic_work1]
|
466
|
+
end
|
467
|
+
|
468
|
+
it 'should remove last related object' do
|
469
|
+
expect( subject.related_objects.delete related_work5 ).to eq [related_work5]
|
470
|
+
expect( subject.related_objects ).to eq [related_object1,related_work2,related_file3,related_object4]
|
471
|
+
expect( subject.child_collections ).to eq [collection2,collection1]
|
472
|
+
expect( subject.child_generic_works). to eq [generic_work1]
|
473
|
+
end
|
474
|
+
|
475
|
+
it 'should remove middle related object' do
|
476
|
+
expect( subject.related_objects.delete related_file3 ).to eq [related_file3]
|
477
|
+
expect( subject.related_objects ).to eq [related_object1,related_work2,related_object4,related_work5]
|
478
|
+
expect( subject.child_collections ).to eq [collection2,collection1]
|
479
|
+
expect( subject.child_generic_works). to eq [generic_work1]
|
480
|
+
end
|
481
|
+
end
|
482
|
+
end
|
11
483
|
|
12
484
|
describe '#collections=' do
|
13
485
|
it 'should aggregate collections' do
|
14
|
-
collection1.
|
15
|
-
collection1.
|
16
|
-
expect(collection1.collections).to eq [collection2, collection3]
|
486
|
+
collection1.child_collections = [collection2, collection3]
|
487
|
+
expect(collection1.child_collections).to eq [collection2, collection3]
|
17
488
|
end
|
18
489
|
end
|
19
490
|
|
20
|
-
describe '#
|
491
|
+
describe '#child_generic_works=' do
|
21
492
|
it 'should aggregate generic_works' do
|
22
|
-
collection1.
|
23
|
-
collection1.
|
24
|
-
expect(collection1.generic_works).to eq [generic_work1,generic_work2]
|
493
|
+
collection1.child_generic_works = [generic_work1,generic_work2]
|
494
|
+
expect(collection1.child_generic_works).to eq [generic_work1,generic_work2]
|
25
495
|
end
|
26
496
|
end
|
27
497
|
|
28
498
|
describe 'Related objects' do
|
29
|
-
let(:object) { Hydra::PCDM::Object.
|
30
|
-
let(:collection) { Hydra::Works::Collection.
|
499
|
+
let(:object) { Hydra::PCDM::Object.new }
|
500
|
+
let(:collection) { Hydra::Works::Collection.new }
|
31
501
|
|
32
502
|
before do
|
33
503
|
collection.related_objects = [object]
|
34
|
-
collection.save
|
35
504
|
end
|
36
505
|
|
37
506
|
it 'persists' do
|
38
|
-
expect(collection.
|
507
|
+
expect(collection.related_objects).to eq [object]
|
508
|
+
end
|
509
|
+
end
|
510
|
+
|
511
|
+
describe "should have parent collection accessors" do
|
512
|
+
before do
|
513
|
+
collection1.child_collections << collection2
|
514
|
+
collection1.save
|
515
|
+
end
|
516
|
+
|
517
|
+
it 'should have parents' do
|
518
|
+
expect(collection2.parents).to eq [collection1]
|
519
|
+
end
|
520
|
+
it 'should have a parent collection' do
|
521
|
+
expect(collection2.parent_collections).to eq [collection1]
|
39
522
|
end
|
40
523
|
end
|
41
524
|
end
|