activerecord-import-uuid 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. data/.gitignore +32 -0
  2. data/.rubocop.yml +49 -0
  3. data/.rubocop_todo.yml +36 -0
  4. data/.travis.yml +52 -0
  5. data/Brewfile +3 -0
  6. data/CHANGELOG.md +87 -0
  7. data/Gemfile +54 -0
  8. data/LICENSE +56 -0
  9. data/README.markdown +101 -0
  10. data/Rakefile +66 -0
  11. data/activerecord-import.gemspec +23 -0
  12. data/benchmarks/README +32 -0
  13. data/benchmarks/benchmark.rb +67 -0
  14. data/benchmarks/lib/base.rb +138 -0
  15. data/benchmarks/lib/cli_parser.rb +106 -0
  16. data/benchmarks/lib/float.rb +15 -0
  17. data/benchmarks/lib/mysql2_benchmark.rb +19 -0
  18. data/benchmarks/lib/output_to_csv.rb +19 -0
  19. data/benchmarks/lib/output_to_html.rb +64 -0
  20. data/benchmarks/models/test_innodb.rb +3 -0
  21. data/benchmarks/models/test_memory.rb +3 -0
  22. data/benchmarks/models/test_myisam.rb +3 -0
  23. data/benchmarks/schema/mysql_schema.rb +16 -0
  24. data/gemfiles/3.2.gemfile +3 -0
  25. data/gemfiles/4.0.gemfile +3 -0
  26. data/gemfiles/4.1.gemfile +3 -0
  27. data/gemfiles/4.2.gemfile +7 -0
  28. data/gemfiles/5.0.gemfile +3 -0
  29. data/lib/activerecord-import.rb +19 -0
  30. data/lib/activerecord-import/active_record/adapters/abstract_adapter.rb +9 -0
  31. data/lib/activerecord-import/active_record/adapters/jdbcmysql_adapter.rb +6 -0
  32. data/lib/activerecord-import/active_record/adapters/jdbcpostgresql_adapter.rb +6 -0
  33. data/lib/activerecord-import/active_record/adapters/mysql2_adapter.rb +6 -0
  34. data/lib/activerecord-import/active_record/adapters/postgresql_adapter.rb +6 -0
  35. data/lib/activerecord-import/active_record/adapters/seamless_database_pool_adapter.rb +7 -0
  36. data/lib/activerecord-import/active_record/adapters/sqlite3_adapter.rb +6 -0
  37. data/lib/activerecord-import/adapters/abstract_adapter.rb +78 -0
  38. data/lib/activerecord-import/adapters/em_mysql2_adapter.rb +5 -0
  39. data/lib/activerecord-import/adapters/mysql2_adapter.rb +5 -0
  40. data/lib/activerecord-import/adapters/mysql_adapter.rb +114 -0
  41. data/lib/activerecord-import/adapters/postgresql_adapter.rb +144 -0
  42. data/lib/activerecord-import/adapters/sqlite3_adapter.rb +51 -0
  43. data/lib/activerecord-import/base.rb +38 -0
  44. data/lib/activerecord-import/import.rb +660 -0
  45. data/lib/activerecord-import/mysql2.rb +7 -0
  46. data/lib/activerecord-import/postgresql.rb +7 -0
  47. data/lib/activerecord-import/sqlite3.rb +7 -0
  48. data/lib/activerecord-import/synchronize.rb +66 -0
  49. data/lib/activerecord-import/value_sets_parser.rb +55 -0
  50. data/lib/activerecord-import/version.rb +5 -0
  51. data/test/adapters/jdbcmysql.rb +1 -0
  52. data/test/adapters/jdbcpostgresql.rb +1 -0
  53. data/test/adapters/mysql2.rb +1 -0
  54. data/test/adapters/mysql2_makara.rb +1 -0
  55. data/test/adapters/mysql2spatial.rb +1 -0
  56. data/test/adapters/postgis.rb +1 -0
  57. data/test/adapters/postgresql.rb +1 -0
  58. data/test/adapters/postgresql_makara.rb +1 -0
  59. data/test/adapters/seamless_database_pool.rb +1 -0
  60. data/test/adapters/spatialite.rb +1 -0
  61. data/test/adapters/sqlite3.rb +1 -0
  62. data/test/database.yml.sample +52 -0
  63. data/test/import_test.rb +574 -0
  64. data/test/jdbcmysql/import_test.rb +6 -0
  65. data/test/jdbcpostgresql/import_test.rb +5 -0
  66. data/test/models/book.rb +7 -0
  67. data/test/models/chapter.rb +4 -0
  68. data/test/models/discount.rb +3 -0
  69. data/test/models/end_note.rb +4 -0
  70. data/test/models/group.rb +3 -0
  71. data/test/models/promotion.rb +3 -0
  72. data/test/models/question.rb +3 -0
  73. data/test/models/rule.rb +3 -0
  74. data/test/models/topic.rb +9 -0
  75. data/test/models/widget.rb +24 -0
  76. data/test/mysql2/import_test.rb +5 -0
  77. data/test/mysql2_makara/import_test.rb +6 -0
  78. data/test/mysqlspatial2/import_test.rb +6 -0
  79. data/test/postgis/import_test.rb +4 -0
  80. data/test/postgresql/import_test.rb +8 -0
  81. data/test/schema/generic_schema.rb +144 -0
  82. data/test/schema/mysql_schema.rb +16 -0
  83. data/test/schema/version.rb +10 -0
  84. data/test/sqlite3/import_test.rb +52 -0
  85. data/test/support/active_support/test_case_extensions.rb +70 -0
  86. data/test/support/assertions.rb +73 -0
  87. data/test/support/factories.rb +57 -0
  88. data/test/support/generate.rb +29 -0
  89. data/test/support/mysql/import_examples.rb +85 -0
  90. data/test/support/postgresql/import_examples.rb +242 -0
  91. data/test/support/shared_examples/on_duplicate_key_update.rb +103 -0
  92. data/test/support/shared_examples/recursive_import.rb +122 -0
  93. data/test/synchronize_test.rb +33 -0
  94. data/test/test_helper.rb +59 -0
  95. data/test/travis/database.yml +62 -0
  96. data/test/value_sets_bytes_parser_test.rb +93 -0
  97. data/test/value_sets_records_parser_test.rb +32 -0
  98. metadata +225 -0
