migration_test.rb 25.6 KB
Newer Older
1
require "cases/helper"
2
require "cases/migration/helper"
3 4
require 'bigdecimal/util'

J
Jeremy Kemper 已提交
5 6
require 'models/person'
require 'models/topic'
7
require 'models/developer'
8 9

require MIGRATIONS_ROOT + "/valid/2_we_need_reminders"
10 11
require MIGRATIONS_ROOT + "/rename/1_we_need_things"
require MIGRATIONS_ROOT + "/rename/2_rename_things"
12
require MIGRATIONS_ROOT + "/decimal/1_give_me_big_numbers"
13

14
class BigNumber < ActiveRecord::Base; end
15

16
class Reminder < ActiveRecord::Base; end
17

18
class Thing < ActiveRecord::Base; end
19

20 21
class MigrationTest < ActiveRecord::TestCase
  self.use_transactional_fixtures = false
22

23
  fixtures :people
24

25 26
  def setup
    super
A
Akira Matsuda 已提交
27
    %w(reminders people_reminders prefix_reminders_suffix p_things_s).each do |table|
A
Aaron Patterson 已提交
28 29 30
      Reminder.connection.drop_table(table) rescue nil
    end
    Reminder.reset_column_information
31 32 33
    ActiveRecord::Migration.verbose = true
    ActiveRecord::Migration.message_count = 0
  end
34

35
  def teardown
36 37 38
    ActiveRecord::Base.table_name_prefix = ""
    ActiveRecord::Base.table_name_suffix = ""

39 40
    ActiveRecord::Base.connection.initialize_schema_migrations_table
    ActiveRecord::Base.connection.execute "DELETE FROM #{ActiveRecord::Migrator.schema_migrations_table_name}"
41

42
    %w(things awesome_things prefix_things_suffix p_awesome_things_s ).each do |table|
43
      Thing.connection.drop_table(table) rescue nil
44
    end
45
    Thing.reset_column_information
46

47 48 49
    %w(reminders people_reminders prefix_reminders_suffix).each do |table|
      Reminder.connection.drop_table(table) rescue nil
    end
50
    Reminder.reset_table_name
51
    Reminder.reset_column_information
52

53 54 55 56 57 58 59 60 61
    %w(last_name key bio age height wealth birthday favorite_day
       moment_of_truth male administrator funny).each do |column|
      Person.connection.remove_column('people', column) rescue nil
    end
    Person.connection.remove_column("people", "first_name") rescue nil
    Person.connection.remove_column("people", "middle_name") rescue nil
    Person.connection.add_column("people", "first_name", :string, :limit => 40)
    Person.reset_column_information
  end
62

63 64 65 66 67 68 69
  def test_migrator_versions
    migrations_path = MIGRATIONS_ROOT + "/valid"
    ActiveRecord::Migrator.migrations_paths = migrations_path

    ActiveRecord::Migrator.up(migrations_path)
    assert_equal 3, ActiveRecord::Migrator.current_version
    assert_equal 3, ActiveRecord::Migrator.last_version
70
    assert_equal false, ActiveRecord::Migrator.needs_migration?
71 72 73 74

    ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid")
    assert_equal 0, ActiveRecord::Migrator.current_version
    assert_equal 3, ActiveRecord::Migrator.last_version
75
    assert_equal true, ActiveRecord::Migrator.needs_migration?
76 77
  end

78 79 80
  def test_create_table_with_force_true_does_not_drop_nonexisting_table
    if Person.connection.table_exists?(:testings2)
      Person.connection.drop_table :testings2
81 82
    end

83 84 85
    # using a copy as we need the drop_table method to
    # continue to work for the ensure block of the test
    temp_conn = Person.connection.dup
86 87 88

    assert_not_equal temp_conn, Person.connection

89 90
    temp_conn.create_table :testings2, :force => true do |t|
      t.column :foo, :string
91
    end
92 93 94
  ensure
    Person.connection.drop_table :testings2 rescue nil
  end
