Skip to content
This repository
Browse code

Foxy fixtures. Adapter#disable_referential_integrity. Closes #9981.

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@8036 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
commit 49eafd8c3620bf8e46d21d447fc634a12c8280ab 1 parent 742694e
Jeremy Kemper jeremy authored
9 activerecord/CHANGELOG
... ... @@ -1,5 +1,14 @@
1 1 *SVN*
2 2
  3 +* Foxy fixtures, from rathole (http://svn.geeksomnia.com/rathole/trunk/README)
  4 + - stable, autogenerated IDs
  5 + - specify associations (belongs_to, has_one, has_many) by label, not ID
  6 + - specify HABTM associations as inline lists
  7 + - autofill timestamp columns
  8 + - support YAML defaults
  9 + - fixture label interpolation
  10 + Enabled for fixtures that correspond to a model class and don't specify a primary key value. #9981 [jbarnette]
  11 +
3 12 * Add docs explaining how to protect all attributes using attr_accessible with no arguments. Closes #9631 [boone, rmm5t]
4 13
5 14 * Update add_index documentation to use new options api. Closes #9787 [kamal]
7 activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -70,6 +70,13 @@ def quote_table_name(name)
70 70 name
71 71 end
72 72
  73 + # REFERENTIAL INTEGRITY ====================================
  74 +
  75 + # Override to turn off referential integrity while executing +&block+
  76 + def disable_referential_integrity(&block)
  77 + yield
  78 + end
  79 +
73 80 # CONNECTION MANAGEMENT ====================================
74 81
75 82 # Is this connection active and ready to perform queries?
12 activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -224,6 +224,18 @@ def quoted_false
224 224 "0"
225 225 end
226 226
  227 + # REFERENTIAL INTEGRITY ====================================
  228 +
  229 + def disable_referential_integrity(&block) #:nodoc:
  230 + old = select_value("SELECT @@FOREIGN_KEY_CHECKS")
  231 +
  232 + begin
  233 + update("SET FOREIGN_KEY_CHECKS = 0")
  234 + yield
  235 + ensure
  236 + update("SET FOREIGN_KEY_CHECKS = #{old}")
  237 + end
  238 + end
227 239
228 240 # CONNECTION MANAGEMENT ====================================
229 241
8 activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -364,6 +364,14 @@ def quoted_date(value) #:nodoc:
364 364 end
365 365 end
366 366
  367 + # REFERENTIAL INTEGRITY ====================================
  368 +
  369 + def disable_referential_integrity(&block) #:nodoc:
  370 + execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
  371 + yield
  372 + ensure
  373 + execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER ALL" }.join(";"))
  374 + end
367 375
368 376 # DATABASE STATEMENTS ======================================
369 377
310 activerecord/lib/active_record/fixtures.rb
@@ -215,6 +215,199 @@ class FixtureClassNotFound < ActiveRecord::ActiveRecordError #:nodoc:
215 215 # the results of your transaction until Active Record supports nested transactions or savepoints (in progress.)
216 216 # 2. Your database does not support transactions. Every Active Record database supports transactions except MySQL MyISAM.
217 217 # Use InnoDB, MaxDB, or NDB instead.
  218 +#
  219 +# = Advanced YAML Fixtures
  220 +#
  221 +# YAML fixtures that don't specify an ID get some extra features:
  222 +#
  223 +# * Stable, autogenerated ID's
  224 +# * Label references for associations (belongs_to, has_one, has_many)
  225 +# * HABTM associations as inline lists
  226 +# * Autofilled timestamp columns
  227 +# * Fixture label interpolation
  228 +# * Support for YAML defaults
  229 +#
  230 +# == Stable, autogenerated ID's
  231 +#
  232 +# Here, have a monkey fixture:
  233 +#
  234 +# george:
  235 +# id: 1
  236 +# name: George the Monkey
  237 +#
  238 +# reginald:
  239 +# id: 2
  240 +# name: Reginald the Pirate
  241 +#
  242 +# Each of these fixtures has two unique identifiers: one for the database
  243 +# and one for the humans. Why don't we generate the primary key instead?
  244 +# Hashing each fixture's label yields a consistent ID:
  245 +#
  246 +# george: # generated id: 503576764
  247 +# name: George the Monkey
  248 +#
  249 +# reginald: # generated id: 324201669
  250 +# name: Reginald the Pirate
  251 +#
  252 +# ActiveRecord looks at the fixture's model class, discovers the correct
  253 +# primary key, and generates it right before inserting the fixture
  254 +# into the database.
  255 +#
  256 +# The generated ID for a given label is constant, so we can discover
  257 +# any fixture's ID without loading anything, as long as we know the label.
  258 +#
  259 +# == Label references for associations (belongs_to, has_one, has_many)
  260 +#
  261 +# Specifying foreign keys in fixtures can be very fragile, not to
  262 +# mention difficult to read. Since ActiveRecord can figure out the ID of
  263 +# and fixture from its label, you can specify FK's by label instead of ID.
  264 +#
  265 +# === belongs_to
  266 +#
  267 +# Let's break out some more monkeys and pirates.
  268 +#
  269 +# ### in pirates.yml
  270 +#
  271 +# reginald:
  272 +# id: 1
  273 +# name: Reginald the Pirate
  274 +# monkey_id: 1
  275 +#
  276 +# ### in monkeys.yml
  277 +#
  278 +# george:
  279 +# id: 1
  280 +# name: George the Monkey
  281 +# pirate_id: 1
  282 +#
  283 +# Add a few more monkeys and pirates and break this into multiple files,
  284 +# and it gets pretty hard to keep track of what's going on. Let's
  285 +# use labels instead of ID's:
  286 +#
  287 +# ### in pirates.yml
  288 +#
  289 +# reginald:
  290 +# name: Reginald the Pirate
  291 +# monkey: george
  292 +#
  293 +# ### in monkeys.yml
  294 +#
  295 +# george:
  296 +# name: George the Monkey
  297 +# pirate: reginald
  298 +#
  299 +# Pow! All is made clear. ActiveRecord reflects on the fixture's model class,
  300 +# finds all the +belongs_to+ associations, and allows you to specify
  301 +# a target *label* for the *association* (monkey: george) rather than
  302 +# a target *id* for the *FK* (monkey_id: 1).
  303 +#
  304 +# === has_and_belongs_to_many
  305 +#
  306 +# Time to give our monkey some fruit.
  307 +#
  308 +# ### in monkeys.yml
  309 +#
  310 +# george:
  311 +# id: 1
  312 +# name: George the Monkey
  313 +# pirate_id: 1
  314 +#
  315 +# ### in fruits.yml
  316 +#
  317 +# apple:
  318 +# id: 1
  319 +# name: apple
  320 +#
  321 +# orange:
  322 +# id: 2
  323 +# name: orange
  324 +#
  325 +# grape:
  326 +# id: 3
  327 +# name: grape
  328 +#
  329 +# ### in fruits_monkeys.yml
  330 +#
  331 +# apple_george:
  332 +# fruit_id: 1
  333 +# monkey_id: 1
  334 +#
  335 +# orange_george:
  336 +# fruit_id: 2
  337 +# monkey_id: 1
  338 +#
  339 +# grape_george:
  340 +# fruit_id: 3
  341 +# monkey_id: 1
  342 +#
  343 +# Let's make the HABTM fixture go away.
  344 +#
  345 +# ### in monkeys.yml
  346 +#
  347 +# george:
  348 +# name: George the Monkey
  349 +# pirate: reginald
  350 +# fruits: apple, orange, grape
  351 +#
  352 +# ### in fruits.yml
  353 +#
  354 +# apple:
  355 +# name: apple
  356 +#
  357 +# orange:
  358 +# name: orange
  359 +#
  360 +# grape:
  361 +# name: grape
  362 +#
  363 +# Zap! No more fruits_monkeys.yml file. We've specified the list of fruits
  364 +# on George's fixture, but we could've just as easily specified a list
  365 +# of monkeys on each fruit. As with +belongs_to+, ActiveRecord reflects on
  366 +# the fixture's model class and discovers the +has_and_belongs_to_many+
  367 +# associations.
  368 +#
  369 +# == Autofilled timestamp columns
  370 +#
  371 +# If your table/model specifies any of ActiveRecord's
  372 +# standard timestamp columns (created_at, created_on, updated_at, updated_on),
  373 +# they will automatically be set to Time.now.
  374 +#
  375 +# If you've set specific values, they'll be left alone.
  376 +#
  377 +# == Fixture label interpolation
  378 +#
  379 +# The label of the current fixture is always available as a column value:
  380 +#
  381 +# geeksomnia:
  382 +# name: Geeksomnia's Account
  383 +# subdomain: $LABEL
  384 +#
  385 +# Also, sometimes (like when porting older join table fixtures) you'll need
  386 +# to be able to get ahold of the identifier for a given label. ERB
  387 +# to the rescue:
  388 +#
  389 +# george_reginald:
  390 +# monkey_id: <%= Fixtures.identify(:reginald) %>
  391 +# pirate_id: <%= Fixtures.identify(:george) %>
  392 +#
  393 +# == Support for YAML defaults
  394 +#
  395 +# You probably already know how to use YAML to set and reuse defaults in
  396 +# your +database.yml+ file,. You can use the same technique in your fixtures:
  397 +#
  398 +# DEFAULTS: &DEFAULTS
  399 +# created_on: <%= 3.weeks.ago.to_s(:db) %>
  400 +#
  401 +# first:
  402 +# name: Smurf
  403 +# <<: *DEFAULTS
  404 +#
  405 +# second:
  406 +# name: Fraggle
  407 +# <<: *DEFAULTS
  408 +#
  409 +# Any fixture labeled "DEFAULTS" is safely ignored.
  410 +
218 411 class Fixtures < YAML::Omap
219 412 DEFAULT_FILTER_RE = /\.ya?ml$/
220 413
@@ -279,32 +472,41 @@ def self.create_fixtures(fixtures_directory, table_names, class_names = {})
279 472
280 473 unless table_names_to_fetch.empty?
281 474 ActiveRecord::Base.silence do
282   - fixtures_map = {}
  475 + connection.disable_referential_integrity do
  476 + fixtures_map = {}
283 477
284   - fixtures = table_names_to_fetch.map do |table_name|
285   - 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))
286   - end
  478 + fixtures = table_names_to_fetch.map do |table_name|
  479 + 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))
  480 + end
