paperclip_jk 5.0.0.beta2

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 (190) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +21 -0
  3. data/.hound.yml +1066 -0
  4. data/.rubocop.yml +1 -0
  5. data/.travis.yml +26 -0
  6. data/Appraisals +27 -0
  7. data/CONTRIBUTING.md +86 -0
  8. data/Gemfile +15 -0
  9. data/LICENSE +24 -0
  10. data/NEWS +424 -0
  11. data/README.md +999 -0
  12. data/RELEASING.md +17 -0
  13. data/Rakefile +44 -0
  14. data/UPGRADING +17 -0
  15. data/features/basic_integration.feature +81 -0
  16. data/features/migration.feature +70 -0
  17. data/features/rake_tasks.feature +62 -0
  18. data/features/step_definitions/attachment_steps.rb +110 -0
  19. data/features/step_definitions/html_steps.rb +15 -0
  20. data/features/step_definitions/rails_steps.rb +230 -0
  21. data/features/step_definitions/s3_steps.rb +14 -0
  22. data/features/step_definitions/web_steps.rb +107 -0
  23. data/features/support/env.rb +11 -0
  24. data/features/support/fakeweb.rb +13 -0
  25. data/features/support/file_helpers.rb +34 -0
  26. data/features/support/fixtures/boot_config.txt +15 -0
  27. data/features/support/fixtures/gemfile.txt +5 -0
  28. data/features/support/fixtures/preinitializer.txt +20 -0
  29. data/features/support/paths.rb +28 -0
  30. data/features/support/rails.rb +63 -0
  31. data/features/support/selectors.rb +19 -0
  32. data/gemfiles/4.2.awsv2.0.gemfile +17 -0
  33. data/gemfiles/4.2.awsv2.1.gemfile +17 -0
  34. data/gemfiles/4.2.awsv2.gemfile +20 -0
  35. data/gemfiles/5.0.awsv2.0.gemfile +17 -0
  36. data/gemfiles/5.0.awsv2.1.gemfile +17 -0
  37. data/gemfiles/5.0.awsv2.gemfile +25 -0
  38. data/lib/generators/paperclip/USAGE +8 -0
  39. data/lib/generators/paperclip/paperclip_generator.rb +30 -0
  40. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +15 -0
  41. data/lib/paperclip.rb +211 -0
  42. data/lib/paperclip/attachment.rb +610 -0
  43. data/lib/paperclip/attachment_registry.rb +60 -0
  44. data/lib/paperclip/callbacks.rb +42 -0
  45. data/lib/paperclip/content_type_detector.rb +80 -0
  46. data/lib/paperclip/errors.rb +34 -0
  47. data/lib/paperclip/file_command_content_type_detector.rb +30 -0
  48. data/lib/paperclip/filename_cleaner.rb +16 -0
  49. data/lib/paperclip/geometry.rb +158 -0
  50. data/lib/paperclip/geometry_detector_factory.rb +48 -0
  51. data/lib/paperclip/geometry_parser_factory.rb +31 -0
  52. data/lib/paperclip/glue.rb +17 -0
  53. data/lib/paperclip/has_attached_file.rb +115 -0
  54. data/lib/paperclip/helpers.rb +60 -0
  55. data/lib/paperclip/interpolations.rb +197 -0
  56. data/lib/paperclip/interpolations/plural_cache.rb +18 -0
  57. data/lib/paperclip/io_adapters/abstract_adapter.rb +47 -0
  58. data/lib/paperclip/io_adapters/attachment_adapter.rb +36 -0
  59. data/lib/paperclip/io_adapters/data_uri_adapter.rb +22 -0
  60. data/lib/paperclip/io_adapters/empty_string_adapter.rb +18 -0
  61. data/lib/paperclip/io_adapters/file_adapter.rb +22 -0
  62. data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +15 -0
  63. data/lib/paperclip/io_adapters/identity_adapter.rb +12 -0
  64. data/lib/paperclip/io_adapters/nil_adapter.rb +34 -0
  65. data/lib/paperclip/io_adapters/registry.rb +32 -0
  66. data/lib/paperclip/io_adapters/stringio_adapter.rb +33 -0
  67. data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +42 -0
  68. data/lib/paperclip/io_adapters/uri_adapter.rb +44 -0
  69. data/lib/paperclip/locales/en.yml +18 -0
  70. data/lib/paperclip/logger.rb +21 -0
  71. data/lib/paperclip/matchers.rb +64 -0
  72. data/lib/paperclip/matchers/have_attached_file_matcher.rb +54 -0
  73. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +100 -0
  74. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +59 -0
  75. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +96 -0
  76. data/lib/paperclip/media_type_spoof_detector.rb +89 -0
  77. data/lib/paperclip/missing_attachment_styles.rb +79 -0
  78. data/lib/paperclip/processor.rb +48 -0
  79. data/lib/paperclip/processor_helpers.rb +50 -0
  80. data/lib/paperclip/rails_environment.rb +25 -0
  81. data/lib/paperclip/railtie.rb +31 -0
  82. data/lib/paperclip/schema.rb +77 -0
  83. data/lib/paperclip/storage.rb +4 -0
  84. data/lib/paperclip/storage/database.rb +140 -0
  85. data/lib/paperclip/storage/filesystem.rb +90 -0
  86. data/lib/paperclip/storage/fog.rb +244 -0
  87. data/lib/paperclip/storage/s3.rb +442 -0
  88. data/lib/paperclip/style.rb +109 -0
  89. data/lib/paperclip/tempfile.rb +43 -0
  90. data/lib/paperclip/tempfile_factory.rb +23 -0
  91. data/lib/paperclip/thumbnail.rb +121 -0
  92. data/lib/paperclip/url_generator.rb +72 -0
  93. data/lib/paperclip/validators.rb +74 -0
  94. data/lib/paperclip/validators/attachment_content_type_validator.rb +88 -0
  95. data/lib/paperclip/validators/attachment_file_name_validator.rb +80 -0
  96. data/lib/paperclip/validators/attachment_file_type_ignorance_validator.rb +29 -0
  97. data/lib/paperclip/validators/attachment_presence_validator.rb +30 -0
  98. data/lib/paperclip/validators/attachment_size_validator.rb +109 -0
  99. data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +27 -0
  100. data/lib/paperclip/version.rb +3 -0
  101. data/lib/tasks/paperclip.rake +127 -0
  102. data/paperclip.gemspec +54 -0
  103. data/shoulda_macros/paperclip.rb +134 -0
  104. data/spec/database.yml +4 -0
  105. data/spec/paperclip/attachment_definitions_spec.rb +13 -0
  106. data/spec/paperclip/attachment_processing_spec.rb +80 -0
  107. data/spec/paperclip/attachment_registry_spec.rb +158 -0
  108. data/spec/paperclip/attachment_spec.rb +1517 -0
  109. data/spec/paperclip/content_type_detector_spec.rb +48 -0
  110. data/spec/paperclip/file_command_content_type_detector_spec.rb +26 -0
  111. data/spec/paperclip/filename_cleaner_spec.rb +14 -0
  112. data/spec/paperclip/geometry_detector_spec.rb +39 -0
  113. data/spec/paperclip/geometry_parser_spec.rb +73 -0
  114. data/spec/paperclip/geometry_spec.rb +255 -0
  115. data/spec/paperclip/glue_spec.rb +44 -0
  116. data/spec/paperclip/has_attached_file_spec.rb +158 -0
  117. data/spec/paperclip/integration_spec.rb +668 -0
  118. data/spec/paperclip/interpolations_spec.rb +262 -0
  119. data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +78 -0
  120. data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +139 -0
  121. data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +83 -0
  122. data/spec/paperclip/io_adapters/empty_string_adapter_spec.rb +17 -0
  123. data/spec/paperclip/io_adapters/file_adapter_spec.rb +131 -0
  124. data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +113 -0
  125. data/spec/paperclip/io_adapters/identity_adapter_spec.rb +8 -0
  126. data/spec/paperclip/io_adapters/nil_adapter_spec.rb +25 -0
  127. data/spec/paperclip/io_adapters/registry_spec.rb +35 -0
  128. data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +64 -0
  129. data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +146 -0
  130. data/spec/paperclip/io_adapters/uri_adapter_spec.rb +102 -0
  131. data/spec/paperclip/matchers/have_attached_file_matcher_spec.rb +19 -0
  132. data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +109 -0
  133. data/spec/paperclip/matchers/validate_attachment_presence_matcher_spec.rb +69 -0
  134. data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +88 -0
  135. data/spec/paperclip/media_type_spoof_detector_spec.rb +70 -0
  136. data/spec/paperclip/meta_class_spec.rb +30 -0
  137. data/spec/paperclip/paperclip_missing_attachment_styles_spec.rb +84 -0
  138. data/spec/paperclip/paperclip_spec.rb +192 -0
  139. data/spec/paperclip/plural_cache_spec.rb +37 -0
  140. data/spec/paperclip/processor_helpers_spec.rb +57 -0
  141. data/spec/paperclip/processor_spec.rb +26 -0
  142. data/spec/paperclip/rails_environment_spec.rb +33 -0
  143. data/spec/paperclip/rake_spec.rb +103 -0
  144. data/spec/paperclip/schema_spec.rb +248 -0
  145. data/spec/paperclip/storage/filesystem_spec.rb +79 -0
  146. data/spec/paperclip/storage/fog_spec.rb +545 -0
  147. data/spec/paperclip/storage/s3_live_spec.rb +186 -0
  148. data/spec/paperclip/storage/s3_spec.rb +1583 -0
  149. data/spec/paperclip/style_spec.rb +255 -0
  150. data/spec/paperclip/tempfile_factory_spec.rb +33 -0
  151. data/spec/paperclip/thumbnail_spec.rb +500 -0
  152. data/spec/paperclip/url_generator_spec.rb +211 -0
  153. data/spec/paperclip/validators/attachment_content_type_validator_spec.rb +322 -0
  154. data/spec/paperclip/validators/attachment_file_name_validator_spec.rb +160 -0
  155. data/spec/paperclip/validators/attachment_presence_validator_spec.rb +85 -0
  156. data/spec/paperclip/validators/attachment_size_validator_spec.rb +235 -0
  157. data/spec/paperclip/validators/media_type_spoof_detection_validator_spec.rb +52 -0
  158. data/spec/paperclip/validators_spec.rb +164 -0
  159. data/spec/spec_helper.rb +45 -0
  160. data/spec/support/assertions.rb +78 -0
  161. data/spec/support/fake_model.rb +25 -0
  162. data/spec/support/fake_rails.rb +12 -0
  163. data/spec/support/fixtures/12k.png +0 -0
  164. data/spec/support/fixtures/50x50.png +0 -0
  165. data/spec/support/fixtures/5k.png +0 -0
  166. data/spec/support/fixtures/animated +0 -0
  167. data/spec/support/fixtures/animated.gif +0 -0
  168. data/spec/support/fixtures/animated.unknown +0 -0
  169. data/spec/support/fixtures/bad.png +1 -0
  170. data/spec/support/fixtures/empty.html +1 -0
  171. data/spec/support/fixtures/empty.xlsx +0 -0
  172. data/spec/support/fixtures/fog.yml +8 -0
  173. data/spec/support/fixtures/rotated.jpg +0 -0
  174. data/spec/support/fixtures/s3.yml +8 -0
  175. data/spec/support/fixtures/spaced file.jpg +0 -0
  176. data/spec/support/fixtures/spaced file.png +0 -0
  177. data/spec/support/fixtures/text.txt +1 -0
  178. data/spec/support/fixtures/twopage.pdf +0 -0
  179. data/spec/support/fixtures/uppercase.PNG +0 -0
  180. data/spec/support/matchers/accept.rb +5 -0
  181. data/spec/support/matchers/exist.rb +5 -0
  182. data/spec/support/matchers/have_column.rb +23 -0
  183. data/spec/support/mock_attachment.rb +22 -0
  184. data/spec/support/mock_interpolator.rb +24 -0
  185. data/spec/support/mock_url_generator_builder.rb +27 -0
  186. data/spec/support/model_reconstruction.rb +68 -0
  187. data/spec/support/reporting.rb +11 -0
  188. data/spec/support/test_data.rb +13 -0
  189. data/spec/support/version_helper.rb +9 -0
  190. metadata +713 -0