95

96 97 98
  def connection
    ActiveRecord::Base.connection
  end
99

100 101 102 103
  def test_migration_instance_has_connection
    migration = Class.new(ActiveRecord::Migration).new
    assert_equal connection, migration.connection
  end
104

105 106 107 108 109 110 111 112
  def test_method_missing_delegates_to_connection
    migration = Class.new(ActiveRecord::Migration) {
      def connection
        Class.new {
          def create_table; "hi mom!"; end
        }.new
      end
    }.new
113

114
    assert_equal "hi mom!", migration.method_missing(:create_table)
115
  end
116

117 118 119 120 121 122 123 124 125 126 127 128 129 130
  def test_add_table_with_decimals
    Person.connection.drop_table :big_numbers rescue nil

    assert !BigNumber.table_exists?
    GiveMeBigNumbers.up

    assert BigNumber.create(
      :bank_balance => 1586.43,
      :big_bank_balance => BigDecimal("1000234000567.95"),
      :world_population => 6000000000,
      :my_house_population => 3,
      :value_of_e => BigDecimal("2.7182818284590452353602875")
    )

131
    b = BigNumber.first
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
    assert_not_nil b

    assert_not_nil b.bank_balance
    assert_not_nil b.big_bank_balance
    assert_not_nil b.world_population
    assert_not_nil b.my_house_population
    assert_not_nil b.value_of_e

    # TODO: set world_population >= 2**62 to cover 64-bit platforms and test
    # is_a?(Bignum)
    assert_kind_of Integer, b.world_population
    assert_equal 6000000000, b.world_population
    assert_kind_of Fixnum, b.my_house_population
    assert_equal 3, b.my_house_population
    assert_kind_of BigDecimal, b.bank_balance
    assert_equal BigDecimal("1586.43"), b.bank_balance
    assert_kind_of BigDecimal, b.big_bank_balance
    assert_equal BigDecimal("1000234000567.95"), b.big_bank_balance

    # This one is fun. The 'value_of_e' field is defined as 'DECIMAL' with
    # precision/scale explicitly left out.  By the SQL standard, numbers
    # assigned to this field should be truncated but that's seldom respected.
    if current_adapter?(:PostgreSQLAdapter)
      # - PostgreSQL changes the SQL spec on columns declared simply as
      # "decimal" to something more useful: instead of being given a scale
      # of 0, they take on the compile-time limit for precision and scale,
      # so the following should succeed unless you have used really wacky
      # compilation options
      # - SQLite2 has the default behavior of preserving all data sent in,
      # so this happens there too
      assert_kind_of BigDecimal, b.value_of_e
      assert_equal BigDecimal("2.7182818284590452353602875"), b.value_of_e
    elsif current_adapter?(:SQLite3Adapter)
      # - SQLite3 stores a float, in violation of SQL
      assert_kind_of BigDecimal, b.value_of_e
      assert_in_delta BigDecimal("2.71828182845905"), b.value_of_e, 0.00000000000001
    else
      # - SQL standard is an integer
      assert_kind_of Fixnum, b.value_of_e
      assert_equal 2, b.value_of_e
    end

    GiveMeBigNumbers.down
175
    assert_raise(ActiveRecord::StatementInvalid) { BigNumber.first }
176
  end
177

178 179 180
  def test_filtering_migrations
    assert !Person.column_methods_hash.include?(:last_name)
    assert !Reminder.table_exists?
181

182 183
    name_filter = lambda { |migration| migration.name == "ValidPeopleHaveLastNames" }
    ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", &name_filter)
184

185 186
    Person.reset_column_information
    assert Person.column_methods_hash.include?(:last_name)
187
    assert_raise(ActiveRecord::StatementInvalid) { Reminder.first }
188

189 190 191 192
    ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid", &name_filter)

    Person.reset_column_information
    assert !Person.column_methods_hash.include?(:last_name)
193
    assert_raise(ActiveRecord::StatementInvalid) { Reminder.first }
