media_attachment_spec.rb 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. # frozen_string_literal: true
  2. require 'rails_helper'
  3. RSpec.describe MediaAttachment, paperclip_processing: true do
  4. describe 'local?' do
  5. subject { media_attachment.local? }
  6. let(:media_attachment) { Fabricate(:media_attachment, 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) { Fabricate(:media_attachment, 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(:media_attachment, shortcode: shortcode) }
  50. let(:shortcode) { nil }
  51. context 'when media attachment has a shortcode' do
  52. let(:shortcode) { 'foo' }
  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. it 'returns string representation of id' do
  60. expect(media_attachment.to_param).to eq media_attachment.id.to_s
  61. end
  62. end
  63. end
  64. shared_examples 'static 600x400 image' do |content_type, extension|
  65. after do
  66. media.destroy
  67. end
  68. it 'saves media attachment' do
  69. expect(media.persisted?).to be true
  70. expect(media.file).to_not be_nil
  71. end
  72. it 'completes processing' do
  73. expect(media.processing_complete?).to be true
  74. end
  75. it 'sets type' do
  76. expect(media.type).to eq 'image'
  77. end
  78. it 'sets content type' do
  79. expect(media.file_content_type).to eq content_type
  80. end
  81. it 'sets file extension' do
  82. expect(media.file_file_name).to end_with extension
  83. end
  84. it 'strips original file name' do
  85. expect(media.file_file_name).to_not start_with '600x400'
  86. end
  87. it 'sets meta for original' do
  88. expect(media.file.meta['original']['width']).to eq 600
  89. expect(media.file.meta['original']['height']).to eq 400
  90. expect(media.file.meta['original']['aspect']).to eq 1.5
  91. end
  92. it 'sets meta for thumbnail' do
  93. expect(media.file.meta['small']['width']).to eq 588
  94. expect(media.file.meta['small']['height']).to eq 392
  95. expect(media.file.meta['small']['aspect']).to eq 1.5
  96. end
  97. end
  98. describe 'jpeg' do
  99. let(:media) { described_class.create(account: Fabricate(:account), file: attachment_fixture('600x400.jpeg')) }
  100. it_behaves_like 'static 600x400 image', 'image/jpeg', '.jpeg'
  101. end
  102. describe 'png' do
  103. let(:media) { described_class.create(account: Fabricate(:account), file: attachment_fixture('600x400.png')) }
  104. it_behaves_like 'static 600x400 image', 'image/png', '.png'
  105. end
  106. describe 'webp' do
  107. let(:media) { described_class.create(account: Fabricate(:account), file: attachment_fixture('600x400.webp')) }
  108. it_behaves_like 'static 600x400 image', 'image/webp', '.webp'
  109. end
  110. describe 'avif' do
  111. let(:media) { described_class.create(account: Fabricate(:account), file: attachment_fixture('600x400.avif')) }
  112. it_behaves_like 'static 600x400 image', 'image/jpeg', '.jpeg'
  113. end
  114. describe 'heic' do
  115. let(:media) { described_class.create(account: Fabricate(:account), file: attachment_fixture('600x400.heic')) }
  116. it_behaves_like 'static 600x400 image', 'image/jpeg', '.jpeg'
  117. end
  118. describe 'base64-encoded image' do
  119. let(:base64_attachment) { "data:image/jpeg;base64,#{Base64.encode64(attachment_fixture('600x400.jpeg').read)}" }
  120. let(:media) { described_class.create(account: Fabricate(:account), file: base64_attachment) }
  121. it_behaves_like 'static 600x400 image', 'image/jpeg', '.jpeg'
  122. end
  123. describe 'animated gif' do
  124. let(:media) { described_class.create(account: Fabricate(:account), file: attachment_fixture('avatar.gif')) }
  125. it 'sets type to gifv' do
  126. expect(media.type).to eq 'gifv'
  127. end
  128. it 'converts original file to mp4' do
  129. expect(media.file_content_type).to eq 'video/mp4'
  130. end
  131. it 'sets meta' do
  132. expect(media.file.meta['original']['width']).to eq 128
  133. expect(media.file.meta['original']['height']).to eq 128
  134. end
  135. end
  136. describe 'static gif' do
  137. fixtures = [
  138. { filename: 'attachment.gif', width: 600, height: 400, aspect: 1.5 },
  139. { filename: 'mini-static.gif', width: 32, height: 32, aspect: 1.0 },
  140. ]
  141. fixtures.each do |fixture|
  142. context fixture[:filename] do
  143. let(:media) { described_class.create(account: Fabricate(:account), file: attachment_fixture(fixture[:filename])) }
  144. it 'sets type to image' do
  145. expect(media.type).to eq 'image'
  146. end
  147. it 'leaves original file as-is' do
  148. expect(media.file_content_type).to eq 'image/gif'
  149. end
  150. it 'sets meta' do
  151. expect(media.file.meta['original']['width']).to eq fixture[:width]
  152. expect(media.file.meta['original']['height']).to eq fixture[:height]
  153. expect(media.file.meta['original']['aspect']).to eq fixture[:aspect]
  154. end
  155. end
  156. end
  157. end
  158. describe 'ogg with cover art' do
  159. let(:media) { described_class.create(account: Fabricate(:account), file: attachment_fixture('boop.ogg')) }
  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 'extracts colors from thumbnail' do
  170. expect(media.file.meta['colors']['background']).to eq '#3088d4'
  171. end
  172. it 'gives the file a random name' do
  173. expect(media.file_file_name).to_not eq 'boop.ogg'
  174. end
  175. end
  176. describe 'mp3 with large cover art' do
  177. let(:media) { described_class.create(account: Fabricate(:account), file: attachment_fixture('boop.mp3')) }
  178. it 'detects it as an audio file' do
  179. expect(media.type).to eq 'audio'
  180. end
  181. it 'sets meta for the duration' do
  182. expect(media.file.meta['original']['duration']).to be_within(0.05).of(0.235102)
  183. end
  184. it 'extracts thumbnail' do
  185. expect(media.thumbnail.present?).to be true
  186. end
  187. it 'gives the file a random name' do
  188. expect(media.file_file_name).to_not eq 'boop.mp3'
  189. end
  190. end
  191. it 'is invalid without file' do
  192. media = described_class.new(account: Fabricate(:account))
  193. expect(media.valid?).to be false
  194. end
  195. describe 'size limit validation' do
  196. it 'rejects video files that are too large' do
  197. stub_const 'MediaAttachment::IMAGE_LIMIT', 100.megabytes
  198. stub_const 'MediaAttachment::VIDEO_LIMIT', 1.kilobyte
  199. expect { described_class.create!(account: Fabricate(:account), file: attachment_fixture('attachment.webm')) }.to raise_error(ActiveRecord::RecordInvalid)
  200. end
  201. it 'accepts video files that are small enough' do
  202. stub_const 'MediaAttachment::IMAGE_LIMIT', 1.kilobyte
  203. stub_const 'MediaAttachment::VIDEO_LIMIT', 100.megabytes
  204. media = described_class.create!(account: Fabricate(:account), file: attachment_fixture('attachment.webm'))
  205. expect(media.valid?).to be true
  206. end
  207. it 'rejects image files that are too large' do
  208. stub_const 'MediaAttachment::IMAGE_LIMIT', 1.kilobyte
  209. stub_const 'MediaAttachment::VIDEO_LIMIT', 100.megabytes
  210. expect { described_class.create!(account: Fabricate(:account), file: attachment_fixture('attachment.jpg')) }.to raise_error(ActiveRecord::RecordInvalid)
  211. end
  212. it 'accepts image files that are small enough' do
  213. stub_const 'MediaAttachment::IMAGE_LIMIT', 100.megabytes
  214. stub_const 'MediaAttachment::VIDEO_LIMIT', 1.kilobyte
  215. media = described_class.create!(account: Fabricate(:account), file: attachment_fixture('attachment.jpg'))
  216. expect(media.valid?).to be true
  217. end
  218. end
  219. end