287 481
288   - all_loaded_fixtures.update(fixtures_map)
  482 + all_loaded_fixtures.update(fixtures_map)
289 483
290   - connection.transaction(Thread.current['open_transactions'].to_i == 0) do
291   - fixtures.reverse.each { |fixture| fixture.delete_existing_fixtures }
292   - fixtures.each { |fixture| fixture.insert_fixtures }
  484 + connection.transaction(Thread.current['open_transactions'].to_i == 0) do
  485 + fixtures.reverse.each { |fixture| fixture.delete_existing_fixtures }
  486 + fixtures.each { |fixture| fixture.insert_fixtures }
293 487
294   - # Cap primary key sequences to max(pk).
295   - if connection.respond_to?(:reset_pk_sequence!)
296   - table_names.each do |table_name|
297   - connection.reset_pk_sequence!(table_name)
  488 + # Cap primary key sequences to max(pk).
  489 + if connection.respond_to?(:reset_pk_sequence!)
  490 + table_names.each do |table_name|
  491 + connection.reset_pk_sequence!(table_name)
  492 + end
298 493 end
299 494 end
300   - end
301 495
302   - cache_fixtures(connection, fixtures)
  496 + cache_fixtures(connection, fixtures)
  497 + end
303 498 end
304 499 end
305 500 cached_fixtures(connection, table_names)
306 501 end
307 502
  503 + # Returns a consistent identifier for +label+. This will always
  504 + # be a positive integer, and will always be the same for a given
  505 + # label, assuming the same OS, platform, and version of Ruby.
  506 + def self.identify(label)
  507 + label.to_s.hash.abs
  508 + end
  509 +