194 195 196 197 198 199 200
  end

  class MockMigration < ActiveRecord::Migration
    attr_reader :went_up, :went_down
    def initialize
      @went_up   = false
      @went_down = false
201 202
    end

203 204 205 206
    def up
      @went_up = true
      super
    end
207

208 209 210
    def down
      @went_down = true
      super
211
    end
212
  end
213

214 215 216 217
  def test_instance_based_migration_up
    migration = MockMigration.new
    assert !migration.went_up, 'have not gone up'
    assert !migration.went_down, 'have not gone down'
218

219 220 221 222
    migration.migrate :up
    assert migration.went_up, 'have gone up'
    assert !migration.went_down, 'have not gone down'
  end
223

224 225 226 227
  def test_instance_based_migration_down
    migration = MockMigration.new
    assert !migration.went_up, 'have not gone up'
    assert !migration.went_down, 'have not gone down'
228

229 230 231 232
    migration.migrate :down
    assert !migration.went_up, 'have gone up'
    assert migration.went_down, 'have not gone down'
  end
233

234 235 236 237
  def test_migrator_one_up_with_exception_and_rollback
    unless ActiveRecord::Base.connection.supports_ddl_transactions?
      skip "not supported on #{ActiveRecord::Base.connection.class}"
    end
238

239
    assert_not Person.column_methods_hash.include?(:last_name)
240

241 242 243 244 245 246 247
    migration = Struct.new(:name, :version) {
      def migrate(x); raise 'Something broke'; end
    }.new('zomg', 100)

    migrator = ActiveRecord::Migrator.new(:up, [migration], 100)

    e = assert_raise(StandardError) { migrator.migrate }
248 249 250 251

    assert_equal "An error has occurred, this and all later migrations canceled:\n\nSomething broke", e.message

    Person.reset_column_information
252
    assert_not Person.column_methods_hash.include?(:last_name)
253
  end
254

255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
  def test_schema_migrations_table_name
    ActiveRecord::Base.table_name_prefix = "prefix_"
    ActiveRecord::Base.table_name_suffix = "_suffix"
    Reminder.reset_table_name
    assert_equal "prefix_schema_migrations_suffix", ActiveRecord::Migrator.schema_migrations_table_name
    ActiveRecord::Base.table_name_prefix = ""
    ActiveRecord::Base.table_name_suffix = ""
    Reminder.reset_table_name
    assert_equal "schema_migrations", ActiveRecord::Migrator.schema_migrations_table_name
  end

  def test_proper_table_name
    assert_equal "table", ActiveRecord::Migrator.proper_table_name('table')
    assert_equal "table", ActiveRecord::Migrator.proper_table_name(:table)
    assert_equal "reminders", ActiveRecord::Migrator.proper_table_name(Reminder)
    Reminder.reset_table_name
    assert_equal Reminder.table_name, ActiveRecord::Migrator.proper_table_name(Reminder)

    # Use the model's own prefix/suffix if a model is given
    ActiveRecord::Base.table_name_prefix = "ARprefix_"
    ActiveRecord::Base.table_name_suffix = "_ARsuffix"
    Reminder.table_name_prefix = 'prefix_'
    Reminder.table_name_suffix = '_suffix'
    Reminder.reset_table_name
    assert_equal "prefix_reminders_suffix", ActiveRecord::Migrator.proper_table_name(Reminder)
    Reminder.table_name_prefix = ''
    Reminder.table_name_suffix = ''
    Reminder.reset_table_name

    # Use AR::Base's prefix/suffix if string or symbol is given
    ActiveRecord::Base.table_name_prefix = "prefix_"
    ActiveRecord::Base.table_name_suffix = "_suffix"
    Reminder.reset_table_name
    assert_equal "prefix_table_suffix", ActiveRecord::Migrator.proper_table_name('table')
    assert_equal "prefix_table_suffix", ActiveRecord::Migrator.proper_table_name(:table)
  end

  def test_rename_table_with_prefix_and_suffix
    assert !Thing.table_exists?
