Skip to content

Commit

Permalink
feature Add file_fixture helper to syntax methods
Browse files Browse the repository at this point in the history
Why:
This is to add simple support to files on factories. This is the
original [issue](#1282).

What:
It is a common behavior to interact with files when creating factories,
and it is used heavily, as demonstrated with the many examples in the
issue, this is a first draft and I would love to see more use-cases to
add to the acceptance test. For the time being we have at least the base
case added.
  • Loading branch information
aledustet committed Jul 12, 2019
1 parent ff1ee46 commit 82b0e30
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 0 deletions.
1 change: 1 addition & 0 deletions lib/factory_bot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
require "factory_bot/linter"
require "factory_bot/version"
require "factory_bot/internal"
require "factory_bot/file_loader"

module FactoryBot
Deprecation = ActiveSupport::Deprecation.new("6.0", "factory_bot")
Expand Down
2 changes: 2 additions & 0 deletions lib/factory_bot/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ class MethodDefinitionError < RuntimeError; end

# Raised when any factory is considered invalid
class InvalidFactoryError < RuntimeError; end

class FileDoesNotExistError < RuntimeError; end
end
39 changes: 39 additions & 0 deletions lib/factory_bot/file_loader.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
require "tempfile"

module FactoryBot
class FileLoader
attr_reader :tempfile, :original_filename

def initialize(file_path)
from_file_path(file_path)
end

def path
tempfile.path
end

def method_missing(method_name, *args, &block) # rubocop:disable Style/MethodMissing
tempfile.public_send(method_name, *args, &block)
end

def respond_to_missing?(method_name, include_private = false)
tempfile.respond_to?(method_name, include_private) || super
end

private

def from_file_path(path)
raise FileDoesNotExistError unless ::File.exist?(path)

@original_filename = ::File.basename(path)
extension = ::File.extname(@original_filename)

@tempfile = Tempfile.new(
[::File.basename(@original_filename, extension), extension],
)
@tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding)

FileUtils.copy_file(path, @tempfile.path)
end
end
end
14 changes: 14 additions & 0 deletions lib/factory_bot/syntax/methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,20 @@ def generate_list(name, count)
Internal.sequence_by_name(name).next
end
end

# Creates a copy of the file passed to attach to the attribute
#
# Arguments:
# filepath: (String)
# The path for the file that will be loaded. Should be a valid path
# for a file that exists at that location.
#
# Returns:
# An instance of the file loader class pointing to the file at the
# provided path.
def file_fixture(file_path)
FileLoader.new(file_path)
end
end
end
end
20 changes: 20 additions & 0 deletions spec/acceptance/file_attributes_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
describe "file attributes" do
context "when an attribute uses a file" do
it "assigns an file to the attribute" do
define_class("Post") do |_class|
attr_accessor :attachment
end
filename = File.expand_path("spec/support/text_file.txt")
file_contents = File.read(filename)

FactoryBot.define do
factory :post do
attachment { file_fixture(filename) }
end
end
post = FactoryBot.build(:post)
expect(post.attachment.original_filename).to eq ::File.basename filename
expect(File.read(post.attachment)).to eq file_contents
end
end
end
21 changes: 21 additions & 0 deletions spec/factory_bot/file_loader_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
describe FactoryBot::FileLoader do
it "creates a tempfile copy from the original" do
original_file_path = File.expand_path("spec/support/text_file.txt")
original_file_contents = File.read(original_file_path)
file_loader = FactoryBot::FileLoader.new(original_file_path)

expect(original_file_contents).to eq File.read(file_loader.tempfile)
end

it "delegates all the methods to the tempfile" do
original_file_path = File.expand_path("spec/support/text_file.txt")
file_loader = FactoryBot::FileLoader.new(original_file_path)

expect(file_loader.path).to eq file_loader.tempfile.path
end

it "raises an exception is the file path does not exists" do
expect { FactoryBot::FileLoader.new("nonexistent.path") }.
to raise_error FactoryBot::FileDoesNotExistError
end
end
1 change: 1 addition & 0 deletions spec/support/text_file.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Test Content

0 comments on commit 82b0e30

Please sign in to comment.