@@ -0,0 +1,4 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: ":memory:"
4
+
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Attachment Definitions" do
4
+ it 'returns all of the attachments on the class' do
5
+ reset_class "Dummy"
6
+ Dummy.has_attached_file :avatar, {path: "abc"}
7
+ Dummy.has_attached_file :other_attachment, {url: "123"}
8
+ Dummy.do_not_validate_attachment_file_type :avatar
9
+ expected = {avatar: {path: "abc"}, other_attachment: {url: "123"}}
10
+
11
+ expect(Dummy.attachment_definitions).to eq expected
12
+ end
13
+ end
@@ -0,0 +1,80 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe 'Attachment Processing' do
5
+ before { rebuild_class }
6
+
7
+ context 'using validates_attachment_content_type' do
8
+ it 'processes attachments given a valid assignment' do
9
+ file = File.new(fixture_file("5k.png"))
10
+ Dummy.validates_attachment_content_type :avatar, content_type: "image/png"
11
+ instance = Dummy.new
12
+ attachment = instance.avatar
13
+ attachment.expects(:post_process_styles)
14
+
15
+ attachment.assign(file)
16
+ end
17
+
18
+ it 'does not process attachments given an invalid assignment with :not' do
19
+ file = File.new(fixture_file("5k.png"))
20
+ Dummy.validates_attachment_content_type :avatar, not: "image/png"
21
+ instance = Dummy.new
22
+ attachment = instance.avatar
23
+ attachment.expects(:post_process_styles).never
24
+
25
+ attachment.assign(file)
26
+ end
27
+
28
+ it 'does not process attachments given an invalid assignment with :content_type' do
29
+ file = File.new(fixture_file("5k.png"))
30
+ Dummy.validates_attachment_content_type :avatar, content_type: "image/tiff"
31
+ instance = Dummy.new
32
+ attachment = instance.avatar
33
+ attachment.expects(:post_process_styles).never
34
+
35
+ attachment.assign(file)
36
+ end
37
+
38
+ it 'allows what would be an invalid assignment when validation :if clause returns false' do
39
+ invalid_assignment = File.new(fixture_file("5k.png"))
40
+ Dummy.validates_attachment_content_type :avatar, content_type: "image/tiff", if: lambda{false}
41
+ instance = Dummy.new
42
+ attachment = instance.avatar
43
+ attachment.expects(:post_process_styles)
44
+
45
+ attachment.assign(invalid_assignment)
46
+ end
47
+ end
48
+
49
+ context 'using validates_attachment' do
50
+ it 'processes attachments given a valid assignment' do
51
+ file = File.new(fixture_file("5k.png"))
52
+ Dummy.validates_attachment :avatar, content_type: {content_type: "image/png"}
53
+ instance = Dummy.new
54
+ attachment = instance.avatar
55
+ attachment.expects(:post_process_styles)
56
+
57
+ attachment.assign(file)
58
+ end
59
+
60
+ it 'does not process attachments given an invalid assignment with :not' do
61
+ file = File.new(fixture_file("5k.png"))
62
+ Dummy.validates_attachment :avatar, content_type: {not: "image/png"}
63
+ instance = Dummy.new
64
+ attachment = instance.avatar
65
+ attachment.expects(:post_process_styles).never
66
+
67
+ attachment.assign(file)
68
+ end
69
+
70
+ it 'does not process attachments given an invalid assignment with :content_type' do
71
+ file = File.new(fixture_file("5k.png"))
72
+ Dummy.validates_attachment :avatar, content_type: {content_type: "image/tiff"}
73
+ instance = Dummy.new
74
+ attachment = instance.avatar
75
+ attachment.expects(:post_process_styles).never
76
+
77
+ attachment.assign(file)
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,158 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Attachment Registry' do
4
+ before do
5
+ Paperclip::AttachmentRegistry.clear
6
+ end
7
+
8
+ context '.names_for' do
9
+ it 'includes attachment names for the given class' do
10
+ foo = Class.new
11
+ Paperclip::AttachmentRegistry.register(foo, :avatar, {})
12
+
13
+ assert_equal [:avatar], Paperclip::AttachmentRegistry.names_for(foo)
14
+ end
15
+
16
+ it 'does not include attachment names for other classes' do
17
+ foo = Class.new
18
+ bar = Class.new
19
+ Paperclip::AttachmentRegistry.register(foo, :avatar, {})
20
+ Paperclip::AttachmentRegistry.register(bar, :lover, {})
21
+
22
+ assert_equal [:lover], Paperclip::AttachmentRegistry.names_for(bar)
23
+ end
24
+
25
+ it 'produces the empty array for a missing key' do
26
+ assert_empty Paperclip::AttachmentRegistry.names_for(Class.new)
27
+ end
28
+ end
29
+
30
+ context '.each_definition' do
31
+ it 'calls the block with the class, attachment name, and options' do
32
+ foo = Class.new
33
+ expected_accumulations = [
34
+ [foo, :avatar, { yo: "greeting" }],
35
+ [foo, :greeter, { ciao: "greeting" }]
36
+ ]
37
+ expected_accumulations.each do |args|
38
+ Paperclip::AttachmentRegistry.register(*args)
39
+ end
40
+ accumulations = []
41
+
42
+ Paperclip::AttachmentRegistry.each_definition do |*args|
43
+ accumulations << args
44
+ end
45
+
46
+ assert_equal expected_accumulations, accumulations
47
+ end
48
+ end
49
+
50
+ context '.definitions_for' do
51
+ it 'produces the attachment name and options' do
52
+ expected_definitions = {
53
+ avatar: { yo: "greeting" },
54
+ greeter: { ciao: "greeting" }
55
+ }
56
+ foo = Class.new
57
+ Paperclip::AttachmentRegistry.register(
58
+ foo,
59
+ :avatar,
60
+ yo: "greeting"
61
+ )
62
+ Paperclip::AttachmentRegistry.register(
63
+ foo,
64
+ :greeter,
65
+ ciao: "greeting"
66
+ )
67
+
68
+ definitions = Paperclip::AttachmentRegistry.definitions_for(foo)
69
+
70
+ assert_equal expected_definitions, definitions
71
+ end
72
+
73
+ it 'produces defintions for subclasses' do
74
+ expected_definitions = { avatar: { yo: "greeting" } }
75
+ foo = Class.new
76
+ bar = Class.new(foo)
77
+ Paperclip::AttachmentRegistry.register(
78
+ foo,
79
+ :avatar,
80
+ expected_definitions[:avatar]
81
+ )
82
+
83
+ definitions = Paperclip::AttachmentRegistry.definitions_for(bar)
84
+
85
+ assert_equal expected_definitions, definitions
86
+ end
87
+
88
+ it 'produces defintions for subclasses but deep merging them' do
89
+ foo_definitions = { avatar: { yo: "greeting" } }
90
+ bar_definitions = { avatar: { ciao: "greeting" } }
91
+ expected_definitions = {
92
+ avatar: {
93
+ yo: "greeting",
94
+ ciao: "greeting"
95
+ }
96
+ }
97
+ foo = Class.new
98
+ bar = Class.new(foo)
99
+ Paperclip::AttachmentRegistry.register(
100
+ foo,
101
+ :avatar,
102
+ foo_definitions[:avatar]
103
+ )
104
+ Paperclip::AttachmentRegistry.register(
105
+ bar,
106
+ :avatar,
107
+ bar_definitions[:avatar]
108
+ )
109
+
110
+ definitions = Paperclip::AttachmentRegistry.definitions_for(bar)
111
+
112
+ assert_equal expected_definitions, definitions
113
+ end
114
+
115
+ it 'allows subclasses to override attachment defitions' do
116
+ foo_definitions = { avatar: { yo: "greeting" } }
117
+ bar_definitions = { avatar: { yo: "hello" } }
118
+
119
+ expected_definitions = {
120
+ avatar: {
121
+ yo: "hello"
122
+ }
123
+ }
124
+
125
+ foo = Class.new
126
+ bar = Class.new(foo)
127
+ Paperclip::AttachmentRegistry.register(
128
+ foo,
129
+ :avatar,
130
+ foo_definitions[:avatar]
131
+ )
132
+ Paperclip::AttachmentRegistry.register(
133
+ bar,
134
+ :avatar,
135
+ bar_definitions[:avatar]
136
+ )
137
+
138
+ definitions = Paperclip::AttachmentRegistry.definitions_for(bar)
139
+
140
+ assert_equal expected_definitions, definitions
141
+ end
142
+ end
143
+
144
+ context '.clear' do
145
+ it 'removes all of the existing attachment definitions' do
146
+ foo = Class.new
147
+ Paperclip::AttachmentRegistry.register(
148
+ foo,
149
+ :greeter,
150
+ ciao: "greeting"
151
+ )
152
+
153
+ Paperclip::AttachmentRegistry.clear
154
+
155
+ assert_empty Paperclip::AttachmentRegistry.names_for(foo)
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,1517 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe Paperclip::Attachment do
5
+
6
+ it "is not present when file not set" do
7
+ rebuild_class
8
+ dummy = Dummy.new
9
+ expect(dummy.avatar).to be_blank
10
+ expect(dummy.avatar).to_not be_present
11
+ end
12
+
13
+ it "is present when the file is set" do
14
+ rebuild_class
15
+ dummy = Dummy.new
16
+ dummy.avatar = File.new(fixture_file("50x50.png"), "rb")
17
+ expect(dummy.avatar).to_not be_blank
18
+ expect(dummy.avatar).to be_present
19
+ end
20
+
21
+ it "processes :original style first" do
22
+ file = File.new(fixture_file("50x50.png"), 'rb')
23
+ rebuild_class styles: { small: '100x>', original: '42x42#' }
24
+ dummy = Dummy.new
25
+ dummy.avatar = file
26
+ dummy.save
27
+
28
+ # :small avatar should be 42px wide (processed original), not 50px (preprocessed original)
29
+ expect(`identify -format "%w" "#{dummy.avatar.path(:small)}"`.strip).to eq "42"
30
+
31
+ file.close
32
+ end
33
+
34
+ it "does not delete styles that don't get reprocessed" do
35
+ file = File.new(fixture_file("50x50.png"), 'rb')
36
+ rebuild_class styles: {
37
+ small: "100x>",
38
+ large: "500x>",
39
+ original: "42x42#"
40
+ }
41
+
42
+ dummy = Dummy.new
43
+ dummy.avatar = file
44
+ dummy.save
45
+
46
+ expect(dummy.avatar.path(:small)).to exist
47
+ expect(dummy.avatar.path(:large)).to exist
48
+ expect(dummy.avatar.path(:original)).to exist
49
+
50
+ dummy.avatar.reprocess!(:small)
51
+
52
+ expect(dummy.avatar.path(:small)).to exist
53
+ expect(dummy.avatar.path(:large)).to exist
54
+ expect(dummy.avatar.path(:original)).to exist
55
+ end
56
+
57
+ context "having a not empty hash as a default option" do
58
+ before do
59
+ @old_default_options = Paperclip::Attachment.default_options.dup
60
+ @new_default_options = { convert_options: { all: "-background white" } }
61
+ Paperclip::Attachment.default_options.merge!(@new_default_options)
62
+ end
63
+
64
+ after do
65
+ Paperclip::Attachment.default_options.merge!(@old_default_options)
66
+ end
67
+
68
+ it "deep merges when it is overridden" do
69
+ new_options = { convert_options: { thumb: "-thumbnailize" } }
70
+ attachment = Paperclip::Attachment.new(:name, :instance, new_options)
71
+
72
+ expect(Paperclip::Attachment.default_options.deep_merge(new_options)).to eq attachment.instance_variable_get("@options")
73
+ end
74
+ end
75
+
76
+ it "handles a boolean second argument to #url" do
77
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
78
+ attachment = Paperclip::Attachment.new(
79
+ :name,
80
+ FakeModel.new,
81
+ url_generator: mock_url_generator_builder
82
+ )
83
+
84
+ attachment.url(:style_name, true)
85
+ expect(mock_url_generator_builder.has_generated_url_with_options?(timestamp: true, escape: true)).to eq true
86
+
87
+ attachment.url(:style_name, false)
88
+ expect(mock_url_generator_builder.has_generated_url_with_options?(timestamp: false, escape: true)).to eq true
89
+ end
90
+
91
+ it "passes the style and options through to the URL generator on #url" do
92
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
93
+ attachment = Paperclip::Attachment.new(
94
+ :name,
95
+ FakeModel.new,
96
+ url_generator: mock_url_generator_builder
97
+ )
98
+
99
+ attachment.url(:style_name, options: :values)
100
+ expect(mock_url_generator_builder.has_generated_url_with_options?(options: :values)).to eq true
101
+ end
102
+
103
+ it "passes default options through when #url is given one argument" do
104
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
105
+ attachment = Paperclip::Attachment.new(:name,
106
+ FakeModel.new,
107
+ url_generator: mock_url_generator_builder,
108
+ use_timestamp: true)
109
+
110
+ attachment.url(:style_name)
111
+ assert mock_url_generator_builder.has_generated_url_with_options?(escape: true, timestamp: true)
112
+ end
113
+
114
+ it "passes default style and options through when #url is given no arguments" do
115
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
116
+ attachment = Paperclip::Attachment.new(:name,
117
+ FakeModel.new,
118
+ default_style: 'default style',
119
+ url_generator: mock_url_generator_builder,
120
+ use_timestamp: true)
121
+
122
+ attachment.url
123
+ assert mock_url_generator_builder.has_generated_url_with_options?(escape: true, timestamp: true)
124
+ assert mock_url_generator_builder.has_generated_url_with_style_name?('default style')
125
+ end
126
+
127
+ it "passes the option timestamp: true if :use_timestamp is true and :timestamp is not passed" do
128
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
129
+ attachment = Paperclip::Attachment.new(:name,
130
+ FakeModel.new,
131
+ url_generator: mock_url_generator_builder,
132
+ use_timestamp: true)
133
+
134
+ attachment.url(:style_name)
135
+ assert mock_url_generator_builder.has_generated_url_with_options?(escape: true, timestamp: true)
136
+ end
137
+
138
+ it "passes the option timestamp: false if :use_timestamp is false and :timestamp is not passed" do
139
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
140
+ attachment = Paperclip::Attachment.new(:name,
141
+ FakeModel.new,
142
+ url_generator: mock_url_generator_builder,
143
+ use_timestamp: false)
144
+
145
+ attachment.url(:style_name)
146
+ assert mock_url_generator_builder.has_generated_url_with_options?(escape: true, timestamp: false)
147
+ end
148
+
149
+ it "does not change the :timestamp if :timestamp is passed" do
150
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
151
+ attachment = Paperclip::Attachment.new(:name,
152
+ FakeModel.new,
153
+ url_generator: mock_url_generator_builder,
154
+ use_timestamp: false)
155
+
156
+ attachment.url(:style_name, timestamp: true)
157
+ assert mock_url_generator_builder.has_generated_url_with_options?(escape: true, timestamp: true)
158
+ end
159
+
160
+ it "renders JSON as default style" do
161
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
162
+ attachment = Paperclip::Attachment.new(:name,
163
+ FakeModel.new,
164
+ default_style: 'default style',
165
+ url_generator: mock_url_generator_builder)
166
+
167
+ attachment.as_json
168
+ assert mock_url_generator_builder.has_generated_url_with_style_name?('default style')
169
+ end
170
+
171
+ it "passes the option escape: true if :escape_url is true and :escape is not passed" do
172
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
173
+ attachment = Paperclip::Attachment.new(:name,
174
+ FakeModel.new,
175
+ url_generator: mock_url_generator_builder,
176
+ escape_url: true)
177
+
178
+ attachment.url(:style_name)
179
+ assert mock_url_generator_builder.has_generated_url_with_options?(escape: true)
180
+ end
181
+
182
+ it "passes the option escape: false if :escape_url is false and :escape is not passed" do
183
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
184
+ attachment = Paperclip::Attachment.new(:name,
185
+ FakeModel.new,
186
+ url_generator: mock_url_generator_builder,
187
+ escape_url: false)
188
+
189
+ attachment.url(:style_name)
190
+ assert mock_url_generator_builder.has_generated_url_with_options?(escape: false)
191
+ end
192
+
193
+ it "returns the path based on the url by default" do
194
+ @attachment = attachment url: "/:class/:id/:basename"
195
+ @model = @attachment.instance
196
+ @model.id = 1234
197
+ @model.avatar_file_name = "fake.jpg"
198
+ assert_equal "#{Rails.root}/public/fake_models/1234/fake", @attachment.path
199
+ end
200
+
201
+ it "defaults to a path that scales" do
202
+ avatar_attachment = attachment
203
+ model = avatar_attachment.instance
204
+ model.id = 1234
205
+ model.avatar_file_name = "fake.jpg"
206
+ expected_path = "#{Rails.root}/public/system/fake_models/avatars/000/001/234/original/fake.jpg"
207
+ assert_equal expected_path, avatar_attachment.path
208
+ end
209
+
210
+ it "renders JSON as the URL to the attachment" do
211
+ avatar_attachment = attachment
212
+ model = avatar_attachment.instance
213
+ model.id = 1234
214
+ model.avatar_file_name = "fake.jpg"
215
+ assert_equal attachment.url, attachment.as_json
216
+ end
217
+
218
+ it "renders JSON from the model when requested by :methods" do
219
+ rebuild_model
220
+ dummy = Dummy.new
221
+ dummy.id = 1234
222
+ dummy.avatar_file_name = "fake.jpg"
223
+ dummy.stubs(:new_record?).returns(false)
224
+ expected_string = '{"avatar":"/system/dummies/avatars/000/001/234/original/fake.jpg"}'
225
+ # active_model pre-3.2 checks only by calling any? on it, thus it doesn't work if it is empty
226
+ assert_equal expected_string, dummy.to_json(only: [:dummy_key_for_old_active_model], methods: [:avatar])
227
+ end
228
+
229
+ context "Attachment default_options" do
230
+ before do
231
+ rebuild_model
232
+ @old_default_options = Paperclip::Attachment.default_options.dup
233
+ @new_default_options = @old_default_options.merge({
234
+ path: "argle/bargle",
235
+ url: "fooferon",
236
+ default_url: "not here.png"
237
+ })
238
+ end
239
+
240
+ after do
241
+ Paperclip::Attachment.default_options.merge! @old_default_options
242
+ end
243
+
244
+ it "is overrideable" do
245
+ Paperclip::Attachment.default_options.merge!(@new_default_options)
246
+ @new_default_options.keys.each do |key|
247
+ assert_equal @new_default_options[key],
248
+ Paperclip::Attachment.default_options[key]
249
+ end
250
+ end
251
+
252
+ context "without an Attachment" do
253
+ before do
254
+ rebuild_model default_url: "default.url"
255
+ @dummy = Dummy.new
256
+ end
257
+
258
+ it "returns false when asked exists?" do
259
+ assert !@dummy.avatar.exists?
260
+ end
261
+
262
+ it "#url returns the default_url" do
263
+ expect(@dummy.avatar.url).to eq "default.url"
264
+ end
265
+ end
266
+
267
+ context "on an Attachment" do
268
+ before do
269
+ @dummy = Dummy.new
270
+ @attachment = @dummy.avatar
271
+ end
272
+
273
+ Paperclip::Attachment.default_options.keys.each do |key|
274
+ it "is the default_options for #{key}" do
275
+ assert_equal @old_default_options[key],
276
+ @attachment.instance_variable_get("@options")[key],
277
+ key.to_s
278
+ end
279
+ end
280
+
281
+ context "when redefined" do
282
+ before do
283
+ Paperclip::Attachment.default_options.merge!(@new_default_options)
284
+ @dummy = Dummy.new
285
+ @attachment = @dummy.avatar
286
+ end
287
+
288
+ Paperclip::Attachment.default_options.keys.each do |key|
289
+ it "is the new default_options for #{key}" do
290
+ assert_equal @new_default_options[key],
291
+ @attachment.instance_variable_get("@options")[key],
292
+ key.to_s
293
+ end
294
+ end
295
+ end
296
+ end
297
+ end
298
+
299
+ context "An attachment with similarly named interpolations" do
300
+ before do
301
+ rebuild_model path: ":id.omg/:id-bbq/:idwhat/:id_partition.wtf"
302
+ @dummy = Dummy.new
303
+ @dummy.stubs(:id).returns(1024)
304
+ @file = File.new(fixture_file("5k.png"), 'rb')
305
+ @dummy.avatar = @file
306
+ end
307
+
308
+ after { @file.close }
309
+
310
+ it "makes sure that they are interpolated correctly" do
311
+ assert_equal "1024.omg/1024-bbq/1024what/000/001/024.wtf", @dummy.avatar.path
312
+ end
313
+ end
314
+
315
+ context "An attachment with :timestamp interpolations" do
316
+ before do
317
+ @file = StringIO.new("...")
318
+ @zone = 'UTC'
319
+ Time.stubs(:zone).returns(@zone)
320
+ @zone_default = 'Eastern Time (US & Canada)'
321
+ Time.stubs(:zone_default).returns(@zone_default)
322
+ end
323
+
324
+ context "using default time zone" do
325
+ before do
326
+ rebuild_model path: ":timestamp", use_default_time_zone: true
327
+ @dummy = Dummy.new
328
+ @dummy.avatar = @file
329
+ end
330
+
331
+ it "returns a time in the default zone" do
332
+ assert_equal @dummy.avatar_updated_at.in_time_zone(@zone_default).to_s, @dummy.avatar.path
333
+ end
334
+ end
335
+
336
+ context "using per-thread time zone" do
337
+ before do
338
+ rebuild_model path: ":timestamp", use_default_time_zone: false
339
+ @dummy = Dummy.new
340
+ @dummy.avatar = @file
341
+ end
342
+
343
+ it "returns a time in the per-thread zone" do
344
+ assert_equal @dummy.avatar_updated_at.in_time_zone(@zone).to_s, @dummy.avatar.path
345
+ end
346
+ end
347
+ end
348
+
349
+ context "An attachment with :hash interpolations" do
350
+ before do
351
+ @file = File.open(fixture_file("5k.png"))
352
+ end
353
+
354
+ after do
355
+ @file.close
356
+ end
357
+
358
+ it "raises if no secret is provided" do
359
+ rebuild_model path: ":hash"
360
+ @attachment = Dummy.new.avatar
361
+ @attachment.assign @file
362
+
363
+ assert_raises ArgumentError do
364
+ @attachment.path
365
+ end
366
+ end
367
+
368
+ context "when secret is set" do
369
+ before do
370
+ rebuild_model path: ":hash",
371
+ hash_secret: "w00t",
372
+ hash_data: ":class/:attachment/:style/:filename"
373
+ @attachment = Dummy.new.avatar
374
+ @attachment.assign @file
375
+ end
376
+
377
+ it "results in the correct interpolation" do
378
+ assert_equal "dummies/avatars/original/5k.png",
379
+ @attachment.send(:interpolate, @attachment.options[:hash_data])
380
+ assert_equal "dummies/avatars/thumb/5k.png",
381
+ @attachment.send(:interpolate, @attachment.options[:hash_data], :thumb)
382
+ end
383
+
384
+ it "results in a correct hash" do
385
+ assert_equal "0a59e9142bba11576de1d353d8747b1acad5ad34", @attachment.path
386
+ assert_equal "b39a062c1e62e85a6c785ed00cf3bebf5f850e2b", @attachment.path(:thumb)
387
+ end
388
+ end
389
+ end
390
+
391
+ context "An attachment with a :rails_env interpolation" do
392
+ before do
393
+ @rails_env = "blah"
394
+ @id = 1024
395
+ rebuild_model path: ":rails_env/:id.png"
396
+ @dummy = Dummy.new
397
+ @dummy.stubs(:id).returns(@id)
398
+ @file = StringIO.new(".")
399
+ @dummy.avatar = @file
400
+ Rails.stubs(:env).returns(@rails_env)
401
+ end
402
+
403
+ it "returns the proper path" do
404
+ assert_equal "#{@rails_env}/#{@id}.png", @dummy.avatar.path
405
+ end
406
+ end
407
+
408
+ context "An attachment with a default style and an extension interpolation" do
409
+ before do
410
+ rebuild_model path: ":basename.:extension",
411
+ styles: { default: ["100x100", :jpg] },
412
+ default_style: :default
413
+ @attachment = Dummy.new.avatar
414
+ @file = File.open(fixture_file("5k.png"))
415
+ @file.stubs(:original_filename).returns("file.png")
416
+ end
417
+ it "returns the right extension for the path" do
418
+ @attachment.assign(@file)
419
+ assert_equal "file.jpg", @attachment.path
420
+ end
421
+ end
422
+
423
+ context "An attachment with :convert_options" do
424
+ before do
425
+ rebuild_model styles: {
426
+ thumb: "100x100",
427
+ large: "400x400"
428
+ },
429
+ convert_options: {
430
+ all: "-do_stuff",
431
+ thumb: "-thumbnailize"
432
+ }
433
+ @dummy = Dummy.new
434
+ @dummy.avatar
435
+ end
436
+
437
+ it "reports the correct options when sent #extra_options_for(:thumb)" do
438
+ assert_equal "-thumbnailize -do_stuff", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect
439
+ end
440
+
441
+ it "reports the correct options when sent #extra_options_for(:large)" do
442
+ assert_equal "-do_stuff", @dummy.avatar.send(:extra_options_for, :large)
443
+ end
444
+ end
445
+
446
+ context "An attachment with :source_file_options" do
447
+ before do
448
+ rebuild_model styles: {
449
+ thumb: "100x100",
450
+ large: "400x400"
451
+ },
452
+ source_file_options: {
453
+ all: "-density 400",
454
+ thumb: "-depth 8"
455
+ }
456
+ @dummy = Dummy.new
457
+ @dummy.avatar
458
+ end
459
+
460
+ it "reports the correct options when sent #extra_source_file_options_for(:thumb)" do
461
+ assert_equal "-depth 8 -density 400", @dummy.avatar.send(:extra_source_file_options_for, :thumb), @dummy.avatar.source_file_options.inspect
462
+ end
463
+
464
+ it "reports the correct options when sent #extra_source_file_options_for(:large)" do
465
+ assert_equal "-density 400", @dummy.avatar.send(:extra_source_file_options_for, :large)
466
+ end
467
+ end
468
+
469
+ context "An attachment with :only_process" do
470
+ before do
471
+ rebuild_model styles: {
472
+ thumb: "100x100",
473
+ large: "400x400"
474
+ },
475
+ only_process: [:thumb]
476
+ @file = StringIO.new("...")
477
+ @attachment = Dummy.new.avatar
478
+ end
479
+
480
+ it "only processes the provided style" do
481
+ @attachment.expects(:post_process).with(:thumb)
482
+ @attachment.expects(:post_process).with(:large).never
483
+ @attachment.assign(@file)
484
+ end
485
+ end
486
+
487
+ context "An attachment with :only_process that is a proc" do
488
+ before do
489
+ rebuild_model styles: {
490
+ thumb: "100x100",
491
+ large: "400x400"
492
+ },
493
+ only_process: lambda { |attachment| [:thumb] }
494
+
495
+ @file = StringIO.new("...")
496
+ @attachment = Dummy.new.avatar
497
+ end
498
+
499
+ it "only processes the provided style" do
500
+ @attachment.expects(:post_process).with(:thumb)
501
+ @attachment.expects(:post_process).with(:large).never
502
+ @attachment.assign(@file)
503
+ end
504
+ end
505
+
506
+ context "An attachment with :convert_options that is a proc" do
507
+ before do
508
+ rebuild_model styles: {
509
+ thumb: "100x100",
510
+ large: "400x400"
511
+ },
512
+ convert_options: {
513
+ all: lambda{|i| i.all },
514
+ thumb: lambda{|i| i.thumb }
515
+ }
516
+ Dummy.class_eval do
517
+ def all; "-all"; end
518
+ def thumb; "-thumb"; end
519
+ end
520
+ @dummy = Dummy.new
521
+ @dummy.avatar
522
+ end
523
+
524
+ it "reports the correct options when sent #extra_options_for(:thumb)" do
525
+ assert_equal "-thumb -all", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect
526
+ end
527
+
528
+ it "reports the correct options when sent #extra_options_for(:large)" do
529
+ assert_equal "-all", @dummy.avatar.send(:extra_options_for, :large)
530
+ end
531
+ end
532
+
533
+ context "An attachment with :path that is a proc" do
534
+ before do
535
+ rebuild_model path: lambda{ |attachment| "path/#{attachment.instance.other}.:extension" }
536
+
537
+ @file = File.new(fixture_file("5k.png"), 'rb')
538
+ @dummyA = Dummy.new(other: 'a')
539
+ @dummyA.avatar = @file
540
+ @dummyB = Dummy.new(other: 'b')
541
+ @dummyB.avatar = @file
542
+ end
543
+
544
+ after { @file.close }
545
+
546
+ it "returns correct path" do
547
+ assert_equal "path/a.png", @dummyA.avatar.path
548
+ assert_equal "path/b.png", @dummyB.avatar.path
549
+ end
550
+ end
551
+
552
+ context "An attachment with :styles that is a proc" do
553
+ before do
554
+ rebuild_model styles: lambda{ |attachment| {thumb: "50x50#", large: "400x400"} }
555
+
556
+ @attachment = Dummy.new.avatar
557
+ end
558
+
559
+ it "has the correct geometry" do
560
+ assert_equal "50x50#", @attachment.styles[:thumb][:geometry]
561
+ end
562
+ end
563
+
564
+ context "An attachment with conditional :styles that is a proc" do
565
+ before do
566
+ rebuild_model styles: lambda{ |attachment| attachment.instance.other == 'a' ? {thumb: "50x50#"} : {large: "400x400"} }
567
+
568
+ @dummy = Dummy.new(other: 'a')
569
+ end
570
+
571
+ it "has the correct styles for the assigned instance values" do
572
+ assert_equal "50x50#", @dummy.avatar.styles[:thumb][:geometry]
573
+ assert_nil @dummy.avatar.styles[:large]
574
+
575
+ @dummy.other = 'b'
576
+
577
+ assert_equal "400x400", @dummy.avatar.styles[:large][:geometry]
578
+ assert_nil @dummy.avatar.styles[:thumb]
579
+ end
580
+ end
581
+
582
+ geometry_specs = [
583
+ [ lambda{|z| "50x50#" }, :png ],
584
+ lambda{|z| "50x50#" },
585
+ { geometry: lambda{|z| "50x50#" } }
586
+ ]
587
+ geometry_specs.each do |geometry_spec|
588
+ context "An attachment geometry like #{geometry_spec}" do
589
+ before do
590
+ rebuild_model styles: { normal: geometry_spec }
591
+ @attachment = Dummy.new.avatar
592
+ end
593
+
594
+ context "when assigned" do
595
+ before do
596
+ @file = StringIO.new(".")
597
+ @attachment.assign(@file)
598
+ end
599
+
600
+ it "has the correct geometry" do
601
+ assert_equal "50x50#", @attachment.styles[:normal][:geometry]
602
+ end
603
+ end
604
+ end
605
+ end
606
+
607
+ context "An attachment with both 'normal' and hash-style styles" do
608
+ before do
609
+ rebuild_model styles: {
610
+ normal: ["50x50#", :png],
611
+ hash: { geometry: "50x50#", format: :png }
612
+ }
613
+ @dummy = Dummy.new
614
+ @attachment = @dummy.avatar
615
+ end
616
+
617
+ [:processors, :whiny, :convert_options, :geometry, :format].each do |field|
618
+ it "has the same #{field} field" do
619
+ assert_equal @attachment.styles[:normal][field], @attachment.styles[:hash][field]
620
+ end
621
+ end
622
+ end
623
+
624
+ context "An attachment with :processors that is a proc" do
625
+ before do
626
+ class Paperclip::Test < Paperclip::Processor; end
627
+ @file = StringIO.new("...")
628
+ Paperclip::Test.stubs(:make).returns(@file)
629
+
630
+ rebuild_model styles: { normal: '' }, processors: lambda { |a| [ :test ] }
631
+ @attachment = Dummy.new.avatar
632
+ end
633
+
634
+ context "when assigned" do
635
+ before do
636
+ @attachment.assign(StringIO.new("."))
637
+ end
638
+
639
+ it "has the correct processors" do
640
+ assert_equal [ :test ], @attachment.styles[:normal][:processors]
641
+ end
642
+ end
643
+ end
644
+
645
+ context "An attachment with erroring processor" do
646
+ before do
647
+ rebuild_model processor: [:thumbnail], styles: { small: '' }, whiny_thumbnails: true
648
+ @dummy = Dummy.new
649
+ @file = StringIO.new("...")
650
+ @file.stubs(:to_tempfile).returns(@file)
651
+ end
652
+
653
+ context "when error is meaningful for the end user" do
654
+ before do
655
+ Paperclip::Thumbnail.expects(:make).raises(
656
+ Paperclip::Errors::NotIdentifiedByImageMagickError,
657
+ "cannot be processed."
658
+ )
659
+ end
660
+
661
+ it "correctly forwards processing error message to the instance" do
662
+ @dummy.avatar = @file
663
+ @dummy.valid?
664
+ assert_contains(
665
+ @dummy.errors.full_messages,
666
+ "Avatar cannot be processed."
667
+ )
668
+ end
669
+ end
670
+
671
+ context "when error is intended for the developer" do
672
+ before do
673
+ Paperclip::Thumbnail.expects(:make).raises(
674
+ Paperclip::Errors::CommandNotFoundError
675
+ )
676
+ end
677
+
678
+ it "propagates the error" do
679
+ assert_raises(Paperclip::Errors::CommandNotFoundError) do
680
+ @dummy.avatar = @file
681
+ end
682
+ end
683
+ end
684
+ end
685
+
686
+ context "An attachment with multiple processors" do
687
+ before do
688
+ class Paperclip::Test < Paperclip::Processor; end
689
+ @style_params = { once: {one: 1, two: 2} }
690
+ rebuild_model processors: [:thumbnail, :test], styles: @style_params
691
+ @dummy = Dummy.new
692
+ @file = StringIO.new("...")
693
+ @file.stubs(:close)
694
+ Paperclip::Test.stubs(:make).returns(@file)
695
+ Paperclip::Thumbnail.stubs(:make).returns(@file)
696
+ end
697
+
698
+ context "when assigned" do
699
+ it "calls #make on all specified processors" do
700
+ @dummy.avatar = @file
701
+
702
+ expect(Paperclip::Thumbnail).to have_received(:make)
703
+ expect(Paperclip::Test).to have_received(:make)
704
+ end
705
+
706
+ it "calls #make with the right parameters passed as second argument" do
707
+ expected_params = @style_params[:once].merge({
708
+ style: :once,
709
+ processors: [:thumbnail, :test],
710
+ whiny: true,
711
+ convert_options: "",
712
+ source_file_options: ""
713
+ })
714
+
715
+ @dummy.avatar = @file
716
+
717
+ expect(Paperclip::Thumbnail).to have_received(:make).with(anything, expected_params, anything)
718
+ end
719
+
720
+ it "calls #make with attachment passed as third argument" do
721
+ @dummy.avatar = @file
722
+
723
+ expect(Paperclip::Test).to have_received(:make).with(anything, anything, @dummy.avatar)
724
+ end
725
+
726
+ it "calls #make and unlinks intermediary files afterward" do
727
+ @dummy.avatar.expects(:unlink_files).with([@file, @file])
728
+
729
+ @dummy.avatar = @file
730
+ end
731
+ end
732
+ end
733
+
734
+ context "An attachment with a processor that returns original file" do
735
+ before do
736
+ class Paperclip::Test < Paperclip::Processor
737
+ def make; @file; end
738
+ end
739
+ rebuild_model processors: [:test], styles: { once: "100x100" }
740
+ @file = StringIO.new("...")
741
+ @file.stubs(:close)
742
+ @dummy = Dummy.new
743
+ end
744
+
745
+ context "when assigned" do
746
+ it "#calls #make and doesn't unlink the original file" do
747
+ @dummy.avatar.expects(:unlink_files).with([])
748
+
749
+ @dummy.avatar = @file
750
+ end
751
+ end
752
+ end
753
+
754
+ it "includes the filesystem module when loading the filesystem storage" do
755
+ rebuild_model storage: :filesystem
756
+ @dummy = Dummy.new
757
+ assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
758
+ end
759
+
760
+ it "includes the filesystem module even if capitalization is wrong" do
761
+ rebuild_model storage: :FileSystem
762
+ @dummy = Dummy.new
763
+ assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
764
+
765
+ rebuild_model storage: :Filesystem
766
+ @dummy = Dummy.new
767
+ assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
768
+ end
769
+
770
+ it "converts underscored storage name to camelcase" do
771
+ rebuild_model storage: :not_here
772
+ @dummy = Dummy.new
773
+ exception = assert_raises(Paperclip::Errors::StorageMethodNotFound, /NotHere/) do
774
+ @dummy.avatar
775
+ end
776
+ end
777
+
778
+ it "raises an error if you try to include a storage module that doesn't exist" do
779
+ rebuild_model storage: :not_here
780
+ @dummy = Dummy.new
781
+ assert_raises(Paperclip::Errors::StorageMethodNotFound) do
782
+ @dummy.avatar
783
+ end
784
+ end
785
+
786
+ context "An attachment with styles but no processors defined" do
787
+ before do
788
+ rebuild_model processors: [], styles: {something: '1'}
789
+ @dummy = Dummy.new
790
+ @file = StringIO.new("...")
791
+ end
792
+ it "raises when assigned to" do
793
+ assert_raises(RuntimeError){ @dummy.avatar = @file }
794
+ end
795
+ end
796
+
797
+ context "An attachment without styles and with no processors defined" do
798
+ before do
799
+ rebuild_model processors: [], styles: {}
800
+ @dummy = Dummy.new
801
+ @file = StringIO.new("...")
802
+ end
803
+ it "does not raise when assigned to" do
804
+ @dummy.avatar = @file
805
+ end
806
+ end
807
+
808
+ context "Assigning an attachment with post_process hooks" do
809
+ before do
810
+ rebuild_class styles: { something: "100x100#" }
811
+ Dummy.class_eval do
812
+ before_avatar_post_process :do_before_avatar
813
+ after_avatar_post_process :do_after_avatar
814
+ before_post_process :do_before_all
815
+ after_post_process :do_after_all
816
+ def do_before_avatar; end
817
+ def do_after_avatar; end
818
+ def do_before_all; end
819
+ def do_after_all; end
820
+ end
821
+ @file = StringIO.new(".")
822
+ @file.stubs(:to_tempfile).returns(@file)
823
+ @dummy = Dummy.new
824
+ Paperclip::Thumbnail.stubs(:make).returns(@file)
825
+ @attachment = @dummy.avatar
826
+ end
827
+
828
+ it "calls the defined callbacks when assigned" do
829
+ @dummy.expects(:do_before_avatar).with()
830
+ @dummy.expects(:do_after_avatar).with()
831
+ @dummy.expects(:do_before_all).with()
832
+ @dummy.expects(:do_after_all).with()
833
+ Paperclip::Thumbnail.expects(:make).returns(@file)
834
+ @dummy.avatar = @file
835
+ end
836
+
837
+ it "does not cancel the processing if a before_post_process returns nil" do
838
+ @dummy.expects(:do_before_avatar).with().returns(nil)
839
+ @dummy.expects(:do_after_avatar).with()
840
+ @dummy.expects(:do_before_all).with().returns(nil)
841
+ @dummy.expects(:do_after_all).with()
842
+ Paperclip::Thumbnail.expects(:make).returns(@file)
843
+ @dummy.avatar = @file
844
+ end
845
+
846
+ it "cancels the processing if a before_post_process returns false" do
847
+ @dummy.expects(:do_before_avatar).never
848
+ @dummy.expects(:do_after_avatar).never
849
+ @dummy.expects(:do_before_all).with().returns(false)
850
+ @dummy.expects(:do_after_all)
851
+ Paperclip::Thumbnail.expects(:make).never
852
+ @dummy.avatar = @file
853
+ end
854
+
855
+ it "cancels the processing if a before_avatar_post_process returns false" do
856
+ @dummy.expects(:do_before_avatar).with().returns(false)
857
+ @dummy.expects(:do_after_avatar)
858
+ @dummy.expects(:do_before_all).with().returns(true)
859
+ @dummy.expects(:do_after_all)
860
+ Paperclip::Thumbnail.expects(:make).never
861
+ @dummy.avatar = @file
862
+ end
863
+ end
864
+
865
+ context "Assigning an attachment" do
866
+ before do
867
+ rebuild_model styles: { something: "100x100#" }
868
+ @file = File.new(fixture_file("5k.png"), "rb")
869
+ @dummy = Dummy.new
870
+ @dummy.avatar = @file
871
+ end
872
+
873
+ it "strips whitespace from original_filename field" do
874
+ assert_equal "5k.png", @dummy.avatar.original_filename
875
+ end
876
+
877
+ it "strips whitespace from content_type field" do
878
+ assert_equal "image/png", @dummy.avatar.instance.avatar_content_type
879
+ end
880
+ end
881
+
882
+ context "Assigning an attachment" do
883
+ before do
884
+ rebuild_model styles: { something: "100x100#" }
885
+ @file = File.new(fixture_file("5k.png"), "rb")
886
+ @dummy = Dummy.new
887
+ @dummy.avatar = @file
888
+ end
889
+
890
+ it "makes sure the content_type is a string" do
891
+ assert_equal "image/png", @dummy.avatar.instance.avatar_content_type
892
+ end
893
+ end
894
+
895
+ context "Attachment with strange letters" do
896
+ before do
897
+ rebuild_model
898
+ @file = File.new(fixture_file("5k.png"), "rb")
899
+ @file.stubs(:original_filename).returns("sheep_say_bæ.png")
900
+ @dummy = Dummy.new
901
+ @dummy.avatar = @file
902
+ end
903
+
904
+ it "does not remove strange letters" do
905
+ assert_equal "sheep_say_bæ.png", @dummy.avatar.original_filename
906
+ end
907
+ end
908
+
909
+ context "Attachment with reserved filename" do
910
+ before do
911
+ rebuild_model
912
+ @file = Tempfile.new(["filename","png"])
913
+ end
914
+
915
+ after do
916
+ @file.unlink
917
+ end
918
+
919
+ context "with default configuration" do
920
+ "&$+,/:;=?@<>[]{}|\^~%# ".split(//).each do |character|
921
+ context "with character #{character}" do
922
+
923
+ context "at beginning of filename" do
924
+ before do
925
+ @file.stubs(:original_filename).returns("#{character}filename.png")
926
+ @dummy = Dummy.new
927
+ @dummy.avatar = @file
928
+ end
929
+
930
+ it "converts special character into underscore" do
931
+ assert_equal "_filename.png", @dummy.avatar.original_filename
932
+ end
933
+ end
934
+
935
+ context "at end of filename" do
936
+ before do
937
+ @file.stubs(:original_filename).returns("filename.png#{character}")
938
+ @dummy = Dummy.new
939
+ @dummy.avatar = @file
940
+ end
941
+
942
+ it "converts special character into underscore" do
943
+ assert_equal "filename.png_", @dummy.avatar.original_filename
944
+ end
945
+ end
946
+
947
+ context "in the middle of filename" do
948
+ before do
949
+ @file.stubs(:original_filename).returns("file#{character}name.png")
950
+ @dummy = Dummy.new
951
+ @dummy.avatar = @file
952
+ end
953
+
954
+ it "converts special character into underscore" do
955
+ assert_equal "file_name.png", @dummy.avatar.original_filename
956
+ end
957
+ end
958
+
959
+ end
960
+ end
961
+ end
962
+
963
+ context "with specified regexp replacement" do
964
+ before do
965
+ @old_defaults = Paperclip::Attachment.default_options.dup
966
+ end
967
+
968
+ after do
969
+ Paperclip::Attachment.default_options.merge! @old_defaults
970
+ end
971
+
972
+ context 'as another regexp' do
973
+ before do
974
+ Paperclip::Attachment.default_options.merge! restricted_characters: /o/
975
+
976
+ @file.stubs(:original_filename).returns("goood.png")
977
+ @dummy = Dummy.new
978
+ @dummy.avatar = @file
979
+ end
980
+
981
+ it "matches and converts that character" do
982
+ assert_equal "g___d.png", @dummy.avatar.original_filename
983
+ end
984
+ end
985
+
986
+ context 'as nil' do
987
+ before do
988
+ Paperclip::Attachment.default_options.merge! restricted_characters: nil
989
+
990
+ @file.stubs(:original_filename).returns("goood.png")
991
+ @dummy = Dummy.new
992
+ @dummy.avatar = @file
993
+ end
994
+
995
+ it "ignores and returns the original file name" do
996
+ assert_equal "goood.png", @dummy.avatar.original_filename
997
+ end
998
+ end
999
+ end
1000
+
1001
+ context 'with specified cleaner' do
1002
+ before do
1003
+ @old_defaults = Paperclip::Attachment.default_options.dup
1004
+ end
1005
+
1006
+ after do
1007
+ Paperclip::Attachment.default_options.merge! @old_defaults
1008
+ end
1009
+
1010
+ it 'calls the given proc and take the result as cleaned filename' do
1011
+ Paperclip::Attachment.default_options[:filename_cleaner] = lambda do |str|
1012
+ "from_proc_#{str}"
1013
+ end
1014
+
1015
+ @file.stubs(:original_filename).returns("goood.png")
1016
+ @dummy = Dummy.new
1017
+ @dummy.avatar = @file
1018
+ assert_equal "from_proc_goood.png", @dummy.avatar.original_filename
1019
+ end
1020
+
1021
+ it 'calls the given object and take the result as the cleaned filename' do
1022
+ class MyCleaner
1023
+ def call(filename)
1024
+ "foo"
1025
+ end
1026
+ end
1027
+ Paperclip::Attachment.default_options[:filename_cleaner] = MyCleaner.new
1028
+
1029
+ @file.stubs(:original_filename).returns("goood.png")
1030
+ @dummy = Dummy.new
1031
+ @dummy.avatar = @file
1032
+ assert_equal "foo", @dummy.avatar.original_filename
1033
+ end
1034
+ end
1035
+ end
1036
+
1037
+ context "Attachment with uppercase extension and a default style" do
1038
+ before do
1039
+ @old_defaults = Paperclip::Attachment.default_options.dup
1040
+ Paperclip::Attachment.default_options.merge!({
1041
+ path: ":rails_root/:attachment/:class/:style/:id/:basename.:extension"
1042
+ })
1043
+ FileUtils.rm_rf("tmp")
1044
+ rebuild_model styles: { large: ["400x400", :jpg],
1045
+ medium: ["100x100", :jpg],
1046
+ small: ["32x32#", :jpg]},
1047
+ default_style: :small
1048
+ @instance = Dummy.new
1049
+ @instance.stubs(:id).returns 123
1050
+ @file = File.new(fixture_file("uppercase.PNG"), 'rb')
1051
+
1052
+ @attachment = @instance.avatar
1053
+
1054
+ now = Time.now
1055
+ Time.stubs(:now).returns(now)
1056
+ @attachment.assign(@file)
1057
+ @attachment.save
1058
+ end
1059
+
1060
+ after do
1061
+ @file.close
1062
+ Paperclip::Attachment.default_options.merge!(@old_defaults)
1063
+ end
1064
+
1065
+ it "has matching to_s and url methods" do
1066
+ assert_equal @attachment.to_s, @attachment.url
1067
+ assert_equal @attachment.to_s(:small), @attachment.url(:small)
1068
+ end
1069
+
1070
+ it "has matching expiring_url and url methods when using the filesystem storage" do
1071
+ assert_equal @attachment.expiring_url, @attachment.url
1072
+ end
1073
+ end
1074
+
1075
+ context "An attachment" do
1076
+ before do
1077
+ @old_defaults = Paperclip::Attachment.default_options.dup
1078
+ Paperclip::Attachment.default_options.merge!({
1079
+ path: ":rails_root/:attachment/:class/:style/:id/:basename.:extension"
1080
+ })
1081
+ FileUtils.rm_rf("tmp")
1082
+ rebuild_model
1083
+ @instance = Dummy.new
1084
+ @instance.stubs(:id).returns 123
1085
+ # @attachment = Paperclip::Attachment.new(:avatar, @instance)
1086
+ @attachment = @instance.avatar
1087
+ @file = File.new(fixture_file("5k.png"), 'rb')
1088
+ end
1089
+
1090
+ after do
1091
+ @file.close
1092
+ Paperclip::Attachment.default_options.merge!(@old_defaults)
1093
+ end
1094
+
1095
+ it "raises if there are not the correct columns when you try to assign" do
1096
+ @other_attachment = Paperclip::Attachment.new(:not_here, @instance)
1097
+ assert_raises(Paperclip::Error) do
1098
+ @other_attachment.assign(@file)
1099
+ end
1100
+ end
1101
+
1102
+ it 'clears out the previous assignment when assigned nil' do
1103
+ @attachment.assign(@file)
1104
+ @attachment.queued_for_write[:original]
1105
+ @attachment.assign(nil)
1106
+ assert_nil @attachment.queued_for_write[:original]
1107
+ end
1108
+
1109
+ it 'does not do anything when it is assigned an empty string' do
1110
+ @attachment.assign(@file)
1111
+ original_file = @attachment.queued_for_write[:original]
1112
+ @attachment.assign("")
1113
+ assert_equal original_file, @attachment.queued_for_write[:original]
1114
+ end
1115
+
1116
+ it "returns nil as path when no file assigned" do
1117
+ assert_equal nil, @attachment.path
1118
+ assert_equal nil, @attachment.path(:blah)
1119
+ end
1120
+
1121
+ context "with a file assigned but not saved yet" do
1122
+ it "clears out any attached files" do
1123
+ @attachment.assign(@file)
1124
+ assert !@attachment.queued_for_write.blank?
1125
+ @attachment.clear
1126
+ assert @attachment.queued_for_write.blank?
1127
+ end
1128
+ end
1129
+
1130
+ context "with a file assigned in the database" do
1131
+ before do
1132
+ @attachment.stubs(:instance_read).with(:file_name).returns("5k.png")
1133
+ @attachment.stubs(:instance_read).with(:content_type).returns("image/png")
1134
+ @attachment.stubs(:instance_read).with(:file_size).returns(12345)
1135
+ dtnow = DateTime.now
1136
+ @now = Time.now
1137
+ Time.stubs(:now).returns(@now)
1138
+ @attachment.stubs(:instance_read).with(:updated_at).returns(dtnow)
1139
+ end
1140
+
1141
+ it "returns the proper path when filename has a single .'s" do
1142
+ assert_equal File.expand_path("tmp/avatars/dummies/original/#{@instance.id}/5k.png"), File.expand_path(@attachment.path)
1143
+ end
1144
+
1145
+ it "returns the proper path when filename has multiple .'s" do
1146
+ @attachment.stubs(:instance_read).with(:file_name).returns("5k.old.png")
1147
+ assert_equal File.expand_path("tmp/avatars/dummies/original/#{@instance.id}/5k.old.png"), File.expand_path(@attachment.path)
1148
+ end
1149
+
1150
+ context "when expecting three styles" do
1151
+ before do
1152
+ rebuild_class styles: {
1153
+ large: ["400x400", :png],
1154
+ medium: ["100x100", :gif],
1155
+ small: ["32x32#", :jpg]
1156
+ }
1157
+ @instance = Dummy.new
1158
+ @instance.stubs(:id).returns 123
1159
+ @file = File.new(fixture_file("5k.png"), 'rb')
1160
+ @attachment = @instance.avatar
1161
+ end
1162
+
1163
+ context "and assigned a file" do
1164
+ before do
1165
+ now = Time.now
1166
+ Time.stubs(:now).returns(now)
1167
+ @attachment.assign(@file)
1168
+ end
1169
+
1170
+ it "is dirty" do
1171
+ assert @attachment.dirty?
1172
+ end
1173
+
1174
+ context "and saved" do
1175
+ before do
1176
+ @attachment.save
1177
+ end
1178
+
1179
+ it "commits the files to disk" do
1180
+ [:large, :medium, :small].each do |style|
1181
+ expect(@attachment.path(style)).to exist
1182
+ end
1183
+ end
1184
+
1185
+ it "saves the files as the right formats and sizes" do
1186
+ [[:large, 400, 61, "PNG"],
1187
+ [:medium, 100, 15, "GIF"],
1188
+ [:small, 32, 32, "JPEG"]].each do |style|
1189
+ cmd = %Q[identify -format "%w %h %b %m" "#{@attachment.path(style.first)}"]
1190
+ out = `#{cmd}`
1191
+ width, height, _size, format = out.split(" ")
1192
+ assert_equal style[1].to_s, width.to_s
1193
+ assert_equal style[2].to_s, height.to_s
1194
+ assert_equal style[3].to_s, format.to_s
1195
+ end
1196
+ end
1197
+
1198
+ context "and trying to delete" do
1199
+ before do
1200
+ @existing_names = @attachment.styles.keys.collect do |style|
1201
+ @attachment.path(style)
1202
+ end
1203
+ end
1204
+
1205
+ it "deletes the files after assigning nil" do
1206
+ @attachment.expects(:instance_write).with(:file_name, nil)
1207
+ @attachment.expects(:instance_write).with(:content_type, nil)
1208
+ @attachment.expects(:instance_write).with(:file_size, nil)
1209
+ @attachment.expects(:instance_write).with(:fingerprint, nil)
1210
+ @attachment.expects(:instance_write).with(:updated_at, nil)
1211
+ @attachment.assign nil
1212
+ @attachment.save
1213
+ @existing_names.each{|f| assert_file_not_exists(f) }
1214
+ end
1215
+
1216
+ it "deletes the files when you call #clear and #save" do
1217
+ @attachment.expects(:instance_write).with(:file_name, nil)
1218
+ @attachment.expects(:instance_write).with(:content_type, nil)
1219
+ @attachment.expects(:instance_write).with(:file_size, nil)
1220
+ @attachment.expects(:instance_write).with(:fingerprint, nil)
1221
+ @attachment.expects(:instance_write).with(:updated_at, nil)
1222
+ @attachment.clear
1223
+ @attachment.save
1224
+ @existing_names.each{|f| assert_file_not_exists(f) }
1225
+ end
1226
+
1227
+ it "deletes the files when you call #delete" do
1228
+ @attachment.expects(:instance_write).with(:file_name, nil)
1229
+ @attachment.expects(:instance_write).with(:content_type, nil)
1230
+ @attachment.expects(:instance_write).with(:file_size, nil)
1231
+ @attachment.expects(:instance_write).with(:fingerprint, nil)
1232
+ @attachment.expects(:instance_write).with(:updated_at, nil)
1233
+ @attachment.destroy
1234
+ @existing_names.each{|f| assert_file_not_exists(f) }
1235
+ end
1236
+
1237
+ context "when keeping old files" do
1238
+ before do
1239
+ @attachment.options[:keep_old_files] = true
1240
+ end
1241
+
1242
+ it "keeps the files after assigning nil" do
1243
+ @attachment.expects(:instance_write).with(:file_name, nil)
1244
+ @attachment.expects(:instance_write).with(:content_type, nil)
1245
+ @attachment.expects(:instance_write).with(:file_size, nil)
1246
+ @attachment.expects(:instance_write).with(:fingerprint, nil)
1247
+ @attachment.expects(:instance_write).with(:updated_at, nil)
1248
+ @attachment.assign nil
1249
+ @attachment.save
1250
+ @existing_names.each{|f| assert_file_exists(f) }
1251
+ end
1252
+
1253
+ it "keeps the files when you call #clear and #save" do
1254
+ @attachment.expects(:instance_write).with(:file_name, nil)
1255
+ @attachment.expects(:instance_write).with(:content_type, nil)
1256
+ @attachment.expects(:instance_write).with(:file_size, nil)
1257
+ @attachment.expects(:instance_write).with(:fingerprint, nil)
1258
+ @attachment.expects(:instance_write).with(:updated_at, nil)
1259
+ @attachment.clear
1260
+ @attachment.save
1261
+ @existing_names.each{|f| assert_file_exists(f) }
1262
+ end
1263
+
1264
+ it "keeps the files when you call #delete" do
1265
+ @attachment.expects(:instance_write).with(:file_name, nil)
1266
+ @attachment.expects(:instance_write).with(:content_type, nil)
1267
+ @attachment.expects(:instance_write).with(:file_size, nil)
1268
+ @attachment.expects(:instance_write).with(:fingerprint, nil)
1269
+ @attachment.expects(:instance_write).with(:updated_at, nil)
1270
+ @attachment.destroy
1271
+ @existing_names.each{|f| assert_file_exists(f) }
1272
+ end
1273
+ end
1274
+ end
1275
+ end
1276
+ end
1277
+ end
1278
+ end
1279
+
1280
+ context "when trying a nonexistant storage type" do
1281
+ before do
1282
+ rebuild_model storage: :not_here
1283
+ end
1284
+
1285
+ it "is not able to find the module" do
1286
+ assert_raises(Paperclip::Errors::StorageMethodNotFound){ Dummy.new.avatar }
1287
+ end
1288
+ end
1289
+ end
1290
+
1291
+ context "An attachment with only a avatar_file_name column" do
1292
+ before do
1293
+ ActiveRecord::Base.connection.create_table :dummies, force: true do |table|
1294
+ table.column :avatar_file_name, :string
1295
+ end
1296
+ rebuild_class
1297
+ @dummy = Dummy.new
1298
+ @file = File.new(fixture_file("5k.png"), 'rb')
1299
+ end
1300
+
1301
+ after { @file.close }
1302
+
1303
+ it "does not error when assigned an attachment" do
1304
+ assert_nothing_raised { @dummy.avatar = @file }
1305
+ end
1306
+
1307
+ it "does not return the time when sent #avatar_updated_at" do
1308
+ @dummy.avatar = @file
1309
+ assert_nil @dummy.avatar.updated_at
1310
+ end
1311
+
1312
+ it "returns the right value when sent #avatar_file_size" do
1313
+ @dummy.avatar = @file
1314
+ assert_equal File.size(@file), @dummy.avatar.size
1315
+ end
1316
+
1317
+ context "and avatar_created_at column" do
1318
+ before do
1319
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_created_at, :timestamp
1320
+ rebuild_class
1321
+ @dummy = Dummy.new
1322
+ end
1323
+
1324
+ it "does not error when assigned an attachment" do
1325
+ assert_nothing_raised { @dummy.avatar = @file }
1326
+ end
1327
+
1328
+ it "returns the creation time when sent #avatar_created_at" do
1329
+ now = Time.now
1330
+ Time.stubs(:now).returns(now)
1331
+ @dummy.avatar = @file
1332
+ assert_equal now.to_i, @dummy.avatar.created_at
1333
+ end
1334
+
1335
+ it "returns the creation time when sent #avatar_created_at and the entry has been updated" do
1336
+ creation = 2.hours.ago
1337
+ now = Time.now
1338
+ Time.stubs(:now).returns(creation)
1339
+ @dummy.avatar = @file
1340
+ Time.stubs(:now).returns(now)
1341
+ @dummy.avatar = @file
1342
+ assert_equal creation.to_i, @dummy.avatar.created_at
1343
+ assert_not_equal now.to_i, @dummy.avatar.created_at
1344
+ end
1345
+
1346
+ it "sets changed? to true on attachment assignment" do
1347
+ @dummy.avatar = @file
1348
+ @dummy.save!
1349
+ @dummy.avatar = @file
1350
+ assert @dummy.changed?
1351
+ end
1352
+ end
1353
+
1354
+ context "and avatar_updated_at column" do
1355
+ before do
1356
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_updated_at, :timestamp
1357
+ rebuild_class
1358
+ @dummy = Dummy.new
1359
+ end
1360
+
1361
+ it "does not error when assigned an attachment" do
1362
+ assert_nothing_raised { @dummy.avatar = @file }
1363
+ end
1364
+
1365
+ it "returns the right value when sent #avatar_updated_at" do
1366
+ now = Time.now
1367
+ Time.stubs(:now).returns(now)
1368
+ @dummy.avatar = @file
1369
+ assert_equal now.to_i, @dummy.avatar.updated_at
1370
+ end
1371
+ end
1372
+
1373
+ it "does not calculate fingerprint" do
1374
+ Digest::MD5.stubs(:file)
1375
+ @dummy.avatar = @file
1376
+ expect(Digest::MD5).to have_received(:file).never
1377
+ end
1378
+
1379
+ it "does not assign fingerprint" do
1380
+ @dummy.avatar = @file
1381
+ assert_nil @dummy.avatar.fingerprint
1382
+ end
1383
+
1384
+ context "and avatar_content_type column" do
1385
+ before do
1386
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_content_type, :string
1387
+ rebuild_class
1388
+ @dummy = Dummy.new
1389
+ end
1390
+
1391
+ it "does not error when assigned an attachment" do
1392
+ assert_nothing_raised { @dummy.avatar = @file }
1393
+ end
1394
+
1395
+ it "returns the right value when sent #avatar_content_type" do
1396
+ @dummy.avatar = @file
1397
+ assert_equal "image/png", @dummy.avatar.content_type
1398
+ end
1399
+ end
1400
+
1401
+ context "and avatar_file_size column" do
1402
+ before do
1403
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_file_size, :integer
1404
+ rebuild_class
1405
+ @dummy = Dummy.new
1406
+ end
1407
+
1408
+ it "does not error when assigned an attachment" do
1409
+ assert_nothing_raised { @dummy.avatar = @file }
1410
+ end
1411
+
1412
+ it "returns the right value when sent #avatar_file_size" do
1413
+ @dummy.avatar = @file
1414
+ assert_equal File.size(@file), @dummy.avatar.size
1415
+ end
1416
+
1417
+ it "returns the right value when saved, reloaded, and sent #avatar_file_size" do
1418
+ @dummy.avatar = @file
1419
+ @dummy.save
1420
+ @dummy = Dummy.find(@dummy.id)
1421
+ assert_equal File.size(@file), @dummy.avatar.size
1422
+ end
1423
+ end
1424
+
1425
+ context "and avatar_fingerprint column" do
1426
+ before do
1427
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_fingerprint, :string
1428
+ rebuild_class
1429
+ @dummy = Dummy.new
1430
+ end
1431
+
1432
+ it "does not error when assigned an attachment" do
1433
+ assert_nothing_raised { @dummy.avatar = @file }
1434
+ end
1435
+
1436
+ it "returns the right value when sent #avatar_fingerprint" do
1437
+ @dummy.avatar = @file
1438
+ assert_equal 'aec488126c3b33c08a10c3fa303acf27', @dummy.avatar_fingerprint
1439
+ end
1440
+
1441
+ it "returns the right value when saved, reloaded, and sent #avatar_fingerprint" do
1442
+ @dummy.avatar = @file
1443
+ @dummy.save
1444
+ @dummy = Dummy.find(@dummy.id)
1445
+ assert_equal 'aec488126c3b33c08a10c3fa303acf27', @dummy.avatar_fingerprint
1446
+ end
1447
+ end
1448
+ end
1449
+
1450
+ context "an attachment with delete_file option set to false" do
1451
+ before do
1452
+ rebuild_model preserve_files: true
1453
+ @dummy = Dummy.new
1454
+ @file = File.new(fixture_file("5k.png"), 'rb')
1455
+ @dummy.avatar = @file
1456
+ @dummy.save!
1457
+ @attachment = @dummy.avatar
1458
+ @path = @attachment.path
1459
+ end
1460
+
1461
+ after { @file.close }
1462
+
1463
+ it "does not delete the files from storage when attachment is destroyed" do
1464
+ @attachment.destroy
1465
+ assert_file_exists(@path)
1466
+ end
1467
+
1468
+ it "clears out attachment data when attachment is destroyed" do
1469
+ @attachment.destroy
1470
+ assert !@attachment.exists?
1471
+ assert_nil @dummy.avatar_file_name
1472
+ end
1473
+
1474
+ it "does not delete the file when model is destroyed" do
1475
+ @dummy.destroy
1476
+ assert_file_exists(@path)
1477
+ end
1478
+ end
1479
+
1480
+ context "An attached file" do
1481
+ before do
1482
+ rebuild_model
1483
+ @dummy = Dummy.new
1484
+ @file = File.new(fixture_file("5k.png"), 'rb')
1485
+ @dummy.avatar = @file
1486
+ @dummy.save!
1487
+ @attachment = @dummy.avatar
1488
+ @path = @attachment.path
1489
+ end
1490
+
1491
+ after { @file.close }
1492
+
1493
+ it "is not deleted when the model fails to destroy" do
1494
+ @dummy.stubs(:destroy).raises(Exception)
1495
+
1496
+ assert_raises Exception do
1497
+ @dummy.destroy
1498
+ end
1499
+
1500
+ assert_file_exists(@path)
1501
+ end
1502
+
1503
+ it "is deleted when the model is destroyed" do
1504
+ @dummy.destroy
1505
+ assert_file_not_exists(@path)
1506
+ end
1507
+
1508
+ it "is not deleted when transaction rollbacks after model is destroyed" do
1509
+ ActiveRecord::Base.transaction do
1510
+ @dummy.destroy
1511
+ raise ActiveRecord::Rollback
1512
+ end
1513
+
1514
+ assert_file_exists(@path)
1515
+ end
1516
+ end
1517
+ end