308 510 attr_reader :table_name
309 511
310 512 def initialize(connection, table_name, class_name, fixture_path, file_filter = DEFAULT_FILTER_RE)
@@ -322,12 +524,90 @@ def delete_existing_fixtures
322 524 end
323 525
324 526 def insert_fixtures
325   - values.each do |fixture|
  527 + now = ActiveRecord::Base.default_timezone == :utc ? Time.now.utc : Time.now
  528 + now = now.to_s(:db)
  529 +
  530 + # allow a standard key to be used for doing defaults in YAML
  531 + delete(assoc("DEFAULTS"))
  532 +
  533 + # track any join tables we need to insert later
  534 + habtm_fixtures = Hash.new do |h, habtm|
  535 + h[habtm] = HabtmFixtures.new(@connection, habtm.options[:join_table], nil, nil)
  536 + end
  537 +
  538 + each do |label, fixture|
  539 + row = fixture.to_hash
  540 +
  541 + if model_class && model_class < ActiveRecord::Base && !row[primary_key_name]
  542 + # fill in timestamp columns if they aren't specified
  543 + timestamp_column_names.each do |name|
  544 + row[name] = now unless row.key?(name)
  545 + end
  546 +
  547 + # interpolate the fixture label
  548 + row.each do |key, value|
  549 + row[key] = label if value == "$LABEL"
  550 + end
  551 +
  552 + # generate a primary key
  553 + row[primary_key_name] = Fixtures.identify(label)
  554 +
  555 + model_class.reflect_on_all_associations.each do |association|
  556 + case association.macro
  557 + when :belongs_to
  558 + if value = row.delete(association.name.to_s)
  559 + fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
  560 + row[fk_name] = Fixtures.identify(value)
  561 + end
  562 + when :has_and_belongs_to_many
  563 + if (targets = row.delete(association.name.to_s))
  564 + targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
  565 + join_fixtures = habtm_fixtures[association]
  566 +
  567 + targets.each do |target|
  568 + join_fixtures["#{label}_#{target}"] = Fixture.new(
  569 + { association.primary_key_name => Fixtures.identify(label),
  570 + association.association_foreign_key => Fixtures.identify(target) }, nil)
  571 + end
  572 + end
  573 + end
  574 + end
  575 + end
  576 +
