diff --git a/lib/mini_paperclip/validators/file_size_validator.rb b/lib/mini_paperclip/validators/file_size_validator.rb index 944fce0..ae75eed 100644 --- a/lib/mini_paperclip/validators/file_size_validator.rb +++ b/lib/mini_paperclip/validators/file_size_validator.rb @@ -14,8 +14,32 @@ def validate_each(record, attribute, value) record.errors.add(attachment_file_size_name, :less_than, count: count) end end + + if check_value = options[:greater_than] + unless attachment_file_size > check_value + count = ActiveSupport::NumberHelper.number_to_human_size(check_value) + record.errors.add(attribute, :greater_than, count: count) + record.errors.add(attachment_file_size_name, :greater_than, count: count) + end + end + + if check_value = (options[:within] || options[:in]) + unless check_value.include?(attachment_file_size) + record.errors.add(attribute, :within, count: formatted_range(check_value)) + record.errors.add(attachment_file_size_name, :within, count: formatted_range(check_value)) + end + end end end + + private + + def formatted_range(range) + dots = range.exclude_end? ? "..." : ".." + first = ActiveSupport::NumberHelper.number_to_human_size(range.begin) + last = ActiveSupport::NumberHelper.number_to_human_size(range.last) + "#{first}#{dots}#{last}" + end end end end diff --git a/spec/mini_paperclip/validators/file_size_validator_spec.rb b/spec/mini_paperclip/validators/file_size_validator_spec.rb index 04597f6..5352385 100644 --- a/spec/mini_paperclip/validators/file_size_validator_spec.rb +++ b/spec/mini_paperclip/validators/file_size_validator_spec.rb @@ -1,28 +1,135 @@ RSpec.describe MiniPaperclip::Validators::FileSizeValidator do - it "#validate_each with valid file size" do - validator = MiniPaperclip::Validators::FileSizeValidator.new( - attributes: :img, - less_than: 1.megabytes, - ) - mock = double('Record') - attachment = double('Attachment') - allow(mock).to receive(:read_attribute_for_validation).with('img_file_size').and_return(1.kilobytes) - expect(mock).to_not receive(:errors) - validator.validate_each(mock, :img, attachment) + describe "less_than" do + it "#validate_each with valid file size" do + validator = MiniPaperclip::Validators::FileSizeValidator.new( + attributes: :img, + less_than: 1.megabytes, + ) + mock = double('Record') + attachment = double('Attachment') + allow(mock).to receive(:read_attribute_for_validation).with('img_file_size').and_return(1.kilobytes) + expect(mock).to_not receive(:errors) + validator.validate_each(mock, :img, attachment) + end + + it "#validate_each with invalid file size" do + validator = MiniPaperclip::Validators::FileSizeValidator.new( + attributes: :img, + less_than: 1.megabytes, + ) + mock = double('Record') + attachment = double('Attachment') + allow(mock).to receive(:read_attribute_for_validation).with('img_file_size').and_return(2.megabytes) + errors_mock = double('Errors') + allow(mock).to receive(:errors).and_return(errors_mock) + expect(errors_mock).to receive(:add).with(:img, :less_than, { count: "1 MB" }) + expect(errors_mock).to receive(:add).with("img_file_size", :less_than, { count: "1 MB" }) + validator.validate_each(mock, :img, attachment) + end + end + + describe "greater_than" do + it "#validate_each with valid file size" do + validator = MiniPaperclip::Validators::FileSizeValidator.new( + attributes: :img, + greater_than: 1.megabytes, + ) + mock = double('Record') + attachment = double('Attachment') + allow(mock).to receive(:read_attribute_for_validation).with('img_file_size').and_return(2.megabytes) + expect(mock).to_not receive(:errors) + validator.validate_each(mock, :img, attachment) + end + + it "#validate_each with invalid file size" do + validator = MiniPaperclip::Validators::FileSizeValidator.new( + attributes: :img, + greater_than: 1.megabytes, + ) + mock = double('Record') + attachment = double('Attachment') + allow(mock).to receive(:read_attribute_for_validation).with('img_file_size').and_return(1.kilobytes) + errors_mock = double('Errors') + allow(mock).to receive(:errors).and_return(errors_mock) + expect(errors_mock).to receive(:add).with(:img, :greater_than, { count: "1 MB" }) + expect(errors_mock).to receive(:add).with("img_file_size", :greater_than, { count: "1 MB" }) + validator.validate_each(mock, :img, attachment) + end + end + + describe "within (1.megabytes..2.megabytes)" do + let(:validator) do + validator = MiniPaperclip::Validators::FileSizeValidator.new( + attributes: :img, + within: 1.megabytes..2.megabytes, + ) + end + + context "valid case" do + [1.megabytes, 1.5.megabytes, 2.megabytes].each do |file_size| + it "returns no error when file size is #{file_size}" do + mock = double('Record') + attachment = double('Attachment') + allow(mock).to receive(:read_attribute_for_validation).with('img_file_size').and_return(file_size) + expect(mock).to_not receive(:errors) + validator.validate_each(mock, :img, attachment) + end + end + end + + context "too large (2.megabytes + 1)" do + it "returns error" do + mock = double('Record') + attachment = double('Attachment') + allow(mock).to receive(:read_attribute_for_validation).with('img_file_size').and_return(2.megabytes + 1) + errors_mock = double('Errors') + allow(mock).to receive(:errors).and_return(errors_mock) + expect(errors_mock).to receive(:add).with(:img, :within, { count: "1 MB..2 MB" }) + expect(errors_mock).to receive(:add).with("img_file_size", :within, { count: "1 MB..2 MB" }) + validator.validate_each(mock, :img, attachment) + end + end + + context "too small (1.megabytes - 1)" do + it "returns error" do + mock = double('Record') + attachment = double('Attachment') + allow(mock).to receive(:read_attribute_for_validation).with('img_file_size').and_return(1.megabytes - 1) + errors_mock = double('Errors') + allow(mock).to receive(:errors).and_return(errors_mock) + expect(errors_mock).to receive(:add).with(:img, :within, { count: "1 MB..2 MB" }) + expect(errors_mock).to receive(:add).with("img_file_size", :within, { count: "1 MB..2 MB" }) + validator.validate_each(mock, :img, attachment) + end + end end - it "#validate_each with invalid file size" do - validator = MiniPaperclip::Validators::FileSizeValidator.new( - attributes: :img, - less_than: 1.megabytes, - ) - mock = double('Record') - attachment = double('Attachment') - allow(mock).to receive(:read_attribute_for_validation).with('img_file_size').and_return(2.megabytes) - errors_mock = double('Errors') - allow(mock).to receive(:errors).and_return(errors_mock) - expect(errors_mock).to receive(:add).with(:img, :less_than, { count: "1 MB" }) - expect(errors_mock).to receive(:add).with("img_file_size", :less_than, { count: "1 MB" }) - validator.validate_each(mock, :img, attachment) + describe "alias 'in' (1.megabytes...3.megabytes)" do + let(:validator) do + validator = MiniPaperclip::Validators::FileSizeValidator.new( + attributes: :img, + in: 1.megabytes...3.megabytes, + ) + end + [1.megabytes, 1.5.megabytes, 3.megabytes - 1 ].each do |file_size| + it "returns no error when file size is #{file_size}" do + mock = double('Record') + attachment = double('Attachment') + allow(mock).to receive(:read_attribute_for_validation).with('img_file_size').and_return(file_size) + expect(mock).to_not receive(:errors) + validator.validate_each(mock, :img, attachment) + end + end + + it "returns error when file size is 3.megebaytes" do + mock = double('Record') + attachment = double('Attachment') + allow(mock).to receive(:read_attribute_for_validation).with('img_file_size').and_return(3.megabytes) + errors_mock = double('Errors') + allow(mock).to receive(:errors).and_return(errors_mock) + expect(errors_mock).to receive(:add).with(:img, :within, { count: "1 MB...3 MB" }) + expect(errors_mock).to receive(:add).with("img_file_size", :within, { count: "1 MB...3 MB" }) + validator.validate_each(mock, :img, attachment) + end end end