294 295
    ActiveRecord::Base.table_name_prefix = 'p_'
    ActiveRecord::Base.table_name_suffix = '_s'
296 297 298 299 300
    Thing.reset_table_name
    Thing.reset_sequence_name
    WeNeedThings.up

    assert Thing.create("content" => "hello world")
301
    assert_equal "hello world", Thing.first.content
302 303

    RenameThings.up
304
    Thing.table_name = "p_awesome_things_s"
305

306
    assert_equal "hello world", Thing.first.content
307 308 309 310 311 312 313 314 315 316 317 318 319
  ensure
    Thing.reset_table_name
    Thing.reset_sequence_name
  end

  def test_add_drop_table_with_prefix_and_suffix
    assert !Reminder.table_exists?
    ActiveRecord::Base.table_name_prefix = 'prefix_'
    ActiveRecord::Base.table_name_suffix = '_suffix'
    Reminder.reset_table_name
    Reminder.reset_sequence_name
    WeNeedReminders.up
    assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
320
    assert_equal "hello world", Reminder.first.content
321 322

    WeNeedReminders.down
323
    assert_raise(ActiveRecord::StatementInvalid) { Reminder.first }
324 325 326
  ensure
    Reminder.reset_sequence_name
  end
327

328 329
  def test_create_table_with_binary_column
    Person.connection.drop_table :binary_testings rescue nil
330

331 332
    assert_nothing_raised {
      Person.connection.create_table :binary_testings do |t|
333
        t.column "data", :binary, :null => false
334
      end
335 336 337 338
    }

    columns = Person.connection.columns(:binary_testings)
    data_column = columns.detect { |c| c.name == "data" }
339

J
Jon Leighton 已提交
340
    assert_nil data_column.default
341

342 343 344 345
    Person.connection.drop_table :binary_testings rescue nil
  end

  def test_create_table_with_custom_sequence_name
346
    skip "not supported" unless current_adapter? :OracleAdapter
347

348 349 350 351 352 353
    # table name is 29 chars, the standard sequence name will
    # be 33 chars and should be shortened
    assert_nothing_raised do
      begin
        Person.connection.create_table :table_with_name_thats_just_ok do |t|
          t.column :foo, :string, :null => false
354
        end
355 356
      ensure
        Person.connection.drop_table :table_with_name_thats_just_ok rescue nil
357
      end
358
    end
359

360 361 362 363 364 365
    # should be all good w/ a custom sequence name
    assert_nothing_raised do
      begin
        Person.connection.create_table :table_with_name_thats_just_ok,
                                       :sequence_name => 'suitably_short_seq' do |t|
          t.column :foo, :string, :null => false
366 367 368
        end

        Person.connection.execute("select suitably_short_seq.nextval from dual")
369 370

      ensure
371 372
        Person.connection.drop_table :table_with_name_thats_just_ok,
                                     :sequence_name => 'suitably_short_seq' rescue nil
373
      end
374
    end
375

376 377 378 379
    # confirm the custom sequence got dropped
    assert_raise(ActiveRecord::StatementInvalid) do
      Person.connection.execute("select suitably_short_seq.nextval from dual")
    end
380
  end
381

382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
  def test_out_of_range_limit_should_raise
    skip("MySQL and PostgreSQL only") unless current_adapter?(:MysqlAdapter, :Mysql2Adapter, :PostgreSQLAdapter)

    Person.connection.drop_table :test_limits rescue nil
    assert_raise(ActiveRecord::ActiveRecordError, "integer limit didn't raise") do
      Person.connection.create_table :test_integer_limits, :force => true do |t|
        t.column :bigone, :integer, :limit => 10
      end
    end

    unless current_adapter?(:PostgreSQLAdapter)
      assert_raise(ActiveRecord::ActiveRecordError, "text limit didn't raise") do
        Person.connection.create_table :test_text_limits, :force => true do |t|
          t.column :bigtext, :text, :limit => 0xfffffffff
        end
      end
    end

    Person.connection.drop_table :test_limits rescue nil
  end