326 577 @connection.insert_fixture(fixture, @table_name)
327 578 end
  579 +
  580 + # insert any HABTM join tables we discovered
  581 + habtm_fixtures.values.each do |fixture|
  582 + fixture.delete_existing_fixtures
  583 + fixture.insert_fixtures
  584 + end
328 585 end
329 586
330 587 private
  588 + class HabtmFixtures < ::Fixtures #:nodoc:
  589 + def read_fixture_files; end
  590 + end
  591 +
  592 + def model_class
  593 + @model_class ||= @class_name.is_a?(Class) ?
  594 + @class_name : @class_name.constantize rescue nil
  595 + end
  596 +
  597 + def primary_key_name
  598 + @primary_key_name ||= model_class && model_class.primary_key
  599 + end
  600 +
  601 + def timestamp_column_names
  602 + @timestamp_column_names ||= %w(created_at created_on updated_at updated_on).select do |name|
  603 + column_names.include?(name)
  604 + end
  605 + end
  606 +
  607 + def column_names
  608 + @column_names ||= @connection.columns(@table_name).collect(&:name)
  609 + end
  610 +
331 611 def read_fixture_files
332 612 if File.file?(yaml_file_path)
333 613 read_yaml_fixture_files
4 activerecord/test/associations/eager_test.rb
@@ -252,9 +252,9 @@ def test_eager_with_has_many_and_limit_and_scoped_and_explicit_conditions_on_the
252 252 end
253 253
254 254 def test_eager_with_scoped_order_using_association_limiting_without_explicit_scope
255   - posts_with_explicit_order = Post.find(:all, :conditions => 'comments.id', :include => :comments, :order => 'posts.id DESC', :limit => 2)
  255 + posts_with_explicit_order = Post.find(:all, :conditions => 'comments.id is not null', :include => :comments, :order => 'posts.id DESC', :limit => 2)
256 256 posts_with_scoped_order = Post.with_scope(:find => {:order => 'posts.id DESC'}) do
257   - Post.find(:all, :conditions => 'comments.id', :include => :comments, :limit => 2)
  257 + Post.find(:all, :conditions => 'comments.id is not null', :include => :comments, :limit => 2)