@@ -0,0 +1,6 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ require File.expand_path(File.dirname(__FILE__) + '/../support/assertions')
4
+ require File.expand_path(File.dirname(__FILE__) + '/../support/mysql/import_examples')
5
+
6
+ should_support_mysql_import_functionality
@@ -0,0 +1,5 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ require File.expand_path(File.dirname(__FILE__) + '/../support/postgresql/import_examples')
4
+
5
+ should_support_postgresql_import_functionality
@@ -0,0 +1,7 @@
1
+ class Book < ActiveRecord::Base
2
+ belongs_to :topic, inverse_of: :books
3
+ has_many :chapters, inverse_of: :book
4
+ has_many :discounts, as: :discountable
5
+ has_many :end_notes, inverse_of: :book
6
+ enum status: [:draft, :published] if ENV['AR_VERSION'].to_f >= 4.1
7
+ end
@@ -0,0 +1,4 @@
1
+ class Chapter < ActiveRecord::Base
2
+ belongs_to :book, inverse_of: :chapters
3
+ validates :title, presence: true
4
+ end
@@ -0,0 +1,3 @@
1
+ class Discount < ActiveRecord::Base
2
+ belongs_to :discountable, polymorphic: true
3
+ end
@@ -0,0 +1,4 @@
1
+ class EndNote < ActiveRecord::Base
2
+ belongs_to :book, inverse_of: :end_notes
3
+ validates :note, presence: true
4
+ end
@@ -0,0 +1,3 @@
1
+ class Group < ActiveRecord::Base
2
+ self.table_name = 'group'
3
+ end
@@ -0,0 +1,3 @@
1
+ class Promotion < ActiveRecord::Base
2
+ self.primary_key = :promotion_id
3
+ end
@@ -0,0 +1,3 @@
1
+ class Question < ActiveRecord::Base
2
+ has_one :rule
3
+ end
@@ -0,0 +1,3 @@
1
+ class Rule < ActiveRecord::Base
2
+ belongs_to :question
3
+ end
@@ -0,0 +1,9 @@
1
+ class Topic < ActiveRecord::Base
2
+ validates_presence_of :author_name
3
+ validates :title, numericality: { only_integer: true }, on: :context_test
4
+
5
+ has_many :books, inverse_of: :topic
6
+ belongs_to :parent, class_name: "Topic"
7
+
8
+ composed_of :description, mapping: [%w(title title), %w(author_name author_name)], allow_nil: true, class_name: "TopicDescription"
9
+ end
@@ -0,0 +1,24 @@
1
+ class CustomCoder
2
+ def load(value)
3
+ if value.nil?
4
+ {}
5
+ else
6
+ YAML.load(value)
7
+ end
8
+ end
9
+
10
+ def dump(value)
11
+ YAML.dump(value)
12
+ end
13
+ end
14
+
15
+ class Widget < ActiveRecord::Base
16
+ self.primary_key = :w_id
17
+
18
+ default_scope -> { where(active: true) }
19
+
20
+ serialize :data, Hash
21
+ serialize :json_data, JSON
22
+ serialize :unspecified_data
23
+ serialize :custom_data, CustomCoder.new
24
+ end
@@ -0,0 +1,5 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/../support/assertions')
3
+ require File.expand_path(File.dirname(__FILE__) + '/../support/mysql/import_examples')
4
+
5
+ should_support_mysql_import_functionality
@@ -0,0 +1,6 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ require File.expand_path(File.dirname(__FILE__) + '/../support/assertions')
4
+ require File.expand_path(File.dirname(__FILE__) + '/../support/mysql/import_examples')
5
+
6
+ should_support_mysql_import_functionality
@@ -0,0 +1,6 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ require File.expand_path(File.dirname(__FILE__) + '/../support/assertions')
4
+ require File.expand_path(File.dirname(__FILE__) + '/../support/mysql/import_examples')
5
+
6
+ should_support_mysql_import_functionality
@@ -0,0 +1,4 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/../support/postgresql/import_examples')
3
+
4
+ should_support_postgresql_import_functionality
@@ -0,0 +1,8 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/../support/postgresql/import_examples')
3
+
4
+ should_support_postgresql_import_functionality
5
+
6
+ if ActiveRecord::Base.connection.supports_on_duplicate_key_update?
7
+ should_support_postgresql_upsert_functionality
8
+ end
@@ -0,0 +1,144 @@
1
+ ActiveRecord::Schema.define do
2
+ create_table :schema_info, force: :cascade do |t|
3
+ t.integer :version, unique: true
4
+ end
5
+ SchemaInfo.create version: SchemaInfo::VERSION
6
+
7
+ create_table :group, force: :cascade do |t|
8
+ t.string :order
9
+ t.timestamps null: true
10
+ end
11
+
12
+ create_table :topics, force: :cascade do |t|
13
+ t.string :title, null: false
14
+ t.string :author_name
15
+ t.string :author_email_address
16
+ t.datetime :written_on
17
+ t.time :bonus_time
18
+ t.datetime :last_read
19
+ t.text :content
20
+ t.boolean :approved, default: '1'
21
+ t.integer :replies_count
22
+ t.integer :parent_id
23
+ t.string :type
24
+ t.datetime :created_at
25
+ t.datetime :created_on
26
+ t.datetime :updated_at
27
+ t.datetime :updated_on
28
+ end
29
+
30
+ create_table :projects, force: :cascade do |t|
31
+ t.string :name
32
+ t.string :type
33
+ end
34
+
35
+ create_table :developers, force: :cascade do |t|
36
+ t.string :name
37
+ t.integer :salary, default: '70000'
38
+ t.datetime :created_at
39
+ t.integer :team_id
40
+ t.datetime :updated_at
41
+ end
42
+
43
+ create_table :addresses, force: :cascade do |t|
44
+ t.string :address
45
+ t.string :city
46
+ t.string :state
47
+ t.string :zip
48
+ t.integer :developer_id
49
+ end
50
+
51
+ create_table :teams, force: :cascade do |t|
52
+ t.string :name
53
+ end
54
+
55
+ create_table :books, force: :cascade do |t|
56
+ t.string :title, null: false
57
+ t.string :publisher, null: false, default: 'Default Publisher'
58
+ t.string :author_name, null: false
59
+ t.datetime :created_at
60
+ t.datetime :created_on
61
+ t.datetime :updated_at
62
+ t.datetime :updated_on
63
+ t.date :publish_date
64
+ t.integer :topic_id
65
+ t.boolean :for_sale, default: true
66
+ t.integer :status, default: 0
67
+ end
68
+
69
+ create_table :chapters, force: :cascade do |t|
70
+ t.string :title
71
+ t.integer :book_id, null: false
72
+ t.datetime :created_at
73
+ t.datetime :updated_at
74
+ end
75
+
76
+ create_table :end_notes, force: :cascade do |t|
77
+ t.string :note
78
+ t.integer :book_id, null: false
79
+ t.datetime :created_at
80
+ t.datetime :updated_at
81
+ end
82
+
83
+ create_table :languages, force: :cascade do |t|
84
+ t.string :name
85
+ t.integer :developer_id
86
+ end
87
+
88
+ create_table :shopping_carts, force: :cascade do |t|
89
+ t.string :name, null: true
90
+ t.datetime :created_at
91
+ t.datetime :updated_at
92
+ end
93
+
94
+ create_table :cart_items, force: :cascade do |t|
95
+ t.string :shopping_cart_id, null: false
96
+ t.string :book_id, null: false
97
+ t.integer :copies, default: 1
98
+ t.datetime :created_at
99
+ t.datetime :updated_at
100
+ end
101
+
102
+ add_index :cart_items, [:shopping_cart_id, :book_id], unique: true, name: 'uk_shopping_cart_books'
103
+
104
+ create_table :animals, force: :cascade do |t|
105
+ t.string :name, null: false
106
+ t.string :size, default: nil
107
+ t.datetime :created_at
108
+ t.datetime :updated_at
109
+ end
110
+
111
+ add_index :animals, [:name], unique: true, name: 'uk_animals'
112
+
113
+ create_table :widgets, id: false, force: :cascade do |t|
114
+ t.integer :w_id
115
+ t.boolean :active, default: false
116
+ t.text :data
117
+ t.text :json_data
118
+ t.text :unspecified_data
119
+ t.text :custom_data
120
+ end
121
+
122
+ create_table :promotions, primary_key: :promotion_id, force: :cascade do |t|
123
+ t.string :code
124
+ t.string :description
125
+ t.decimal :discount
126
+ end
127
+
128
+ add_index :promotions, [:code], unique: true, name: 'uk_code'
129
+
130
+ create_table :discounts, force: :cascade do |t|
131
+ t.decimal :amount
132
+ t.integer :discountable_id
133
+ t.string :discountable_type
134
+ end
135
+
136
+ create_table :rules, force: :cascade do |t|
137
+ t.string :condition_text
138
+ t.integer :question_id
139
+ end
140
+
141
+ create_table :questions, force: :cascade do |t|
142
+ t.string :body
143
+ end
144
+ end
@@ -0,0 +1,16 @@
1
+ ActiveRecord::Schema.define do
2
+ create_table :books, options: 'ENGINE=MyISAM', force: true do |t|
3
+ t.column :title, :string, null: false
4
+ t.column :publisher, :string, null: false, default: 'Default Publisher'
5
+ t.column :author_name, :string, null: false
6
+ t.column :created_at, :datetime
7
+ t.column :created_on, :datetime
8
+ t.column :updated_at, :datetime
9
+ t.column :updated_on, :datetime
10
+ t.column :publish_date, :date
11
+ t.column :topic_id, :integer
12
+ t.column :for_sale, :boolean, default: true
13
+ t.column :status, :integer
14
+ end
15
+ execute "ALTER TABLE books ADD FULLTEXT( `title`, `publisher`, `author_name` )"
16
+ end
@@ -0,0 +1,10 @@
1
+ class SchemaInfo < ActiveRecord::Base
2
+ if respond_to?(:table_name=)
3
+ self.table_name = 'schema_info'
4
+ else
5
+ # this is becoming deprecated in ActiveRecord but not all adapters supported it
6
+ # at this time
7
+ set_table_name 'schema_info'
8
+ end
9
+ VERSION = 12
10
+ end
@@ -0,0 +1,52 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ should_support_recursive_import
4
+
5
+ describe "#supports_imports?" do
6
+ context "and SQLite is 3.7.11 or higher" do
7
+ it "supports import" do
8
+ version = ActiveRecord::ConnectionAdapters::SQLite3Adapter::Version.new("3.7.11")
9
+ assert ActiveRecord::Base.supports_import?(version)
10
+
11
+ version = ActiveRecord::ConnectionAdapters::SQLite3Adapter::Version.new("3.7.12")
12
+ assert ActiveRecord::Base.supports_import?(version)
13
+ end
14
+ end
15
+
16
+ context "and SQLite less than 3.7.11" do
17
+ it "doesn't support import" do
18
+ version = ActiveRecord::ConnectionAdapters::SQLite3Adapter::Version.new("3.7.10")
19
+ assert !ActiveRecord::Base.supports_import?(version)
20
+ end
21
+ end
22
+ end
23
+
24
+ describe "#import" do
25
+ it "imports with a single insert on SQLite 3.7.11 or higher" do
26
+ assert_difference "Topic.count", +507 do
27
+ result = Topic.import Build(7, :topics)
28
+ assert_equal 1, result.num_inserts, "Failed to issue a single INSERT statement. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
29
+ assert_equal 7, Topic.count, "Failed to insert all records. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
30
+
31
+ result = Topic.import Build(500, :topics)
32
+ assert_equal 1, result.num_inserts, "Failed to issue a single INSERT statement. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
33
+ assert_equal 507, Topic.count, "Failed to insert all records. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
34
+ end
35
+ end
36
+
37
+ it "imports with a two inserts on SQLite 3.7.11 or higher" do
38
+ assert_difference "Topic.count", +501 do
39
+ result = Topic.import Build(501, :topics)
40
+ assert_equal 2, result.num_inserts, "Failed to issue a two INSERT statements. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
41
+ assert_equal 501, Topic.count, "Failed to insert all records. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
42
+ end
43
+ end
44
+
45
+ it "imports with a five inserts on SQLite 3.7.11 or higher" do
46
+ assert_difference "Topic.count", +2500 do
47
+ result = Topic.import Build(2500, :topics)
48
+ assert_equal 5, result.num_inserts, "Failed to issue a two INSERT statements. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
49
+ assert_equal 2500, Topic.count, "Failed to insert all records. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,70 @@
1
+ class ActiveSupport::TestCase
2
+ include ActiveRecord::TestFixtures
3
+ self.use_transactional_fixtures = true
4
+
5
+ class << self
6
+ def requires_active_record_version(version_string, &blk)
7
+ return unless Gem::Dependency.new('', version_string).match?('', ActiveRecord::VERSION::STRING)
8
+ instance_eval(&blk)
9
+ end
10
+
11
+ def assertion(name, &block)
12
+ mc = class << self; self; end
13
+ mc.class_eval do
14
+ define_method(name) do
15
+ it(name, &block)
16
+ end
17
+ end
18
+ end
19
+
20
+ def asssertion_group(name, &block)
21
+ mc = class << self; self; end
22
+ mc.class_eval do
23
+ define_method(name, &block)
24
+ end
25
+ end
26
+
27
+ def macro(name, &block)
28
+ class_eval do
29
+ define_method(name, &block)
30
+ end
31
+ end
32
+
33
+ def describe(description, toplevel = nil, &blk)
34
+ text = toplevel ? description : "#{name} #{description}"
35
+ klass = Class.new(self)
36
+
37
+ klass.class_eval <<-RUBY_EVAL
38
+ def self.name
39
+ "#{text}"
40
+ end
41
+ RUBY_EVAL
42
+
43
+ # do not inherit test methods from the superclass
44
+ klass.class_eval do
45
+ instance_methods.grep(/^test.+/) do |method|
46
+ undef_method method
47
+ end
48
+ end
49
+
50
+ klass.instance_eval(&blk)
51
+ end
52
+ alias context describe
53
+
54
+ def let(name, &blk)
55
+ define_method(name) do
56
+ instance_variable_name = "@__let_#{name}"
57
+ return instance_variable_get(instance_variable_name) if instance_variable_defined?(instance_variable_name)
58
+ instance_variable_set(instance_variable_name, instance_eval(&blk))
59
+ end
60
+ end
61
+
62
+ def it(description, &blk)
63
+ define_method("test_#{name}_#{description}", &blk)
64
+ end
65
+ end
66
+ end
67
+
68
+ def describe(description, &blk)
69
+ ActiveSupport::TestCase.describe(description, true, &blk)
70
+ end
@@ -0,0 +1,73 @@
1
+ class ActiveSupport::TestCase
2
+ module ImportAssertions
3
+ def self.extended(klass)
4
+ klass.instance_eval do
5
+ assertion(:should_not_update_created_at_on_timestamp_columns) do
6
+ Timecop.freeze Chronic.parse("5 minutes from now") do
7
+ perform_import
8
+ assert_in_delta @topic.created_at.to_i, updated_topic.created_at.to_i, 1
9
+ assert_in_delta @topic.created_on.to_i, updated_topic.created_on.to_i, 1
10
+ end
11
+ end
12
+
13
+ assertion(:should_update_updated_at_on_timestamp_columns) do
14
+ time = Chronic.parse("5 minutes from now")
15
+ Timecop.freeze time do
16
+ perform_import
17
+ assert_in_delta time.to_i, updated_topic.updated_at.to_i, 1
18
+ assert_in_delta time.to_i, updated_topic.updated_on.to_i, 1
19
+ end
20
+ end
21
+
22
+ assertion(:should_not_update_updated_at_on_timestamp_columns) do
23
+ time = Chronic.parse("5 minutes from now")
24
+ Timecop.freeze time do
25
+ perform_import
26
+ assert_in_delta @topic.updated_at.to_i, updated_topic.updated_at.to_i, 1
27
+ assert_in_delta @topic.updated_on.to_i, updated_topic.updated_on.to_i, 1
28
+ end
29
+ end
30
+
31
+ assertion(:should_not_update_timestamps) do
32
+ Timecop.freeze Chronic.parse("5 minutes from now") do
33
+ perform_import timestamps: false
34
+ assert_in_delta @topic.created_at.to_i, updated_topic.created_at.to_i, 1
35
+ assert_in_delta @topic.created_on.to_i, updated_topic.created_on.to_i, 1
36
+ assert_in_delta @topic.updated_at.to_i, updated_topic.updated_at.to_i, 1
37
+ assert_in_delta @topic.updated_on.to_i, updated_topic.updated_on.to_i, 1
38
+ end
39
+ end
40
+
41
+ assertion(:should_not_update_fields_not_mentioned) do
42
+ assert_equal "John Doe", updated_topic.author_name
43
+ end
44
+
45
+ assertion(:should_update_fields_mentioned) do
46
+ perform_import
47
+ assert_equal "Book - 2nd Edition", updated_topic.title
48
+ assert_equal "johndoe@example.com", updated_topic.author_email_address
49
+ end
50
+
51
+ assertion(:should_raise_update_fields_mentioned) do
52
+ assert_raise ActiveRecord::RecordNotUnique do
53
+ perform_import
54
+ end
55
+
56
+ assert_equal "Book", updated_topic.title
57
+ assert_equal "john@doe.com", updated_topic.author_email_address
58
+ end
59
+
60
+ assertion(:should_update_fields_mentioned_with_hash_mappings) do
61
+ perform_import
62
+ assert_equal "johndoe@example.com", updated_topic.title
63
+ assert_equal "Book - 2nd Edition", updated_topic.author_email_address
64
+ end
65
+
66
+ assertion(:should_update_foreign_keys) do
67
+ perform_import
68
+ assert_equal 57, updated_topic.parent_id
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end