403 404 405 406
  protected
    def with_env_tz(new_tz = 'US/Eastern')
      old_tz, ENV['TZ'] = ENV['TZ'], new_tz
      yield
407
    ensure
408
      old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
409
    end
410
end
411

412 413 414 415 416
class ReservedWordsMigrationTest < ActiveRecord::TestCase
  def test_drop_index_from_table_named_values
    connection = Person.connection
    connection.create_table :values, :force => true do |t|
      t.integer :value
417
    end
418

419 420 421
    assert_nothing_raised do
      connection.add_index :values, :value
      connection.remove_index :values, :column => :value
422
    end
423

424 425 426 427 428 429 430 431 432 433
    connection.drop_table :values rescue nil
  end
end

if ActiveRecord::Base.connection.supports_bulk_alter?
  class BulkAlterTableMigrationsTest < ActiveRecord::TestCase
    def setup
      @connection = Person.connection
      @connection.create_table(:delete_me, :force => true) {|t| }
    end
434

435 436 437
    def teardown
      Person.connection.drop_table(:delete_me) rescue nil
    end
438

439 440
    def test_adding_multiple_columns
      assert_queries(1) do
441
        with_bulk_change_table do |t|
442
          t.column :name, :string
443
          t.string :qualification, :experience
444 445 446
          t.integer :age, :default => 0
          t.date :birthdate
          t.timestamps
447
        end
448
      end
449

450 451 452 453
      assert_equal 8, columns.size
      [:name, :qualification, :experience].each {|s| assert_equal :string, column(s).type }
      assert_equal 0, column(:age).default
    end
454

455 456 457
    def test_removing_columns
      with_bulk_change_table do |t|
        t.string :qualification, :experience
458 459
      end

460
      [:qualification, :experience].each {|c| assert column(c) }
461

462 463 464 465
      assert_queries(1) do
        with_bulk_change_table do |t|
          t.remove :qualification, :experience
          t.string :qualification_experience
466
        end
467
      end
468

469 470 471
      [:qualification, :experience].each {|c| assert ! column(c) }
      assert column(:qualification_experience)
    end
472

473 474 475 476 477
    def test_adding_indexes
      with_bulk_change_table do |t|
        t.string :username
        t.string :name
        t.integer :age
478 479
      end

480 481
      # Adding an index fires a query every time to check if an index already exists or not
      assert_queries(3) do
482
        with_bulk_change_table do |t|
483 484
          t.index :username, :unique => true, :name => :awesome_username_index
          t.index [:name, :age]
485
        end
486
      end
487

488
      assert_equal 2, indexes.size
489

490 491 492
      name_age_index = index(:index_delete_me_on_name_and_age)
      assert_equal ['name', 'age'].sort, name_age_index.columns.sort
      assert ! name_age_index.unique
493

494 495
      assert index(:awesome_username_index).unique
    end
496

497 498 499 500
    def test_removing_index
      with_bulk_change_table do |t|
        t.string :name
        t.index :name
501
      end
502

503 504 505
      assert index(:index_delete_me_on_name)

      assert_queries(3) do
506
        with_bulk_change_table do |t|
507 508
          t.remove_index :name
          t.index :name, :name => :new_name_index, :unique => true
509
        end
510
      end
511

512
      assert ! index(:index_delete_me_on_name)
513

514 515 516
      new_name_index = index(:new_name_index)
      assert new_name_index.unique
    end
517

518 519 520 521
    def test_changing_columns
      with_bulk_change_table do |t|
        t.string :name
        t.date :birthdate
522
      end
523

524 525
      assert ! column(:name).default
      assert_equal :date, column(:birthdate).type
526

527 528 529
      # One query for columns (delete_me table)
      # One query for primary key (delete_me table)
      # One query to do the bulk change