258 258 end
259 259 assert_equal posts_with_explicit_order, posts_with_scoped_order
260 260 end
2  activerecord/test/associations_test.rb
@@ -548,7 +548,7 @@ def test_find_string_ids_when_using_finder_sql
548 548 client_ary = firm.clients_using_finder_sql.find("2", "3")
549 549 assert_kind_of Array, client_ary
550 550 assert_equal 2, client_ary.size
551   - assert_equal client, client_ary.first
  551 + assert client_ary.include?(client)
552 552 end
553 553
554 554 def test_find_all
29 activerecord/test/fixtures/db_definitions/schema.rb
@@ -295,4 +295,33 @@ def create_table(*args, &block)
295 295 t.column :city, :string, :null => false
296 296 t.column :type, :string
297 297 end
  298 +
  299 + create_table :parrots, :force => true do |t|
  300 + t.column :name, :string
  301 + t.column :created_at, :datetime
  302 + t.column :created_on, :datetime
  303 + t.column :updated_at, :datetime
  304 + t.column :updated_on, :datetime
  305 + end
  306 +
  307 + create_table :pirates, :force => true do |t|
  308 + t.column :catchphrase, :string
  309 + t.column :parrot_id, :integer
  310 + t.column :created_on, :datetime
  311 + t.column :updated_on, :datetime
  312 + end
  313 +
  314 + create_table :parrots_pirates, :id => false, :force => true do |t|
  315 + t.column :parrot_id, :integer
  316 + t.column :pirate_id, :integer
  317 + end
  318 +
  319 + create_table :treasures, :force => true do |t|
  320 + t.column :name, :string
  321 + end
  322 +
  323 + create_table :parrots_treasures, :id => false, :force => true do |t|
  324 + t.column :parrot_id, :integer
  325 + t.column :treasure_id, :integer
  326 + end
298 327 end
4 activerecord/test/fixtures/parrot.rb
... ... @@ -0,0 +1,4 @@
  1 +class Parrot < ActiveRecord::Base
  2 + has_and_belongs_to_many :pirates
  3 + has_and_belongs_to_many :treasures
  4 +end
16 activerecord/test/fixtures/parrots.yml
... ... @@ -0,0 +1,16 @@
  1 +george:
  2 + name: "Curious George"
  3 + treasures: diamond, sapphire
  4 +
  5 +louis:
  6 + name: "King Louis"
  7 + treasures: [diamond, sapphire]
  8 +
  9 +frederick:
  10 + name: $LABEL
  11 +
  12 +DEFAULTS: &DEFAULTS
  13 + treasures: sapphire, ruby
  14 +
  15 +davey:
  16 + <<: *DEFAULTS
7 activerecord/test/fixtures/parrots_pirates.yml
... ... @@ -0,0 +1,7 @@
  1 +george_blackbeard:
  2 + parrot_id: <%= Fixtures.identify(:george) %>
  3 + pirate_id: <%= Fixtures.identify(:blackbeard) %>
  4 +
  5 +louis_blackbeard:
  6 + parrot_id: <%= Fixtures.identify(:louis) %>
  7 + pirate_id: <%= Fixtures.identify(:blackbeard) %>
4 activerecord/test/fixtures/pirate.rb
... ... @@ -0,0 +1,4 @@
  1 +class Pirate < ActiveRecord::Base
  2 + belongs_to :parrot
  3 + has_and_belongs_to_many :parrots
  4 +end
9 activerecord/test/fixtures/pirates.yml
... ... @@ -0,0 +1,9 @@
  1 +blackbeard:
  2 + catchphrase: "Yar."
  3 + parrot: george
  4 +
  5 +redbeard:
  6 + catchphrase: "Avast!"
  7 + parrot: louis
  8 + created_on: <%= 2.weeks.ago.to_s(:db) %>
  9 + updated_on: <%= 2.weeks.ago.to_s(:db) %>
3  activerecord/test/fixtures/treasure.rb
... ... @@ -0,0 +1,3 @@
  1 +class Treasure < ActiveRecord::Base
  2 + has_and_belongs_to_many :parrots
  3 +end
8 activerecord/test/fixtures/treasures.yml
... ... @@ -0,0 +1,8 @@
  1 +diamond:
  2 + name: $LABEL
  3 +
  4 +sapphire:
  5 + name: $LABEL
  6 +
  7 +ruby:
  8 + name: $LABEL
