summaryrefslogtreecommitdiff
path: root/vendor/rails/activerecord/lib/active_record/fixtures.rb
Side-by-side diff
Diffstat (limited to 'vendor/rails/activerecord/lib/active_record/fixtures.rb') (more/less context) (ignore whitespace changes)
-rw-r--r--vendor/rails/activerecord/lib/active_record/fixtures.rb1034
1 files changed, 0 insertions, 1034 deletions
diff --git a/vendor/rails/activerecord/lib/active_record/fixtures.rb b/vendor/rails/activerecord/lib/active_record/fixtures.rb
deleted file mode 100644
index 0da8c51..0000000
--- a/vendor/rails/activerecord/lib/active_record/fixtures.rb
+++ b/dev/null
@@ -1,1034 +0,0 @@
-require 'erb'
-require 'yaml'
-require 'csv'
-
-module YAML #:nodoc:
- class Omap #:nodoc:
- def keys; map { |k, v| k } end
- def values; map { |k, v| v } end
- end
-end
-
-if defined? ActiveRecord
- class FixtureClassNotFound < ActiveRecord::ActiveRecordError #:nodoc:
- end
-else
- class FixtureClassNotFound < StandardError #:nodoc:
- end
-end
-
-# Fixtures are a way of organizing data that you want to test against; in short, sample data. They come in 3 flavors:
-#
-# 1. YAML fixtures
-# 2. CSV fixtures
-# 3. Single-file fixtures
-#
-# = YAML fixtures
-#
-# This type of fixture is in YAML format and the preferred default. YAML is a file format which describes data structures
-# in a non-verbose, human-readable format. It ships with Ruby 1.8.1+.
-#
-# Unlike single-file fixtures, YAML fixtures are stored in a single file per model, which are placed in the directory appointed
-# by <tt>Test::Unit::TestCase.fixture_path=(path)</tt> (this is automatically configured for Rails, so you can just
-# put your files in <your-rails-app>/test/fixtures/). The fixture file ends with the .yml file extension (Rails example:
-# "<your-rails-app>/test/fixtures/web_sites.yml"). The format of a YAML fixture file looks like this:
-#
-# rubyonrails:
-# id: 1
-# name: Ruby on Rails
-# url: http://www.rubyonrails.org
-#
-# google:
-# id: 2
-# name: Google
-# url: http://www.google.com
-#
-# This YAML fixture file includes two fixtures. Each YAML fixture (ie. record) is given a name and is followed by an
-# indented list of key/value pairs in the "key: value" format. Records are separated by a blank line for your viewing
-# pleasure.
-#
-# Note that YAML fixtures are unordered. If you want ordered fixtures, use the omap YAML type. See http://yaml.org/type/omap.html
-# for the specification. You will need ordered fixtures when you have foreign key constraints on keys in the same table.
-# This is commonly needed for tree structures. Example:
-#
-# --- !omap
-# - parent:
-# id: 1
-# parent_id: NULL
-# title: Parent
-# - child:
-# id: 2
-# parent_id: 1
-# title: Child
-#
-# = CSV fixtures
-#
-# Fixtures can also be kept in the Comma Separated Value format. Akin to YAML fixtures, CSV fixtures are stored
-# in a single file, but instead end with the .csv file extension (Rails example: "<your-rails-app>/test/fixtures/web_sites.csv")
-#
-# The format of this type of fixture file is much more compact than the others, but also a little harder to read by us
-# humans. The first line of the CSV file is a comma-separated list of field names. The rest of the file is then comprised
-# of the actual data (1 per line). Here's an example:
-#
-# id, name, url
-# 1, Ruby On Rails, http://www.rubyonrails.org
-# 2, Google, http://www.google.com
-#
-# Should you have a piece of data with a comma character in it, you can place double quotes around that value. If you
-# need to use a double quote character, you must escape it with another double quote.
-#
-# Another unique attribute of the CSV fixture is that it has *no* fixture name like the other two formats. Instead, the
-# fixture names are automatically generated by deriving the class name of the fixture file and adding an incrementing
-# number to the end. In our example, the 1st fixture would be called "web_site_1" and the 2nd one would be called
-# "web_site_2".
-#
-# Most databases and spreadsheets support exporting to CSV format, so this is a great format for you to choose if you
-# have existing data somewhere already.
-#
-# = Single-file fixtures
-#
-# This type of fixture was the original format for Active Record that has since been deprecated in favor of the YAML and CSV formats.
-# Fixtures for this format are created by placing text files in a sub-directory (with the name of the model) to the directory
-# appointed by <tt>Test::Unit::TestCase.fixture_path=(path)</tt> (this is automatically configured for Rails, so you can just
-# put your files in <your-rails-app>/test/fixtures/<your-model-name>/ -- like <your-rails-app>/test/fixtures/web_sites/ for the WebSite
-# model).
-#
-# Each text file placed in this directory represents a "record". Usually these types of fixtures are named without
-# extensions, but if you are on a Windows machine, you might consider adding .txt as the extension. Here's what the
-# above example might look like:
-#
-# web_sites/google
-# web_sites/yahoo.txt
-# web_sites/ruby-on-rails
-#
-# The file format of a standard fixture is simple. Each line is a property (or column in db speak) and has the syntax
-# of "name => value". Here's an example of the ruby-on-rails fixture above:
-#
-# id => 1
-# name => Ruby on Rails
-# url => http://www.rubyonrails.org
-#
-# = Using Fixtures
-#
-# Since fixtures are a testing construct, we use them in our unit and functional tests. There are two ways to use the
-# fixtures, but first let's take a look at a sample unit test:
-#
-# require 'web_site'
-#
-# class WebSiteTest < Test::Unit::TestCase
-# def test_web_site_count
-# assert_equal 2, WebSite.count
-# end
-# end
-#
-# As it stands, unless we pre-load the web_site table in our database with two records, this test will fail. Here's the
-# easiest way to add fixtures to the database:
-#
-# ...
-# class WebSiteTest < Test::Unit::TestCase
-# fixtures :web_sites # add more by separating the symbols with commas
-# ...
-#
-# By adding a "fixtures" method to the test case and passing it a list of symbols (only one is shown here though), we trigger
-# the testing environment to automatically load the appropriate fixtures into the database before each test.
-# To ensure consistent data, the environment deletes the fixtures before running the load.
-#
-# In addition to being available in the database, the fixtures are also loaded into a hash stored in an instance variable
-# of the test case. It is named after the symbol... so, in our example, there would be a hash available called
-# @web_sites. This is where the "fixture name" comes into play.
-#
-# On top of that, each record is automatically "found" (using Model.find(id)) and placed in the instance variable of its name.
-# So for the YAML fixtures, we'd get @rubyonrails and @google, which could be interrogated using regular Active Record semantics:
-#
-# # test if the object created from the fixture data has the same attributes as the data itself
-# def test_find
-# assert_equal @web_sites["rubyonrails"]["name"], @rubyonrails.name
-# end
-#
-# As seen above, the data hash created from the YAML fixtures would have @web_sites["rubyonrails"]["url"] return
-# "http://www.rubyonrails.org" and @web_sites["google"]["name"] would return "Google". The same fixtures, but loaded
-# from a CSV fixture file, would be accessible via @web_sites["web_site_1"]["name"] == "Ruby on Rails" and have the individual
-# fixtures available as instance variables @web_site_1 and @web_site_2.
-#
-# If you do not wish to use instantiated fixtures (usually for performance reasons) there are two options.
-#
-# - to completely disable instantiated fixtures:
-# self.use_instantiated_fixtures = false
-#
-# - to keep the fixture instance (@web_sites) available, but do not automatically 'find' each instance:
-# self.use_instantiated_fixtures = :no_instances
-#
-# Even if auto-instantiated fixtures are disabled, you can still access them
-# by name via special dynamic methods. Each method has the same name as the
-# model, and accepts the name of the fixture to instantiate:
-#
-# fixtures :web_sites
-#
-# def test_find
-# assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
-# end
-#
-# = Dynamic fixtures with ERb
-#
-# Some times you don't care about the content of the fixtures as much as you care about the volume. In these cases, you can
-# mix ERb in with your YAML or CSV fixtures to create a bunch of fixtures for load testing, like:
-#
-# <% for i in 1..1000 %>
-# fix_<%= i %>:
-# id: <%= i %>
-# name: guy_<%= 1 %>
-# <% end %>
-#
-# This will create 1000 very simple YAML fixtures.
-#
-# Using ERb, you can also inject dynamic values into your fixtures with inserts like <%= Date.today.strftime("%Y-%m-%d") %>.
-# This is however a feature to be used with some caution. The point of fixtures are that they're stable units of predictable
-# sample data. If you feel that you need to inject dynamic values, then perhaps you should reexamine whether your application
-# is properly testable. Hence, dynamic values in fixtures are to be considered a code smell.
-#
-# = Transactional fixtures
-#
-# TestCases can use begin+rollback to isolate their changes to the database instead of having to delete+insert for every test case.
-# They can also turn off auto-instantiation of fixture data since the feature is costly and often unused.
-#
-# class FooTest < Test::Unit::TestCase
-# self.use_transactional_fixtures = true
-# self.use_instantiated_fixtures = false
-#
-# fixtures :foos
-#
-# def test_godzilla
-# assert !Foo.find(:all).empty?
-# Foo.destroy_all
-# assert Foo.find(:all).empty?
-# end
-#
-# def test_godzilla_aftermath
-# assert !Foo.find(:all).empty?
-# end
-# end
-#
-# If you preload your test database with all fixture data (probably in the Rakefile task) and use transactional fixtures,
-# then you may omit all fixtures declarations in your test cases since all the data's already there and every case rolls back its changes.
-#
-# In order to use instantiated fixtures with preloaded data, set +self.pre_loaded_fixtures+ to true. This will provide
-# access to fixture data for every table that has been loaded through fixtures (depending on the value of +use_instantiated_fixtures+)
-#
-# When *not* to use transactional fixtures:
-# 1. You're testing whether a transaction works correctly. Nested transactions don't commit until all parent transactions commit,
-# particularly, the fixtures transaction which is begun in setup and rolled back in teardown. Thus, you won't be able to verify
-# the results of your transaction until Active Record supports nested transactions or savepoints (in progress).
-# 2. Your database does not support transactions. Every Active Record database supports transactions except MySQL MyISAM.
-# Use InnoDB, MaxDB, or NDB instead.
-#
-# = Advanced YAML Fixtures
-#
-# YAML fixtures that don't specify an ID get some extra features:
-#
-# * Stable, autogenerated ID's
-# * Label references for associations (belongs_to, has_one, has_many)
-# * HABTM associations as inline lists
-# * Autofilled timestamp columns
-# * Fixture label interpolation
-# * Support for YAML defaults
-#
-# == Stable, autogenerated ID's
-#
-# Here, have a monkey fixture:
-#
-# george:
-# id: 1
-# name: George the Monkey
-#
-# reginald:
-# id: 2
-# name: Reginald the Pirate
-#
-# Each of these fixtures has two unique identifiers: one for the database
-# and one for the humans. Why don't we generate the primary key instead?
-# Hashing each fixture's label yields a consistent ID:
-#
-# george: # generated id: 503576764
-# name: George the Monkey
-#
-# reginald: # generated id: 324201669
-# name: Reginald the Pirate
-#
-# ActiveRecord looks at the fixture's model class, discovers the correct
-# primary key, and generates it right before inserting the fixture
-# into the database.
-#
-# The generated ID for a given label is constant, so we can discover
-# any fixture's ID without loading anything, as long as we know the label.
-#
-# == Label references for associations (belongs_to, has_one, has_many)
-#
-# Specifying foreign keys in fixtures can be very fragile, not to
-# mention difficult to read. Since ActiveRecord can figure out the ID of
-# any fixture from its label, you can specify FK's by label instead of ID.
-#
-# === belongs_to
-#
-# Let's break out some more monkeys and pirates.
-#
-# ### in pirates.yml
-#
-# reginald:
-# id: 1
-# name: Reginald the Pirate
-# monkey_id: 1
-#
-# ### in monkeys.yml
-#
-# george:
-# id: 1
-# name: George the Monkey
-# pirate_id: 1
-#
-# Add a few more monkeys and pirates and break this into multiple files,
-# and it gets pretty hard to keep track of what's going on. Let's
-# use labels instead of ID's:
-#
-# ### in pirates.yml
-#
-# reginald:
-# name: Reginald the Pirate
-# monkey: george
-#
-# ### in monkeys.yml
-#
-# george:
-# name: George the Monkey
-# pirate: reginald
-#
-# Pow! All is made clear. ActiveRecord reflects on the fixture's model class,
-# finds all the +belongs_to+ associations, and allows you to specify
-# a target *label* for the *association* (monkey: george) rather than
-# a target *id* for the *FK* (monkey_id: 1).
-#
-# ==== Polymorphic belongs_to
-#
-# Supporting polymorphic relationships is a little bit more complicated, since
-# ActiveRecord needs to know what type your association is pointing at. Something
-# like this should look familiar:
-#
-# ### in fruit.rb
-#
-# belongs_to :eater, :polymorphic => true
-#
-# ### in fruits.yml
-#
-# apple:
-# id: 1
-# name: apple
-# eater_id: 1
-# eater_type: Monkey
-#
-# Can we do better? You bet!
-#
-# apple:
-# eater: george (Monkey)
-#
-# Just provide the polymorphic target type and ActiveRecord will take care of the rest.
-#
-# === has_and_belongs_to_many
-#
-# Time to give our monkey some fruit.
-#
-# ### in monkeys.yml
-#
-# george:
-# id: 1
-# name: George the Monkey
-# pirate_id: 1
-#
-# ### in fruits.yml
-#
-# apple:
-# id: 1
-# name: apple
-#
-# orange:
-# id: 2
-# name: orange
-#
-# grape:
-# id: 3
-# name: grape
-#
-# ### in fruits_monkeys.yml
-#
-# apple_george:
-# fruit_id: 1
-# monkey_id: 1
-#
-# orange_george:
-# fruit_id: 2
-# monkey_id: 1
-#
-# grape_george:
-# fruit_id: 3
-# monkey_id: 1
-#
-# Let's make the HABTM fixture go away.
-#
-# ### in monkeys.yml
-#
-# george:
-# name: George the Monkey
-# pirate: reginald
-# fruits: apple, orange, grape
-#
-# ### in fruits.yml
-#
-# apple:
-# name: apple
-#
-# orange:
-# name: orange
-#
-# grape:
-# name: grape
-#
-# Zap! No more fruits_monkeys.yml file. We've specified the list of fruits
-# on George's fixture, but we could've just as easily specified a list
-# of monkeys on each fruit. As with +belongs_to+, ActiveRecord reflects on
-# the fixture's model class and discovers the +has_and_belongs_to_many+
-# associations.
-#
-# == Autofilled timestamp columns
-#
-# If your table/model specifies any of ActiveRecord's
-# standard timestamp columns (created_at, created_on, updated_at, updated_on),
-# they will automatically be set to Time.now.
-#
-# If you've set specific values, they'll be left alone.
-#
-# == Fixture label interpolation
-#
-# The label of the current fixture is always available as a column value:
-#
-# geeksomnia:
-# name: Geeksomnia's Account
-# subdomain: $LABEL
-#
-# Also, sometimes (like when porting older join table fixtures) you'll need
-# to be able to get ahold of the identifier for a given label. ERB
-# to the rescue:
-#
-# george_reginald:
-# monkey_id: <%= Fixtures.identify(:reginald) %>
-# pirate_id: <%= Fixtures.identify(:george) %>
-#
-# == Support for YAML defaults
-#
-# You probably already know how to use YAML to set and reuse defaults in
-# your +database.yml+ file,. You can use the same technique in your fixtures:
-#
-# DEFAULTS: &DEFAULTS
-# created_on: <%= 3.weeks.ago.to_s(:db) %>
-#
-# first:
-# name: Smurf
-# <<: *DEFAULTS
-#
-# second:
-# name: Fraggle
-# <<: *DEFAULTS
-#
-# Any fixture labeled "DEFAULTS" is safely ignored.
-
-class Fixtures < YAML::Omap
- DEFAULT_FILTER_RE = /\.ya?ml$/
-
- @@all_cached_fixtures = {}
-
- def self.reset_cache(connection = nil)
- connection ||= ActiveRecord::Base.connection
- @@all_cached_fixtures[connection.object_id] = {}
- end
-
- def self.cache_for_connection(connection)
- @@all_cached_fixtures[connection.object_id] ||= {}
- @@all_cached_fixtures[connection.object_id]
- end
-
- def self.fixture_is_cached?(connection, table_name)
- cache_for_connection(connection)[table_name]
- end
-
- def self.cached_fixtures(connection, keys_to_fetch = nil)
- if keys_to_fetch
- fixtures = cache_for_connection(connection).values_at(*keys_to_fetch)
- else
- fixtures = cache_for_connection(connection).values
- end
- fixtures.size > 1 ? fixtures : fixtures.first
- end
-
- def self.cache_fixtures(connection, fixtures)
- cache_for_connection(connection).update(fixtures.index_by(&:table_name))
- end
-
- def self.instantiate_fixtures(object, table_name, fixtures, load_instances = true)
- object.instance_variable_set "@#{table_name.to_s.gsub('.','_')}", fixtures
- if load_instances
- ActiveRecord::Base.silence do
- fixtures.each do |name, fixture|
- begin
- object.instance_variable_set "@#{name}", fixture.find
- rescue FixtureClassNotFound
- nil
- end
- end
- end
- end
- end
-
- def self.instantiate_all_loaded_fixtures(object, load_instances = true)
- all_loaded_fixtures.each do |table_name, fixtures|
- Fixtures.instantiate_fixtures(object, table_name, fixtures, load_instances)
- end
- end
-
- cattr_accessor :all_loaded_fixtures
- self.all_loaded_fixtures = {}
-
- def self.create_fixtures(fixtures_directory, table_names, class_names = {})
- table_names = [table_names].flatten.map { |n| n.to_s }
- connection = block_given? ? yield : ActiveRecord::Base.connection
-
- table_names_to_fetch = table_names.reject { |table_name| fixture_is_cached?(connection, table_name) }
-
- unless table_names_to_fetch.empty?
- ActiveRecord::Base.silence do
- connection.disable_referential_integrity do
- fixtures_map = {}
-
- fixtures = table_names_to_fetch.map do |table_name|
- fixtures_map[table_name] = Fixtures.new(connection, File.split(table_name.to_s).last, class_names[table_name.to_sym], File.join(fixtures_directory, table_name.to_s))
- end
-
- all_loaded_fixtures.update(fixtures_map)
-
- connection.transaction(Thread.current['open_transactions'].to_i == 0) do
- fixtures.reverse.each { |fixture| fixture.delete_existing_fixtures }
- fixtures.each { |fixture| fixture.insert_fixtures }
-
- # Cap primary key sequences to max(pk).
- if connection.respond_to?(:reset_pk_sequence!)
- table_names.each do |table_name|
- connection.reset_pk_sequence!(table_name)
- end
- end
- end
-
- cache_fixtures(connection, fixtures)
- end
- end
- end
- cached_fixtures(connection, table_names)
- end
-
- # Returns a consistent identifier for +label+. This will always
- # be a positive integer, and will always be the same for a given
- # label, assuming the same OS, platform, and version of Ruby.
- def self.identify(label)
- label.to_s.hash.abs
- end
-
- attr_reader :table_name
-
- def initialize(connection, table_name, class_name, fixture_path, file_filter = DEFAULT_FILTER_RE)
- @connection, @table_name, @fixture_path, @file_filter = connection, table_name, fixture_path, file_filter
- @class_name = class_name ||
- (ActiveRecord::Base.pluralize_table_names ? @table_name.singularize.camelize : @table_name.camelize)
- @table_name = ActiveRecord::Base.table_name_prefix + @table_name + ActiveRecord::Base.table_name_suffix
- @table_name = class_name.table_name if class_name.respond_to?(:table_name)
- @connection = class_name.connection if class_name.respond_to?(:connection)
- read_fixture_files
- end
-
- def delete_existing_fixtures
- @connection.delete "DELETE FROM #{@connection.quote_table_name(table_name)}", 'Fixture Delete'
- end
-
- def insert_fixtures
- now = ActiveRecord::Base.default_timezone == :utc ? Time.now.utc : Time.now
- now = now.to_s(:db)
-
- # allow a standard key to be used for doing defaults in YAML
- delete(assoc("DEFAULTS"))
-
- # track any join tables we need to insert later
- habtm_fixtures = Hash.new do |h, habtm|
- h[habtm] = HabtmFixtures.new(@connection, habtm.options[:join_table], nil, nil)
- end
-
- each do |label, fixture|
- row = fixture.to_hash
-
- if model_class && model_class < ActiveRecord::Base
- # fill in timestamp columns if they aren't specified and the model is set to record_timestamps
- if model_class.record_timestamps
- timestamp_column_names.each do |name|
- row[name] = now unless row.key?(name)
- end
- end
-
- # interpolate the fixture label
- row.each do |key, value|
- row[key] = label if value == "$LABEL"
- end
-
- # generate a primary key if necessary
- if has_primary_key_column? && !row.include?(primary_key_name)
- row[primary_key_name] = Fixtures.identify(label)
- end
-
- # If STI is used, find the correct subclass for association reflection
- reflection_class =
- if row.include?(inheritance_column_name)
- row[inheritance_column_name].constantize rescue model_class
- else
- model_class
- end
-
- reflection_class.reflect_on_all_associations.each do |association|
- case association.macro
- when :belongs_to
- # Do not replace association name with association foreign key if they are named the same
- fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
-
- if association.name.to_s != fk_name && value = row.delete(association.name.to_s)
- if association.options[:polymorphic]
- if value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
- target_type = $1
- target_type_name = (association.options[:foreign_type] || "#{association.name}_type").to_s
-
- # support polymorphic belongs_to as "label (Type)"
- row[target_type_name] = target_type
- end
- end
-
- row[fk_name] = Fixtures.identify(value)
- end
- when :has_and_belongs_to_many
- if (targets = row.delete(association.name.to_s))
- targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
- join_fixtures = habtm_fixtures[association]
-
- targets.each do |target|
- join_fixtures["#{label}_#{target}"] = Fixture.new(
- { association.primary_key_name => row[primary_key_name],
- association.association_foreign_key => Fixtures.identify(target) }, nil)
- end
- end
- end
- end
- end
-
- @connection.insert_fixture(fixture, @table_name)
- end
-
- # insert any HABTM join tables we discovered
- habtm_fixtures.values.each do |fixture|
- fixture.delete_existing_fixtures
- fixture.insert_fixtures
- end
- end
-
- private
- class HabtmFixtures < ::Fixtures #:nodoc:
- def read_fixture_files; end
- end
-
- def model_class
- @model_class ||= @class_name.is_a?(Class) ?
- @class_name : @class_name.constantize rescue nil
- end
-
- def primary_key_name
- @primary_key_name ||= model_class && model_class.primary_key
- end
-
- def has_primary_key_column?
- @has_primary_key_column ||= model_class && primary_key_name &&
- model_class.columns.find { |c| c.name == primary_key_name }
- end
-
- def timestamp_column_names
- @timestamp_column_names ||= %w(created_at created_on updated_at updated_on).select do |name|
- column_names.include?(name)
- end
- end
-
- def inheritance_column_name
- @inheritance_column_name ||= model_class && model_class.inheritance_column
- end
-
- def column_names
- @column_names ||= @connection.columns(@table_name).collect(&:name)
- end
-
- def read_fixture_files
- if File.file?(yaml_file_path)
- read_yaml_fixture_files
- elsif File.file?(csv_file_path)
- read_csv_fixture_files
- else
- # Standard fixtures
- Dir.entries(@fixture_path).each do |file|
- path = File.join(@fixture_path, file)
- if File.file?(path) and file !~ @file_filter
- self[file] = Fixture.new(path, @class_name)
- end
- end
- end
- end
-
- def read_yaml_fixture_files
- yaml_string = ""
- Dir["#{@fixture_path}/**/*.yml"].select { |f| test(?f, f) }.each do |subfixture_path|
- yaml_string << IO.read(subfixture_path)
- end
- yaml_string << IO.read(yaml_file_path)
-
- if yaml = parse_yaml_string(yaml_string)
- # If the file is an ordered map, extract its children.
- yaml_value =
- if yaml.respond_to?(:type_id) && yaml.respond_to?(:value)
- yaml.value
- else
- [yaml]
- end
-
- yaml_value.each do |fixture|
- fixture.each do |name, data|
- unless data
- raise Fixture::FormatError, "Bad data for #{@class_name} fixture named #{name} (nil)"
- end
-
- self[name] = Fixture.new(data, @class_name)
- end
- end
- end
- end
-
- def read_csv_fixture_files
- reader = CSV::Reader.create(erb_render(IO.read(csv_file_path)))
- header = reader.shift
- i = 0
- reader.each do |row|
- data = {}
- row.each_with_index { |cell, j| data[header[j].to_s.strip] = cell.to_s.strip }
- self["#{Inflector::underscore(@class_name)}_#{i+=1}"]= Fixture.new(data, @class_name)
- end
- end
-
- def yaml_file_path
- "#{@fixture_path}.yml"
- end
-
- def csv_file_path
- @fixture_path + ".csv"
- end
-
- def yaml_fixtures_key(path)
- File.basename(@fixture_path).split(".").first
- end
-
- def parse_yaml_string(fixture_content)
- YAML::load(erb_render(fixture_content))
- rescue => error
- raise Fixture::FormatError, "a YAML error occurred parsing #{yaml_file_path}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at http://www.yaml.org/faq.html\nThe exact error was:\n #{error.class}: #{error}"
- end
-
- def erb_render(fixture_content)
- ERB.new(fixture_content).result
- end
-end
-
-class Fixture #:nodoc:
- include Enumerable
-
- class FixtureError < StandardError #:nodoc:
- end
-
- class FormatError < FixtureError #:nodoc:
- end
-
- attr_reader :class_name
-
- def initialize(fixture, class_name)
- case fixture
- when Hash, YAML::Omap
- @fixture = fixture
- when String
- @fixture = read_fixture_file(fixture)
- else
- raise ArgumentError, "Bad fixture argument #{fixture.inspect} during creation of #{class_name} fixture"
- end
-
- @class_name = class_name
- end
-
- def each
- @fixture.each { |item| yield item }
- end
-
- def [](key)
- @fixture[key]
- end
-
- def to_hash
- @fixture
- end
-
- def key_list
- columns = @fixture.keys.collect{ |column_name| ActiveRecord::Base.connection.quote_column_name(column_name) }
- columns.join(", ")
- end
-
- def value_list
- klass = @class_name.constantize rescue nil
-
- list = @fixture.inject([]) do |fixtures, (key, value)|
- col = klass.columns_hash[key] if klass.respond_to?(:ancestors) && klass.ancestors.include?(ActiveRecord::Base)
- fixtures << ActiveRecord::Base.connection.quote(value, col).gsub('[^\]\\n', "\n").gsub('[^\]\\r', "\r")
- end
- list * ', '
- end
-
- def find
- klass = @class_name.is_a?(Class) ? @class_name : Object.const_get(@class_name) rescue nil
- if klass
- klass.find(self[klass.primary_key])
- else
- raise FixtureClassNotFound, "The class #{@class_name.inspect} was not found."
- end
- end
-
- private
- def read_fixture_file(fixture_file_path)
- IO.readlines(fixture_file_path).inject({}) do |fixture, line|
- # Mercifully skip empty lines.
- next if line =~ /^\s*$/
-
- # Use the same regular expression for attributes as Active Record.
- unless md = /^\s*([a-zA-Z][-_\w]*)\s*=>\s*(.+)\s*$/.match(line)
- raise FormatError, "#{fixture_file_path}: fixture format error at '#{line}'. Expecting 'key => value'."
- end
- key, value = md.captures
-
- # Disallow duplicate keys to catch typos.
- raise FormatError, "#{fixture_file_path}: duplicate '#{key}' in fixture." if fixture[key]
- fixture[key] = value.strip
- fixture
- end
- end
-end
-
-module Test #:nodoc:
- module Unit #:nodoc:
- class TestCase #:nodoc:
- superclass_delegating_accessor :fixture_path
- superclass_delegating_accessor :fixture_table_names
- superclass_delegating_accessor :fixture_class_names
- superclass_delegating_accessor :use_transactional_fixtures
- superclass_delegating_accessor :use_instantiated_fixtures # true, false, or :no_instances
- superclass_delegating_accessor :pre_loaded_fixtures
-
- self.fixture_table_names = []
- self.use_transactional_fixtures = false
- self.use_instantiated_fixtures = true
- self.pre_loaded_fixtures = false
-
- @@already_loaded_fixtures = {}
- self.fixture_class_names = {}
-
- def self.set_fixture_class(class_names = {})
- self.fixture_class_names = self.fixture_class_names.merge(class_names)
- end
-
- def self.fixtures(*table_names)
- if table_names.first == :all
- table_names = Dir["#{fixture_path}/*.yml"] + Dir["#{fixture_path}/*.csv"]
- table_names.map! { |f| File.basename(f).split('.')[0..-2].join('.') }
- else
- table_names = table_names.flatten.map { |n| n.to_s }
- end
-
- self.fixture_table_names |= table_names
- require_fixture_classes(table_names)
- setup_fixture_accessors(table_names)
- end
-
- def self.require_fixture_classes(table_names = nil)
- (table_names || fixture_table_names).each do |table_name|
- file_name = table_name.to_s
- file_name = file_name.singularize if ActiveRecord::Base.pluralize_table_names
- begin
- require_dependency file_name
- rescue LoadError
- # Let's hope the developer has included it himself
- end
- end
- end
-
- def self.setup_fixture_accessors(table_names = nil)
- (table_names || fixture_table_names).each do |table_name|
- table_name = table_name.to_s.tr('.', '_')
-
- define_method(table_name) do |*fixtures|
- force_reload = fixtures.pop if fixtures.last == true || fixtures.last == :reload
-
- @fixture_cache[table_name] ||= {}
-
- instances = fixtures.map do |fixture|
- @fixture_cache[table_name].delete(fixture) if force_reload
-
- if @loaded_fixtures[table_name][fixture.to_s]
- @fixture_cache[table_name][fixture] ||= @loaded_fixtures[table_name][fixture.to_s].find
- else
- raise StandardError, "No fixture with name '#{fixture}' found for table '#{table_name}'"
- end
- end
-
- instances.size == 1 ? instances.first : instances
- end
- end
- end
-
- def self.uses_transaction(*methods)
- @uses_transaction = [] unless defined?(@uses_transaction)
- @uses_transaction.concat methods.map(&:to_s)
- end
-
- def self.uses_transaction?(method)
- @uses_transaction = [] unless defined?(@uses_transaction)
- @uses_transaction.include?(method.to_s)
- end
-
- def use_transactional_fixtures?
- use_transactional_fixtures &&
- !self.class.uses_transaction?(method_name)
- end
-
- def setup_with_fixtures
- return if @fixtures_setup
- @fixtures_setup = true
- return unless defined?(ActiveRecord::Base) && !ActiveRecord::Base.configurations.blank?
-
- if pre_loaded_fixtures && !use_transactional_fixtures
- raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_fixtures'
- end
-
- @fixture_cache = {}
-
- # Load fixtures once and begin transaction.
- if use_transactional_fixtures?
- if @@already_loaded_fixtures[self.class]
- @loaded_fixtures = @@already_loaded_fixtures[self.class]
- else
- load_fixtures
- @@already_loaded_fixtures[self.class] = @loaded_fixtures
- end
- ActiveRecord::Base.send :increment_open_transactions
- ActiveRecord::Base.connection.begin_db_transaction
- # Load fixtures for every test.
- else
- Fixtures.reset_cache
- @@already_loaded_fixtures[self.class] = nil
- load_fixtures
- end
-
- # Instantiate fixtures for every test if requested.
- instantiate_fixtures if use_instantiated_fixtures
- end
- alias_method :setup, :setup_with_fixtures
-
- def teardown_with_fixtures
- return if @fixtures_teardown
- @fixtures_teardown = true
- return unless defined?(ActiveRecord::Base) && !ActiveRecord::Base.configurations.blank?
-
- unless use_transactional_fixtures?
- Fixtures.reset_cache
- end
-
- # Rollback changes if a transaction is active.
- if use_transactional_fixtures? && Thread.current['open_transactions'] != 0
- ActiveRecord::Base.connection.rollback_db_transaction
- Thread.current['open_transactions'] = 0
- end
- ActiveRecord::Base.verify_active_connections!
- end
- alias_method :teardown, :teardown_with_fixtures
-
- def self.method_added(method)
- return if @__disable_method_added__
- @__disable_method_added__ = true
-
- case method.to_s
- when 'setup'
- unless method_defined?(:setup_without_fixtures)
- alias_method :setup_without_fixtures, :setup
- define_method(:full_setup) do
- setup_with_fixtures
- setup_without_fixtures
- end
- end
- alias_method :setup, :full_setup
- when 'teardown'
- unless method_defined?(:teardown_without_fixtures)
- alias_method :teardown_without_fixtures, :teardown
- define_method(:full_teardown) do
- teardown_without_fixtures
- teardown_with_fixtures
- end
- end
- alias_method :teardown, :full_teardown
- end
-
- @__disable_method_added__ = false
- end
-
- private
- def load_fixtures
- @loaded_fixtures = {}
- fixtures = Fixtures.create_fixtures(fixture_path, fixture_table_names, fixture_class_names)
- unless fixtures.nil?
- if fixtures.instance_of?(Fixtures)
- @loaded_fixtures[fixtures.table_name] = fixtures
- else
- fixtures.each { |f| @loaded_fixtures[f.table_name] = f }
- end
- end
- end
-
- # for pre_loaded_fixtures, only require the classes once. huge speed improvement
- @@required_fixture_classes = false
-
- def instantiate_fixtures
- if pre_loaded_fixtures
- raise RuntimeError, 'Load fixtures before instantiating them.' if Fixtures.all_loaded_fixtures.empty?
- unless @@required_fixture_classes
- self.class.require_fixture_classes Fixtures.all_loaded_fixtures.keys
- @@required_fixture_classes = true
- end
- Fixtures.instantiate_all_loaded_fixtures(self, load_instances?)
- else
- raise RuntimeError, 'Load fixtures before instantiating them.' if @loaded_fixtures.nil?
- @loaded_fixtures.each do |table_name, fixtures|
- Fixtures.instantiate_fixtures(self, table_name, fixtures, load_instances?)
- end
- end
- end
-
- def load_instances?
- use_instantiated_fixtures != :no_instances
- end
- end
- end
-end