530
      assert_queries(3, :ignore_none => true) do
531 532 533
        with_bulk_change_table do |t|
          t.change :name, :string, :default => 'NONAME'
          t.change :birthdate, :datetime
534
        end
535 536
      end

537 538 539
      assert_equal 'NONAME', column(:name).default
      assert_equal :datetime, column(:birthdate).type
    end
540

541
    protected
542

543 544 545
    def with_bulk_change_table
      # Reset columns/indexes cache as we're changing the table
      @columns = @indexes = nil
546

547 548
      Person.connection.change_table(:delete_me, :bulk => true) do |t|
        yield t
549
      end
550
    end
551

552 553 554
    def column(name)
      columns.detect {|c| c.name == name.to_s }
    end
555

556 557
    def columns
      @columns ||= Person.connection.columns('delete_me')
558 559
    end

560 561
    def index(name)
      indexes.detect {|i| i.name == name.to_s }
562 563
    end

564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
    def indexes
      @indexes ||= Person.connection.indexes('delete_me')
    end
  end # AlterTableMigrationsTest

end

class CopyMigrationsTest < ActiveRecord::TestCase
  def setup
  end

  def clear
    ActiveRecord::Base.timestamped_migrations = true
    to_delete = Dir[@migrations_path + "/*.rb"] - @existing_migrations
    File.delete(*to_delete)
  end

  def test_copying_migrations_without_timestamps
    ActiveRecord::Base.timestamped_migrations = false
    @migrations_path = MIGRATIONS_ROOT + "/valid"
    @existing_migrations = Dir[@migrations_path + "/*.rb"]

    copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy"})
    assert File.exists?(@migrations_path + "/4_people_have_hobbies.bukkits.rb")
    assert File.exists?(@migrations_path + "/5_people_have_descriptions.bukkits.rb")
    assert_equal [@migrations_path + "/4_people_have_hobbies.bukkits.rb", @migrations_path + "/5_people_have_descriptions.bukkits.rb"], copied.map(&:filename)

    expected = "# This migration comes from bukkits (originally 1)"
    assert_equal expected, IO.readlines(@migrations_path + "/4_people_have_hobbies.bukkits.rb")[0].chomp

    files_count = Dir[@migrations_path + "/*.rb"].length
    copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy"})
    assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
    assert copied.empty?
  ensure
    clear
  end

  def test_copying_migrations_without_timestamps_from_2_sources
    ActiveRecord::Base.timestamped_migrations = false
    @migrations_path = MIGRATIONS_ROOT + "/valid"
    @existing_migrations = Dir[@migrations_path + "/*.rb"]

607
    sources = {}
608 609 610 611 612 613 614 615 616 617 618 619 620 621
    sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy"
    sources[:omg] = MIGRATIONS_ROOT + "/to_copy2"
    ActiveRecord::Migration.copy(@migrations_path, sources)
    assert File.exists?(@migrations_path + "/4_people_have_hobbies.bukkits.rb")
    assert File.exists?(@migrations_path + "/5_people_have_descriptions.bukkits.rb")
    assert File.exists?(@migrations_path + "/6_create_articles.omg.rb")
    assert File.exists?(@migrations_path + "/7_create_comments.omg.rb")

    files_count = Dir[@migrations_path + "/*.rb"].length
    ActiveRecord::Migration.copy(@migrations_path, sources)
    assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
  ensure
    clear
  end
622

623 624 625
  def test_copying_migrations_with_timestamps
    @migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
    @existing_migrations = Dir[@migrations_path + "/*.rb"]
626