83 activerecord/test/fixtures_test.rb
@@ -7,6 +7,9 @@
7 7 require 'fixtures/joke'
8 8 require 'fixtures/course'
9 9 require 'fixtures/category'
  10 +require 'fixtures/parrot'
  11 +require 'fixtures/pirate'
  12 +require 'fixtures/treasure'
10 13
11 14 class FixturesTest < Test::Unit::TestCase
12 15 self.use_instantiated_fixtures = true
@@ -446,3 +449,83 @@ def test_cache
446 449 assert_equal 'Welcome to the weblog', posts(:welcome).title
447 450 end
448 451 end
  452 +
  453 +class FoxyFixturesTest < Test::Unit::TestCase
  454 + fixtures :parrots, :parrots_pirates, :pirates, :treasures
  455 +
  456 + def test_identifies_strings
  457 + assert_equal(Fixtures.identify("foo"), Fixtures.identify("foo"))
  458 + assert_not_equal(Fixtures.identify("foo"), Fixtures.identify("FOO"))
  459 + end
  460 +
  461 + def test_identifies_symbols
  462 + assert_equal(Fixtures.identify(:foo), Fixtures.identify(:foo))
  463 + end
  464 +
  465 + TIMESTAMP_COLUMNS = %w(created_at created_on updated_at updated_on)
  466 +
  467 + def test_populates_timestamp_columns
  468 + TIMESTAMP_COLUMNS.each do |property|
  469 + assert_not_nil(parrots(:george).send(property), "should set #{property}")
  470 + end
  471 + end
  472 +
  473 + def test_populates_all_columns_with_the_same_time
  474 + last = nil
  475 +
  476 + TIMESTAMP_COLUMNS.each do |property|
  477 + current = parrots(:george).send(property)
  478 + last ||= current
  479 +
  480 + assert_equal(last, current)
  481 + last = current
  482 + end
  483 + end
  484 +
  485 + def test_only_populates_columns_that_exist
  486 + assert_not_nil(pirates(:blackbeard).created_on)
  487 + assert_not_nil(pirates(:blackbeard).updated_on)
  488 + end
  489 +
  490 + def test_preserves_existing_fixture_data
  491 + assert_equal(2.weeks.ago.to_date, pirates(:redbeard).created_on.to_date)
  492 + assert_equal(2.weeks.ago.to_date, pirates(:redbeard).updated_on.to_date)
  493 + end
  494 +
  495 + def test_generates_unique_ids
  496 + assert_not_nil(parrots(:george).id)
  497 + assert_not_equal(parrots(:george).id, parrots(:louis).id)
  498 + end
  499 +
  500 + def test_resolves_belongs_to_symbols
  501 + assert_equal(parrots(:george), pirates(:blackbeard).parrot)
  502 + end
  503 +
  504 + def test_supports_join_tables
  505 + assert(pirates(:blackbeard).parrots.include?(parrots(:george)))
  506 + assert(pirates(:blackbeard).parrots.include?(parrots(:louis)))
  507 + assert(parrots(:george).pirates.include?(pirates(:blackbeard)))
  508 + end
  509 +
  510 + def test_supports_inline_habtm
  511 + assert(parrots(:george).treasures.include?(treasures(:diamond)))
  512 + assert(parrots(:george).treasures.include?(treasures(:sapphire)))
  513 + assert(!parrots(:george).treasures.include?(treasures(:ruby)))
  514 + end
  515 +
  516 + def test_supports_yaml_arrays
  517 + assert(parrots(:louis).treasures.include?(treasures(:diamond)))
  518 + assert(parrots(:louis).treasures.include?(treasures(:sapphire)))
  519 + end
  520 +
  521 + def test_strips_DEFAULTS_key
  522 + assert_raise(StandardError) { parrots(:DEFAULTS) }
  523 +
  524 + # this lets us do YAML defaults and not have an extra fixture entry
  525 + %w(sapphire ruby).each { |t| assert(parrots(:davey).treasures.include?(treasures(t))) }
  526 + end
  527 +
  528 + def test_supports_label_interpolation
  529 + assert_equal("frederick", parrots(:frederick).name)
  530 + end
  531 +end

0 comments on commit 49eafd8

Please sign in to comment.
Something went wrong with that request. Please try again.