media_attachment_spec.rb 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. # frozen_string_literal: true
  2. require 'rails_helper'
  3. RSpec.describe MediaAttachment, :paperclip_processing do
  4. describe 'local?' do
  5. subject { media_attachment.local? }
  6. let(:media_attachment) { described_class.new(remote_url: remote_url) }
  7. context 'when remote_url is blank' do
  8. let(:remote_url) { '' }
  9. it 'returns true' do
  10. expect(subject).to be true
  11. end
  12. end
  13. context 'when remote_url is present' do
  14. let(:remote_url) { 'remote_url' }
  15. it 'returns false' do
  16. expect(subject).to be false
  17. end
  18. end
  19. end
  20. describe 'needs_redownload?' do
  21. subject { media_attachment.needs_redownload? }
  22. let(:media_attachment) { described_class.new(remote_url: remote_url, file: file) }
  23. context 'when file is blank' do
  24. let(:file) { nil }
  25. context 'when remote_url is present' do
  26. let(:remote_url) { 'remote_url' }
  27. it 'returns true' do
  28. expect(subject).to be true
  29. end
  30. end
  31. end
  32. context 'when file is present' do
  33. let(:file) { attachment_fixture('avatar.gif') }
  34. context 'when remote_url is blank' do
  35. let(:remote_url) { '' }
  36. it 'returns false' do
  37. expect(subject).to be false
  38. end
  39. end
  40. context 'when remote_url is present' do
  41. let(:remote_url) { 'remote_url' }
  42. it 'returns true' do
  43. expect(subject).to be false
  44. end
  45. end
  46. end
  47. end
  48. describe '#to_param' do
  49. let(:media_attachment) { Fabricate.build(:media_attachment, shortcode: shortcode, id: id) }
  50. context 'when media attachment has a shortcode' do
  51. let(:shortcode) { 'foo' }
  52. let(:id) { 123 }
  53. it 'returns shortcode' do
  54. expect(media_attachment.to_param).to eq shortcode
  55. end
  56. end
  57. context 'when media attachment does not have a shortcode' do
  58. let(:shortcode) { nil }
  59. let(:id) { 123 }
  60. it 'returns string representation of id' do
  61. expect(media_attachment.to_param).to eq id.to_s
  62. end
  63. end
  64. end
  65. shared_examples 'static 600x400 image' do |content_type, extension|
  66. after do
  67. media.destroy
  68. end
  69. it 'saves media attachment with correct file metadata' do
  70. expect(media.persisted?).to be true
  71. expect(media.file).to_not be_nil
  72. # completes processing
  73. expect(media.processing_complete?).to be true
  74. # sets type
  75. expect(media.type).to eq 'image'
  76. # sets content type
  77. expect(media.file_content_type).to eq content_type
  78. # sets file extension
  79. expect(media.file_file_name).to end_with extension
  80. # Rack::Mime (used by PublicFileServerMiddleware) recognizes file extension
  81. expect(Rack::Mime.mime_type(extension, nil)).to eq content_type
  82. end
  83. it 'saves media attachment with correct size metadata' do
  84. # strips original file name
  85. expect(media.file_file_name).to_not start_with '600x400'
  86. # sets meta for original
  87. expect(media.file.meta['original']['width']).to eq 600
  88. expect(media.file.meta['original']['height']).to eq 400
  89. expect(media.file.meta['original']['aspect']).to eq 1.5
  90. # sets meta for thumbnail
  91. expect(media.file.meta['small']['width']).to eq 588
  92. expect(media.file.meta['small']['height']).to eq 392
  93. expect(media.file.meta['small']['aspect']).to eq 1.5
  94. end
  95. end
  96. describe 'jpeg' do
  97. let(:media) { Fabricate(:media_attachment, file: attachment_fixture('600x400.jpeg')) }
  98. it_behaves_like 'static 600x400 image', 'image/jpeg', '.jpeg'
  99. end
  100. describe 'png' do
  101. let(:media) { Fabricate(:media_attachment, file: attachment_fixture('600x400.png')) }
  102. it_behaves_like 'static 600x400 image', 'image/png', '.png'
  103. end
  104. describe 'webp' do
  105. let(:media) { Fabricate(:media_attachment, file: attachment_fixture('600x400.webp')) }
  106. it_behaves_like 'static 600x400 image', 'image/webp', '.webp'
  107. end
  108. describe 'avif' do
  109. let(:media) { Fabricate(:media_attachment, file: attachment_fixture('600x400.avif')) }
  110. it_behaves_like 'static 600x400 image', 'image/jpeg', '.jpeg'
  111. end
  112. describe 'heic' do
  113. let(:media) { Fabricate(:media_attachment, file: attachment_fixture('600x400.heic')) }
  114. it_behaves_like 'static 600x400 image', 'image/jpeg', '.jpeg'
  115. end
  116. describe 'base64-encoded image' do
  117. let(:base64_attachment) { "data:image/jpeg;base64,#{Base64.encode64(attachment_fixture('600x400.jpeg').read)}" }
  118. let(:media) { Fabricate(:media_attachment, file: base64_attachment) }
  119. it_behaves_like 'static 600x400 image', 'image/jpeg', '.jpeg'
  120. end
  121. describe 'animated gif' do
  122. let(:media) { Fabricate(:media_attachment, file: attachment_fixture('avatar.gif')) }
  123. it 'sets correct file metadata' do
  124. expect(media.type).to eq 'gifv'
  125. expect(media.file_content_type).to eq 'video/mp4'
  126. expect(media.file.meta['original']['width']).to eq 128
  127. expect(media.file.meta['original']['height']).to eq 128
  128. end
  129. end
  130. describe 'static gif' do
  131. fixtures = [
  132. { filename: 'attachment.gif', width: 600, height: 400, aspect: 1.5 },
  133. { filename: 'mini-static.gif', width: 32, height: 32, aspect: 1.0 },
  134. ]
  135. fixtures.each do |fixture|
  136. context fixture[:filename] do
  137. let(:media) { Fabricate(:media_attachment, file: attachment_fixture(fixture[:filename])) }
  138. it 'sets correct file metadata' do
  139. expect(media.type).to eq 'image'
  140. expect(media.file_content_type).to eq 'image/gif'
  141. expect(media.file.meta['original']['width']).to eq fixture[:width]
  142. expect(media.file.meta['original']['height']).to eq fixture[:height]
  143. expect(media.file.meta['original']['aspect']).to eq fixture[:aspect]
  144. end
  145. end
  146. end
  147. end
  148. describe 'ogg with cover art' do
  149. let(:media) { Fabricate(:media_attachment, file: attachment_fixture('boop.ogg')) }
  150. it 'sets correct file metadata' do
  151. expect(media.type).to eq 'audio'
  152. expect(media.file.meta['original']['duration']).to be_within(0.05).of(0.235102)
  153. expect(media.thumbnail.present?).to be true
  154. expect(media.file.meta['colors']['background']).to eq '#3088d4'
  155. expect(media.file_file_name).to_not eq 'boop.ogg'
  156. end
  157. end
  158. describe 'mp3 with large cover art' do
  159. let(:media) { Fabricate(:media_attachment, file: attachment_fixture('boop.mp3')) }
  160. it 'detects it as an audio file' do
  161. expect(media.type).to eq 'audio'
  162. end
  163. it 'sets meta for the duration' do
  164. expect(media.file.meta['original']['duration']).to be_within(0.05).of(0.235102)
  165. end
  166. it 'extracts thumbnail' do
  167. expect(media.thumbnail.present?).to be true
  168. end
  169. it 'gives the file a random name' do
  170. expect(media.file_file_name).to_not eq 'boop.mp3'
  171. end
  172. end
  173. it 'is invalid without file' do
  174. media = described_class.new
  175. expect(media.valid?).to be false
  176. expect(media).to model_have_error_on_field(:file)
  177. end
  178. describe 'size limit validation' do
  179. it 'rejects video files that are too large' do
  180. stub_const 'MediaAttachment::IMAGE_LIMIT', 100.megabytes
  181. stub_const 'MediaAttachment::VIDEO_LIMIT', 1.kilobyte
  182. expect { Fabricate(:media_attachment, file: attachment_fixture('attachment.webm')) }.to raise_error(ActiveRecord::RecordInvalid)
  183. end
  184. it 'accepts video files that are small enough' do
  185. stub_const 'MediaAttachment::IMAGE_LIMIT', 1.kilobyte
  186. stub_const 'MediaAttachment::VIDEO_LIMIT', 100.megabytes
  187. media = Fabricate(:media_attachment, file: attachment_fixture('attachment.webm'))
  188. expect(media.valid?).to be true
  189. end
  190. it 'rejects image files that are too large' do
  191. stub_const 'MediaAttachment::IMAGE_LIMIT', 1.kilobyte
  192. stub_const 'MediaAttachment::VIDEO_LIMIT', 100.megabytes
  193. expect { Fabricate(:media_attachment, file: attachment_fixture('attachment.jpg')) }.to raise_error(ActiveRecord::RecordInvalid)
  194. end
  195. it 'accepts image files that are small enough' do
  196. stub_const 'MediaAttachment::IMAGE_LIMIT', 100.megabytes
  197. stub_const 'MediaAttachment::VIDEO_LIMIT', 1.kilobyte
  198. media = Fabricate(:media_attachment, file: attachment_fixture('attachment.jpg'))
  199. expect(media.valid?).to be true
  200. end
  201. end
  202. end