627 628 629 630 631 632 633
    Time.travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
      copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
      assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
      assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
      expected = [@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb",
                  @migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb"]
      assert_equal expected, copied.map(&:filename)
634

635
      files_count = Dir[@migrations_path + "/*.rb"].length
636
      copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
637 638 639
      assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
      assert copied.empty?
    end
640 641 642
  ensure
    clear
  end
643

644 645 646
  def test_copying_migrations_with_timestamps_from_2_sources
    @migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
    @existing_migrations = Dir[@migrations_path + "/*.rb"]
647

648
    sources = {}
649 650 651 652 653 654 655 656 657 658
    sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy_with_timestamps"
    sources[:omg]     = MIGRATIONS_ROOT + "/to_copy_with_timestamps2"

    Time.travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
      copied = ActiveRecord::Migration.copy(@migrations_path, sources)
      assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
      assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
      assert File.exists?(@migrations_path + "/20100726101012_create_articles.omg.rb")
      assert File.exists?(@migrations_path + "/20100726101013_create_comments.omg.rb")
      assert_equal 4, copied.length
659 660 661 662 663

      files_count = Dir[@migrations_path + "/*.rb"].length
      ActiveRecord::Migration.copy(@migrations_path, sources)
      assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
    end
664 665 666
  ensure
    clear
  end
667

668 669 670
  def test_copying_migrations_with_timestamps_to_destination_with_timestamps_in_future
    @migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
    @existing_migrations = Dir[@migrations_path + "/*.rb"]
671

672 673 674 675
    Time.travel_to(Time.utc(2010, 2, 20, 10, 10, 10)) do
      ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
      assert File.exists?(@migrations_path + "/20100301010102_people_have_hobbies.bukkits.rb")
      assert File.exists?(@migrations_path + "/20100301010103_people_have_descriptions.bukkits.rb")
676

677 678 679 680
      files_count = Dir[@migrations_path + "/*.rb"].length
      copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
      assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
      assert copied.empty?
681
    end
682 683 684
  ensure
    clear
  end
685

686 687 688
  def test_skipping_migrations
    @migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
    @existing_migrations = Dir[@migrations_path + "/*.rb"]
689 690

    sources = {}
691 692
    sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy_with_timestamps"
    sources[:omg]     = MIGRATIONS_ROOT + "/to_copy_with_name_collision"
693

694 695 696 697
    skipped = []
    on_skip = Proc.new { |name, migration| skipped << "#{name} #{migration.name}" }
    copied = ActiveRecord::Migration.copy(@migrations_path, sources, :on_skip => on_skip)
    assert_equal 2, copied.length
698

699 700 701 702 703
    assert_equal 1, skipped.length
    assert_equal ["omg PeopleHaveHobbies"], skipped
  ensure
    clear
  end
704

705 706 707
  def test_skip_is_not_called_if_migrations_are_from_the_same_plugin
    @migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
    @existing_migrations = Dir[@migrations_path + "/*.rb"]
708

709
    sources = {}
710
    sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy_with_timestamps"
711

712 713 714 715
    skipped = []
    on_skip = Proc.new { |name, migration| skipped << "#{name} #{migration.name}" }
    copied = ActiveRecord::Migration.copy(@migrations_path, sources, :on_skip => on_skip)
    ActiveRecord::Migration.copy(@migrations_path, sources, :on_skip => on_skip)
716

717 718 719 720 721
    assert_equal 2, copied.length
    assert_equal 0, skipped.length
  ensure
    clear
  end
722

723 724 725
  def test_copying_migrations_to_non_existing_directory
    @migrations_path = MIGRATIONS_ROOT + "/non_existing"
    @existing_migrations = []
726

727 728 729 730
    Time.travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
      copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
      assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
      assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
731 732
      assert_equal 2, copied.length
    end
733 734 735 736
  ensure
    clear
    Dir.delete(@migrations_path)
  end
737

738 739 740
  def test_copying_migrations_to_empty_directory
    @migrations_path = MIGRATIONS_ROOT + "/empty"
    @existing_migrations = []
741

742 743 744 745
    Time.travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
      copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
      assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
      assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
746
      assert_equal 2, copied.length
747
    end
748 749
  ensure
    clear
750
  end
751
end