activerecord 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (311) hide show
  1. data/CHANGELOG +4928 -3
  2. data/README +45 -46
  3. data/RUNNING_UNIT_TESTS +8 -11
  4. data/Rakefile +247 -0
  5. data/install.rb +8 -38
  6. data/lib/active_record/aggregations.rb +64 -49
  7. data/lib/active_record/associations/association_collection.rb +217 -47
  8. data/lib/active_record/associations/association_proxy.rb +159 -0
  9. data/lib/active_record/associations/belongs_to_association.rb +56 -0
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
  11. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +155 -37
  12. data/lib/active_record/associations/has_many_association.rb +145 -75
  13. data/lib/active_record/associations/has_many_through_association.rb +283 -0
  14. data/lib/active_record/associations/has_one_association.rb +96 -0
  15. data/lib/active_record/associations.rb +1537 -304
  16. data/lib/active_record/attribute_methods.rb +328 -0
  17. data/lib/active_record/base.rb +2001 -588
  18. data/lib/active_record/calculations.rb +269 -0
  19. data/lib/active_record/callbacks.rb +169 -165
  20. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +308 -0
  21. data/lib/active_record/connection_adapters/abstract/database_statements.rb +171 -0
  22. data/lib/active_record/connection_adapters/abstract/query_cache.rb +87 -0
  23. data/lib/active_record/connection_adapters/abstract/quoting.rb +69 -0
  24. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +472 -0
  25. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +306 -0
  26. data/lib/active_record/connection_adapters/abstract_adapter.rb +125 -279
  27. data/lib/active_record/connection_adapters/mysql_adapter.rb +442 -77
  28. data/lib/active_record/connection_adapters/postgresql_adapter.rb +805 -135
  29. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
  30. data/lib/active_record/connection_adapters/sqlite_adapter.rb +353 -69
  31. data/lib/active_record/fixtures.rb +946 -100
  32. data/lib/active_record/locking/optimistic.rb +144 -0
  33. data/lib/active_record/locking/pessimistic.rb +77 -0
  34. data/lib/active_record/migration.rb +417 -0
  35. data/lib/active_record/observer.rb +142 -32
  36. data/lib/active_record/query_cache.rb +23 -0
  37. data/lib/active_record/reflection.rb +163 -70
  38. data/lib/active_record/schema.rb +58 -0
  39. data/lib/active_record/schema_dumper.rb +171 -0
  40. data/lib/active_record/serialization.rb +98 -0
  41. data/lib/active_record/serializers/json_serializer.rb +71 -0
  42. data/lib/active_record/serializers/xml_serializer.rb +315 -0
  43. data/lib/active_record/timestamp.rb +41 -0
  44. data/lib/active_record/transactions.rb +87 -57
  45. data/lib/active_record/validations.rb +909 -122
  46. data/lib/active_record/vendor/db2.rb +362 -0
  47. data/lib/active_record/vendor/mysql.rb +126 -29
  48. data/lib/active_record/version.rb +9 -0
  49. data/lib/active_record.rb +35 -7
  50. data/lib/activerecord.rb +1 -0
  51. data/test/aaa_create_tables_test.rb +72 -0
  52. data/test/abstract_unit.rb +73 -5
  53. data/test/active_schema_test_mysql.rb +43 -0
  54. data/test/adapter_test.rb +105 -0
  55. data/test/adapter_test_sqlserver.rb +95 -0
  56. data/test/aggregations_test.rb +110 -16
  57. data/test/all.sh +2 -2
  58. data/test/ar_schema_test.rb +33 -0
  59. data/test/association_inheritance_reload.rb +14 -0
  60. data/test/associations/ar_joins_test.rb +0 -0
  61. data/test/associations/callbacks_test.rb +147 -0
  62. data/test/associations/cascaded_eager_loading_test.rb +110 -0
  63. data/test/associations/eager_singularization_test.rb +145 -0
  64. data/test/associations/eager_test.rb +442 -0
  65. data/test/associations/extension_test.rb +47 -0
  66. data/test/associations/inner_join_association_test.rb +88 -0
  67. data/test/associations/join_model_test.rb +553 -0
  68. data/test/associations_test.rb +1930 -267
  69. data/test/attribute_methods_test.rb +146 -0
  70. data/test/base_test.rb +1316 -84
  71. data/test/binary_test.rb +32 -0
  72. data/test/calculations_test.rb +251 -0
  73. data/test/callbacks_test.rb +400 -0
  74. data/test/class_inheritable_attributes_test.rb +3 -4
  75. data/test/column_alias_test.rb +17 -0
  76. data/test/connection_test_firebird.rb +8 -0
  77. data/test/connection_test_mysql.rb +30 -0
  78. data/test/connections/native_db2/connection.rb +25 -0
  79. data/test/connections/native_firebird/connection.rb +26 -0
  80. data/test/connections/native_frontbase/connection.rb +27 -0
  81. data/test/connections/native_mysql/connection.rb +21 -18
  82. data/test/connections/native_openbase/connection.rb +21 -0
  83. data/test/connections/native_oracle/connection.rb +27 -0
  84. data/test/connections/native_postgresql/connection.rb +17 -18
  85. data/test/connections/native_sqlite/connection.rb +17 -16
  86. data/test/connections/native_sqlite3/connection.rb +25 -0
  87. data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
  88. data/test/connections/native_sybase/connection.rb +23 -0
  89. data/test/copy_table_test_sqlite.rb +69 -0
  90. data/test/datatype_test_postgresql.rb +203 -0
  91. data/test/date_time_test.rb +37 -0
  92. data/test/default_test_firebird.rb +16 -0
  93. data/test/defaults_test.rb +67 -0
  94. data/test/deprecated_finder_test.rb +30 -0
  95. data/test/finder_test.rb +607 -32
  96. data/test/fixtures/accounts.yml +28 -0
  97. data/test/fixtures/all/developers.yml +0 -0
  98. data/test/fixtures/all/people.csv +0 -0
  99. data/test/fixtures/all/tasks.yml +0 -0
  100. data/test/fixtures/author.rb +107 -0
  101. data/test/fixtures/author_favorites.yml +4 -0
  102. data/test/fixtures/authors.yml +7 -0
  103. data/test/fixtures/bad_fixtures/attr_with_numeric_first_char +1 -0
  104. data/test/fixtures/bad_fixtures/attr_with_spaces +1 -0
  105. data/test/fixtures/bad_fixtures/blank_line +3 -0
  106. data/test/fixtures/bad_fixtures/duplicate_attributes +3 -0
  107. data/test/fixtures/bad_fixtures/missing_value +1 -0
  108. data/test/fixtures/binaries.yml +132 -0
  109. data/test/fixtures/binary.rb +2 -0
  110. data/test/fixtures/book.rb +4 -0
  111. data/test/fixtures/books.yml +7 -0
  112. data/test/fixtures/categories/special_categories.yml +9 -0
  113. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  114. data/test/fixtures/categories.yml +14 -0
  115. data/test/fixtures/categories_ordered.yml +7 -0
  116. data/test/fixtures/categories_posts.yml +23 -0
  117. data/test/fixtures/categorization.rb +5 -0
  118. data/test/fixtures/categorizations.yml +17 -0
  119. data/test/fixtures/category.rb +26 -0
  120. data/test/fixtures/citation.rb +6 -0
  121. data/test/fixtures/comment.rb +23 -0
  122. data/test/fixtures/comments.yml +59 -0
  123. data/test/fixtures/companies.yml +55 -0
  124. data/test/fixtures/company.rb +81 -4
  125. data/test/fixtures/company_in_module.rb +32 -6
  126. data/test/fixtures/computer.rb +4 -0
  127. data/test/fixtures/computers.yml +4 -0
  128. data/test/fixtures/contact.rb +16 -0
  129. data/test/fixtures/courses.yml +7 -0
  130. data/test/fixtures/customer.rb +28 -3
  131. data/test/fixtures/customers.yml +17 -0
  132. data/test/fixtures/db_definitions/db2.drop.sql +33 -0
  133. data/test/fixtures/db_definitions/db2.sql +235 -0
  134. data/test/fixtures/db_definitions/db22.drop.sql +2 -0
  135. data/test/fixtures/db_definitions/db22.sql +5 -0
  136. data/test/fixtures/db_definitions/firebird.drop.sql +65 -0
  137. data/test/fixtures/db_definitions/firebird.sql +310 -0
  138. data/test/fixtures/db_definitions/firebird2.drop.sql +2 -0
  139. data/test/fixtures/db_definitions/firebird2.sql +6 -0
  140. data/test/fixtures/db_definitions/frontbase.drop.sql +33 -0
  141. data/test/fixtures/db_definitions/frontbase.sql +273 -0
  142. data/test/fixtures/db_definitions/frontbase2.drop.sql +1 -0
  143. data/test/fixtures/db_definitions/frontbase2.sql +4 -0
  144. data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
  145. data/test/fixtures/db_definitions/openbase.sql +318 -0
  146. data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
  147. data/test/fixtures/db_definitions/openbase2.sql +7 -0
  148. data/test/fixtures/db_definitions/oracle.drop.sql +67 -0
  149. data/test/fixtures/db_definitions/oracle.sql +330 -0
  150. data/test/fixtures/db_definitions/oracle2.drop.sql +2 -0
  151. data/test/fixtures/db_definitions/oracle2.sql +6 -0
  152. data/test/fixtures/db_definitions/postgresql.drop.sql +44 -0
  153. data/test/fixtures/db_definitions/postgresql.sql +217 -38
  154. data/test/fixtures/db_definitions/postgresql2.drop.sql +2 -0
  155. data/test/fixtures/db_definitions/postgresql2.sql +2 -2
  156. data/test/fixtures/db_definitions/schema.rb +354 -0
  157. data/test/fixtures/db_definitions/schema2.rb +11 -0
  158. data/test/fixtures/db_definitions/sqlite.drop.sql +33 -0
  159. data/test/fixtures/db_definitions/sqlite.sql +139 -5
  160. data/test/fixtures/db_definitions/sqlite2.drop.sql +2 -0
  161. data/test/fixtures/db_definitions/sqlite2.sql +1 -0
  162. data/test/fixtures/db_definitions/sybase.drop.sql +35 -0
  163. data/test/fixtures/db_definitions/sybase.sql +222 -0
  164. data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
  165. data/test/fixtures/db_definitions/sybase2.sql +5 -0
  166. data/test/fixtures/developer.rb +70 -6
  167. data/test/fixtures/developers.yml +21 -0
  168. data/test/fixtures/developers_projects/david_action_controller +2 -1
  169. data/test/fixtures/developers_projects/david_active_record +2 -1
  170. data/test/fixtures/developers_projects.yml +17 -0
  171. data/test/fixtures/edge.rb +5 -0
  172. data/test/fixtures/edges.yml +6 -0
  173. data/test/fixtures/entrants.yml +14 -0
  174. data/test/fixtures/example.log +1 -0
  175. data/test/fixtures/fk_test_has_fk.yml +3 -0
  176. data/test/fixtures/fk_test_has_pk.yml +2 -0
  177. data/test/fixtures/flowers.jpg +0 -0
  178. data/test/fixtures/funny_jokes.yml +10 -0
  179. data/test/fixtures/item.rb +7 -0
  180. data/test/fixtures/items.yml +4 -0
  181. data/test/fixtures/joke.rb +3 -0
  182. data/test/fixtures/keyboard.rb +3 -0
  183. data/test/fixtures/legacy_thing.rb +3 -0
  184. data/test/fixtures/legacy_things.yml +3 -0
  185. data/test/fixtures/matey.rb +4 -0
  186. data/test/fixtures/mateys.yml +4 -0
  187. data/test/fixtures/migrations/1_people_have_last_names.rb +9 -0
  188. data/test/fixtures/migrations/2_we_need_reminders.rb +12 -0
  189. data/test/fixtures/migrations/3_innocent_jointable.rb +12 -0
  190. data/test/fixtures/migrations_with_decimal/1_give_me_big_numbers.rb +15 -0
  191. data/test/fixtures/migrations_with_duplicate/1_people_have_last_names.rb +9 -0
  192. data/test/fixtures/migrations_with_duplicate/2_we_need_reminders.rb +12 -0
  193. data/test/fixtures/migrations_with_duplicate/3_foo.rb +7 -0
  194. data/test/fixtures/migrations_with_duplicate/3_innocent_jointable.rb +12 -0
  195. data/test/fixtures/migrations_with_missing_versions/1000_people_have_middle_names.rb +9 -0
  196. data/test/fixtures/migrations_with_missing_versions/1_people_have_last_names.rb +9 -0
  197. data/test/fixtures/migrations_with_missing_versions/3_we_need_reminders.rb +12 -0
  198. data/test/fixtures/migrations_with_missing_versions/4_innocent_jointable.rb +12 -0
  199. data/test/fixtures/minimalistic.rb +2 -0
  200. data/test/fixtures/minimalistics.yml +2 -0
  201. data/test/fixtures/mixed_case_monkey.rb +3 -0
  202. data/test/fixtures/mixed_case_monkeys.yml +6 -0
  203. data/test/fixtures/mixins.yml +29 -0
  204. data/test/fixtures/movies.yml +7 -0
  205. data/test/fixtures/naked/csv/accounts.csv +1 -0
  206. data/test/fixtures/naked/yml/accounts.yml +1 -0
  207. data/test/fixtures/naked/yml/companies.yml +1 -0
  208. data/test/fixtures/naked/yml/courses.yml +1 -0
  209. data/test/fixtures/order.rb +4 -0
  210. data/test/fixtures/parrot.rb +13 -0
  211. data/test/fixtures/parrots.yml +27 -0
  212. data/test/fixtures/parrots_pirates.yml +7 -0
  213. data/test/fixtures/people.yml +3 -0
  214. data/test/fixtures/person.rb +4 -0
  215. data/test/fixtures/pirate.rb +5 -0
  216. data/test/fixtures/pirates.yml +9 -0
  217. data/test/fixtures/post.rb +59 -0
  218. data/test/fixtures/posts.yml +48 -0
  219. data/test/fixtures/project.rb +27 -2
  220. data/test/fixtures/projects.yml +7 -0
  221. data/test/fixtures/reader.rb +4 -0
  222. data/test/fixtures/readers.yml +4 -0
  223. data/test/fixtures/reply.rb +18 -2
  224. data/test/fixtures/reserved_words/distinct.yml +5 -0
  225. data/test/fixtures/reserved_words/distincts_selects.yml +11 -0
  226. data/test/fixtures/reserved_words/group.yml +14 -0
  227. data/test/fixtures/reserved_words/select.yml +8 -0
  228. data/test/fixtures/reserved_words/values.yml +7 -0
  229. data/test/fixtures/ship.rb +3 -0
  230. data/test/fixtures/ships.yml +5 -0
  231. data/test/fixtures/subject.rb +4 -0
  232. data/test/fixtures/subscriber.rb +4 -3
  233. data/test/fixtures/tag.rb +7 -0
  234. data/test/fixtures/tagging.rb +10 -0
  235. data/test/fixtures/taggings.yml +25 -0
  236. data/test/fixtures/tags.yml +7 -0
  237. data/test/fixtures/task.rb +3 -0
  238. data/test/fixtures/tasks.yml +7 -0
  239. data/test/fixtures/topic.rb +20 -3
  240. data/test/fixtures/topics.yml +22 -0
  241. data/test/fixtures/treasure.rb +4 -0
  242. data/test/fixtures/treasures.yml +10 -0
  243. data/test/fixtures/vertex.rb +9 -0
  244. data/test/fixtures/vertices.yml +4 -0
  245. data/test/fixtures_test.rb +574 -8
  246. data/test/inheritance_test.rb +113 -27
  247. data/test/json_serialization_test.rb +180 -0
  248. data/test/lifecycle_test.rb +56 -29
  249. data/test/locking_test.rb +273 -0
  250. data/test/method_scoping_test.rb +416 -0
  251. data/test/migration_test.rb +933 -0
  252. data/test/migration_test_firebird.rb +124 -0
  253. data/test/mixin_test.rb +95 -0
  254. data/test/modules_test.rb +23 -10
  255. data/test/multiple_db_test.rb +17 -3
  256. data/test/pk_test.rb +59 -15
  257. data/test/query_cache_test.rb +104 -0
  258. data/test/readonly_test.rb +107 -0
  259. data/test/reflection_test.rb +124 -27
  260. data/test/reserved_word_test_mysql.rb +177 -0
  261. data/test/schema_authorization_test_postgresql.rb +75 -0
  262. data/test/schema_dumper_test.rb +131 -0
  263. data/test/schema_test_postgresql.rb +64 -0
  264. data/test/serialization_test.rb +47 -0
  265. data/test/synonym_test_oracle.rb +17 -0
  266. data/test/table_name_test_sqlserver.rb +23 -0
  267. data/test/threaded_connections_test.rb +48 -0
  268. data/test/transactions_test.rb +227 -29
  269. data/test/unconnected_test.rb +14 -6
  270. data/test/validations_test.rb +1293 -32
  271. data/test/xml_serialization_test.rb +202 -0
  272. metadata +347 -143
  273. data/dev-utils/eval_debugger.rb +0 -9
  274. data/examples/associations.rb +0 -87
  275. data/examples/shared_setup.rb +0 -15
  276. data/examples/validation.rb +0 -88
  277. data/lib/active_record/deprecated_associations.rb +0 -70
  278. data/lib/active_record/support/class_attribute_accessors.rb +0 -43
  279. data/lib/active_record/support/class_inheritable_attributes.rb +0 -37
  280. data/lib/active_record/support/clean_logger.rb +0 -10
  281. data/lib/active_record/support/inflector.rb +0 -70
  282. data/lib/active_record/vendor/simple.rb +0 -702
  283. data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
  284. data/lib/active_record/wrappings.rb +0 -59
  285. data/rakefile +0 -122
  286. data/test/deprecated_associations_test.rb +0 -336
  287. data/test/fixtures/accounts/signals37 +0 -3
  288. data/test/fixtures/accounts/unknown +0 -2
  289. data/test/fixtures/companies/first_client +0 -6
  290. data/test/fixtures/companies/first_firm +0 -4
  291. data/test/fixtures/companies/second_client +0 -6
  292. data/test/fixtures/courses/java +0 -2
  293. data/test/fixtures/courses/ruby +0 -2
  294. data/test/fixtures/customers/david +0 -6
  295. data/test/fixtures/db_definitions/mysql.sql +0 -96
  296. data/test/fixtures/db_definitions/mysql2.sql +0 -4
  297. data/test/fixtures/developers/david +0 -2
  298. data/test/fixtures/developers/jamis +0 -2
  299. data/test/fixtures/entrants/first +0 -3
  300. data/test/fixtures/entrants/second +0 -3
  301. data/test/fixtures/entrants/third +0 -3
  302. data/test/fixtures/fixture_database.sqlite +0 -0
  303. data/test/fixtures/fixture_database_2.sqlite +0 -0
  304. data/test/fixtures/movies/first +0 -2
  305. data/test/fixtures/movies/second +0 -2
  306. data/test/fixtures/projects/action_controller +0 -2
  307. data/test/fixtures/projects/active_record +0 -2
  308. data/test/fixtures/topics/first +0 -9
  309. data/test/fixtures/topics/second +0 -8
  310. data/test/inflector_test.rb +0 -104
  311. data/test/thread_safety_test.rb +0 -33
@@ -1,78 +1,175 @@
1
- #require File.dirname(__FILE__) + '/../dev-utils/eval_debugger'
2
1
  require 'abstract_unit'
3
2
  require 'fixtures/topic'
4
3
  require 'fixtures/customer'
5
4
  require 'fixtures/company'
6
5
  require 'fixtures/company_in_module'
6
+ require 'fixtures/subscriber'
7
7
 
8
8
  class ReflectionTest < Test::Unit::TestCase
9
+ fixtures :topics, :customers, :companies, :subscribers
10
+
9
11
  def setup
10
- @topics = create_fixtures "topics"
11
- @customers = create_fixtures "customers"
12
- @companies = create_fixtures "companies"
13
12
  @first = Topic.find(1)
14
13
  end
15
14
 
15
+ def test_column_null_not_null
16
+ subscriber = Subscriber.find(:first)
17
+ assert subscriber.column_for_attribute("name").null
18
+ assert !subscriber.column_for_attribute("nick").null
19
+ end
20
+
16
21
  def test_read_attribute_names
17
22
  assert_equal(
18
- %w( id title author_name author_email_address written_on last_read content approved replies_count parent_id type ).sort,
23
+ %w( id title author_name author_email_address bonus_time written_on last_read content approved replies_count parent_id type ).sort,
19
24
  @first.attribute_names
20
25
  )
21
26
  end
22
-
27
+
23
28
  def test_columns
24
- assert_equal 11, Topic.columns.length
29
+ assert_equal 12, Topic.columns.length
30
+ end
31
+
32
+ def test_columns_are_returned_in_the_order_they_were_declared
33
+ column_names = Topic.columns.map { |column| column.name }
34
+ assert_equal %w(id title author_name author_email_address written_on bonus_time last_read content approved replies_count parent_id type), column_names
25
35
  end
26
36
 
27
37
  def test_content_columns
28
- assert_equal 7, Topic.content_columns.length
38
+ content_columns = Topic.content_columns
39
+ content_column_names = content_columns.map {|column| column.name}
40
+ assert_equal 8, content_columns.length
41
+ assert_equal %w(title author_name author_email_address written_on bonus_time last_read content approved).sort, content_column_names.sort
29
42
  end
30
-
43
+
31
44
  def test_column_string_type_and_limit
32
45
  assert_equal :string, @first.column_for_attribute("title").type
33
46
  assert_equal 255, @first.column_for_attribute("title").limit
34
47
  end
48
+
49
+ def test_column_null_not_null
50
+ subscriber = Subscriber.find(:first)
51
+ assert subscriber.column_for_attribute("name").null
52
+ assert !subscriber.column_for_attribute("nick").null
53
+ end
35
54
 
36
55
  def test_human_name_for_column
37
56
  assert_equal "Author name", @first.column_for_attribute("author_name").human_name
38
57
  end
39
-
58
+
40
59
  def test_integer_columns
41
60
  assert_equal :integer, @first.column_for_attribute("id").type
42
- end
61
+ end
62
+
63
+ def test_reflection_klass_for_nested_class_name
64
+ reflection = ActiveRecord::Reflection::MacroReflection.new(nil, nil, { :class_name => 'MyApplication::Business::Company' }, nil)
65
+ assert_nothing_raised do
66
+ assert_equal MyApplication::Business::Company, reflection.klass
67
+ end
68
+ end
43
69
 
44
70
  def test_aggregation_reflection
45
71
  reflection_for_address = ActiveRecord::Reflection::AggregateReflection.new(
46
- :address, { :mapping => [ %w(address_street street), %w(address_city city), %w(address_country country) ] }, Customer
72
+ :composed_of, :address, { :mapping => [ %w(address_street street), %w(address_city city), %w(address_country country) ] }, Customer
47
73
  )
48
74
 
49
75
  reflection_for_balance = ActiveRecord::Reflection::AggregateReflection.new(
50
- :balance, { :class_name => "Money", :mapping => %w(balance amount) }, Customer
76
+ :composed_of, :balance, { :class_name => "Money", :mapping => %w(balance amount) }, Customer
51
77
  )
52
78
 
53
- assert_equal(
54
- [ reflection_for_address, reflection_for_balance ],
55
- Customer.reflect_on_all_aggregations
79
+ reflection_for_gps_location = ActiveRecord::Reflection::AggregateReflection.new(
80
+ :composed_of, :gps_location, { }, Customer
56
81
  )
57
-
82
+
83
+ assert Customer.reflect_on_all_aggregations.include?(reflection_for_gps_location)
84
+ assert Customer.reflect_on_all_aggregations.include?(reflection_for_balance)
85
+ assert Customer.reflect_on_all_aggregations.include?(reflection_for_address)
86
+
58
87
  assert_equal reflection_for_address, Customer.reflect_on_aggregation(:address)
59
-
88
+
60
89
  assert_equal Address, Customer.reflect_on_aggregation(:address).klass
90
+
91
+ assert_equal Money, Customer.reflect_on_aggregation(:balance).klass
61
92
  end
62
-
63
- def test_association_reflection
64
- reflection_for_clients = ActiveRecord::Reflection::AssociationReflection.new(
65
- :clients, { :order => "id", :dependent => true }, Firm
66
- )
93
+
94
+ def test_has_many_reflection
95
+ reflection_for_clients = ActiveRecord::Reflection::AssociationReflection.new(:has_many, :clients, { :order => "id", :dependent => :destroy }, Firm)
67
96
 
68
97
  assert_equal reflection_for_clients, Firm.reflect_on_association(:clients)
69
98
 
70
99
  assert_equal Client, Firm.reflect_on_association(:clients).klass
100
+ assert_equal 'companies', Firm.reflect_on_association(:clients).table_name
101
+
71
102
  assert_equal Client, Firm.reflect_on_association(:clients_of_firm).klass
103
+ assert_equal 'companies', Firm.reflect_on_association(:clients_of_firm).table_name
72
104
  end
73
-
105
+
106
+ def test_has_one_reflection
107
+ reflection_for_account = ActiveRecord::Reflection::AssociationReflection.new(:has_one, :account, { :foreign_key => "firm_id", :dependent => :destroy }, Firm)
108
+ assert_equal reflection_for_account, Firm.reflect_on_association(:account)
109
+
110
+ assert_equal Account, Firm.reflect_on_association(:account).klass
111
+ assert_equal 'accounts', Firm.reflect_on_association(:account).table_name
112
+ end
113
+
114
+ def test_belongs_to_inferred_foreign_key_from_assoc_name
115
+ Company.belongs_to :foo
116
+ assert_equal "foo_id", Company.reflect_on_association(:foo).primary_key_name
117
+ Company.belongs_to :bar, :class_name => "Xyzzy"
118
+ assert_equal "bar_id", Company.reflect_on_association(:bar).primary_key_name
119
+ Company.belongs_to :baz, :class_name => "Xyzzy", :foreign_key => "xyzzy_id"
120
+ assert_equal "xyzzy_id", Company.reflect_on_association(:baz).primary_key_name
121
+ end
122
+
74
123
  def test_association_reflection_in_modules
75
- assert_equal MyApplication::Business::Client, MyApplication::Business::Firm.reflect_on_association(:clients_of_firm).klass
76
- assert_equal MyApplication::Business::Firm, MyApplication::Billing::Account.reflect_on_association(:firm).klass
124
+ assert_reflection MyApplication::Business::Firm,
125
+ :clients_of_firm,
126
+ :klass => MyApplication::Business::Client,
127
+ :class_name => 'Client',
128
+ :table_name => 'companies'
129
+
130
+ assert_reflection MyApplication::Billing::Account,
131
+ :firm,
132
+ :klass => MyApplication::Business::Firm,
133
+ :class_name => 'MyApplication::Business::Firm',
134
+ :table_name => 'companies'
135
+
136
+ assert_reflection MyApplication::Billing::Account,
137
+ :qualified_billing_firm,
138
+ :klass => MyApplication::Billing::Firm,
139
+ :class_name => 'MyApplication::Billing::Firm',
140
+ :table_name => 'companies'
141
+
142
+ assert_reflection MyApplication::Billing::Account,
143
+ :unqualified_billing_firm,
144
+ :klass => MyApplication::Billing::Firm,
145
+ :class_name => 'Firm',
146
+ :table_name => 'companies'
147
+
148
+ assert_reflection MyApplication::Billing::Account,
149
+ :nested_qualified_billing_firm,
150
+ :klass => MyApplication::Billing::Nested::Firm,
151
+ :class_name => 'MyApplication::Billing::Nested::Firm',
152
+ :table_name => 'companies'
153
+
154
+ assert_reflection MyApplication::Billing::Account,
155
+ :nested_unqualified_billing_firm,
156
+ :klass => MyApplication::Billing::Nested::Firm,
157
+ :class_name => 'Nested::Firm',
158
+ :table_name => 'companies'
77
159
  end
78
- end
160
+
161
+ def test_reflection_of_all_associations
162
+ assert_equal 17, Firm.reflect_on_all_associations.size
163
+ assert_equal 15, Firm.reflect_on_all_associations(:has_many).size
164
+ assert_equal 2, Firm.reflect_on_all_associations(:has_one).size
165
+ assert_equal 0, Firm.reflect_on_all_associations(:belongs_to).size
166
+ end
167
+
168
+ private
169
+ def assert_reflection(klass, association, options)
170
+ assert reflection = klass.reflect_on_association(association)
171
+ options.each do |method, value|
172
+ assert_equal(value, reflection.send(method))
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,177 @@
1
+ require "#{File.dirname(__FILE__)}/abstract_unit"
2
+
3
+ class Group < ActiveRecord::Base
4
+ Group.table_name = 'group'
5
+ belongs_to :select, :class_name => 'Select'
6
+ has_one :values
7
+ end
8
+
9
+ class Select < ActiveRecord::Base
10
+ Select.table_name = 'select'
11
+ has_many :groups
12
+ end
13
+
14
+ class Values < ActiveRecord::Base
15
+ Values.table_name = 'values'
16
+ end
17
+
18
+ class Distinct < ActiveRecord::Base
19
+ Distinct.table_name = 'distinct'
20
+ has_and_belongs_to_many :selects
21
+ has_many :values, :through => :groups
22
+ end
23
+
24
+ # a suite of tests to ensure the ConnectionAdapters#MysqlAdapter can handle tables with
25
+ # reserved word names (ie: group, order, values, etc...)
26
+ class MysqlReservedWordTest < Test::Unit::TestCase
27
+ def setup
28
+ @connection = ActiveRecord::Base.connection
29
+
30
+ # we call execute directly here (and do similar below) because ActiveRecord::Base#create_table()
31
+ # will fail with these table names if these test cases fail
32
+
33
+ create_tables_directly 'group'=>'id int auto_increment primary key, `order` varchar(255), select_id int',
34
+ 'select'=>'id int auto_increment primary key',
35
+ 'values'=>'id int auto_increment primary key, group_id int',
36
+ 'distinct'=>'id int auto_increment primary key',
37
+ 'distincts_selects'=>'distinct_id int, select_id int'
38
+ end
39
+
40
+ def teardown
41
+ drop_tables_directly ['group', 'select', 'values', 'distinct', 'distincts_selects', 'order']
42
+ end
43
+
44
+ # create tables with reserved-word names and columns
45
+ def test_create_tables
46
+ assert_nothing_raised {
47
+ @connection.create_table :order do |t|
48
+ t.column :group, :string
49
+ end
50
+ }
51
+ end
52
+
53
+ # rename tables with reserved-word names
54
+ def test_rename_tables
55
+ assert_nothing_raised { @connection.rename_table(:group, :order) }
56
+ end
57
+
58
+ # alter column with a reserved-word name in a table with a reserved-word name
59
+ def test_change_columns
60
+ assert_nothing_raised { @connection.change_column_default(:group, :order, 'whatever') }
61
+ #the quoting here will reveal any double quoting issues in change_column's interaction with the column method in the adapter
62
+ assert_nothing_raised { @connection.change_column('group', 'order', :Int, :default => 0) }
63
+ assert_nothing_raised { @connection.rename_column(:group, :order, :values) }
64
+ end
65
+
66
+ # dump structure of table with reserved word name
67
+ def test_structure_dump
68
+ assert_nothing_raised { @connection.structure_dump }
69
+ end
70
+
71
+ # introspect table with reserved word name
72
+ def test_introspect
73
+ assert_nothing_raised { @connection.columns(:group) }
74
+ assert_nothing_raised { @connection.indexes(:group) }
75
+ end
76
+
77
+ #fixtures
78
+ self.use_instantiated_fixtures = true
79
+ self.use_transactional_fixtures = false
80
+
81
+ #fixtures :group
82
+
83
+ def test_fixtures
84
+ f = create_test_fixtures :select, :distinct, :group, :values, :distincts_selects
85
+
86
+ assert_nothing_raised {
87
+ f.each do |x|
88
+ x.delete_existing_fixtures
89
+ end
90
+ }
91
+
92
+ assert_nothing_raised {
93
+ f.each do |x|
94
+ x.insert_fixtures
95
+ end
96
+ }
97
+ end
98
+
99
+ #activerecord model class with reserved-word table name
100
+ def test_activerecord_model
101
+ create_test_fixtures :select, :distinct, :group, :values, :distincts_selects
102
+ x = nil
103
+ assert_nothing_raised { x = Group.new }
104
+ x.order = 'x'
105
+ assert_nothing_raised { x.save }
106
+ x.order = 'y'
107
+ assert_nothing_raised { x.save }
108
+ assert_nothing_raised { y = Group.find_by_order('y') }
109
+ assert_nothing_raised { y = Group.find(1) }
110
+ x = Group.find(1)
111
+ end
112
+
113
+ # has_one association with reserved-word table name
114
+ def test_has_one_associations
115
+ create_test_fixtures :select, :distinct, :group, :values, :distincts_selects
116
+ v = nil
117
+ assert_nothing_raised { v = Group.find(1).values }
118
+ assert_equal v.id, 2
119
+ end
120
+
121
+ # belongs_to association with reserved-word table name
122
+ def test_belongs_to_associations
123
+ create_test_fixtures :select, :distinct, :group, :values, :distincts_selects
124
+ gs = nil
125
+ assert_nothing_raised { gs = Select.find(2).groups }
126
+ assert_equal gs.length, 2
127
+ assert(gs.collect{|x| x.id}.sort == [2, 3])
128
+ end
129
+
130
+ # has_and_belongs_to_many with reserved-word table name
131
+ def test_has_and_belongs_to_many
132
+ create_test_fixtures :select, :distinct, :group, :values, :distincts_selects
133
+ s = nil
134
+ assert_nothing_raised { s = Distinct.find(1).selects }
135
+ assert_equal s.length, 2
136
+ assert(s.collect{|x|x.id}.sort == [1, 2])
137
+ end
138
+
139
+ # activerecord model introspection with reserved-word table and column names
140
+ def test_activerecord_introspection
141
+ assert_nothing_raised { Group.table_exists? }
142
+ assert_nothing_raised { Group.columns }
143
+ end
144
+
145
+ # Calculations
146
+ def test_calculations_work_with_reserved_words
147
+ assert_nothing_raised { Group.count }
148
+ end
149
+
150
+ def test_associations_work_with_reserved_words
151
+ assert_nothing_raised { Select.find(:all, :include => [:groups]) }
152
+ end
153
+
154
+ #the following functions were added to DRY test cases
155
+
156
+ private
157
+ # custom fixture loader, uses Fixtures#create_fixtures and appends base_path to the current file's path
158
+ def create_test_fixtures(*fixture_names)
159
+ fixture_path = "./test/fixtures/reserved_words"
160
+ Fixtures.create_fixtures(fixture_path, fixture_names)
161
+ end
162
+
163
+ # custom drop table, uses execute on connection to drop a table if it exists. note: escapes table_name
164
+ def drop_tables_directly(table_names, connection = @connection)
165
+ table_names.each do |name|
166
+ connection.execute("DROP TABLE IF EXISTS `#{name}`")
167
+ end
168
+ end
169
+
170
+ # custom create table, uses execute on connection to create a table, note: escapes table_name, does NOT escape columns
171
+ def create_tables_directly (tables, connection = @connection)
172
+ tables.each do |table_name, column_properties|
173
+ connection.execute("CREATE TABLE `#{table_name}` ( #{column_properties} )")
174
+ end
175
+ end
176
+
177
+ end
@@ -0,0 +1,75 @@
1
+ require 'abstract_unit'
2
+
3
+ class SchemaThing < ActiveRecord::Base
4
+ end
5
+
6
+ class SchemaAuthorizationTest < Test::Unit::TestCase
7
+ self.use_transactional_fixtures = false
8
+
9
+ TABLE_NAME = 'schema_things'
10
+ COLUMNS = [
11
+ 'id serial primary key',
12
+ 'name character varying(50)'
13
+ ]
14
+ USERS = ['rails_pg_schema_user1', 'rails_pg_schema_user2']
15
+
16
+ def setup
17
+ @connection = ActiveRecord::Base.connection
18
+ @connection.execute "SET search_path TO '$user',public"
19
+ set_session_auth
20
+ USERS.each do |u|
21
+ @connection.execute "CREATE ROLE #{u}"
22
+ @connection.execute "CREATE SCHEMA AUTHORIZATION #{u}"
23
+ set_session_auth u
24
+ @connection.execute "CREATE TABLE #{TABLE_NAME} (#{COLUMNS.join(',')})"
25
+ @connection.execute "INSERT INTO #{TABLE_NAME} (name) VALUES ('#{u}')"
26
+ set_session_auth
27
+ end
28
+ end
29
+
30
+ def teardown
31
+ set_session_auth
32
+ @connection.execute "RESET search_path"
33
+ USERS.each do |u|
34
+ @connection.execute "DROP SCHEMA #{u} CASCADE"
35
+ @connection.execute "DROP ROLE #{u}"
36
+ end
37
+ end
38
+
39
+ def test_schema_invisible
40
+ assert_raise(ActiveRecord::StatementInvalid) do
41
+ set_session_auth
42
+ @connection.execute "SELECT * FROM #{TABLE_NAME}"
43
+ end
44
+ end
45
+
46
+ def test_schema_uniqueness
47
+ assert_nothing_raised do
48
+ set_session_auth
49
+ USERS.each do |u|
50
+ set_session_auth u
51
+ assert_equal u, @connection.select_value("SELECT name FROM #{TABLE_NAME} WHERE id = 1")
52
+ set_session_auth
53
+ end
54
+ end
55
+ end
56
+
57
+ def test_sequence_schema_caching
58
+ assert_nothing_raised do
59
+ USERS.each do |u|
60
+ set_session_auth u
61
+ st = SchemaThing.new :name => 'TEST1'
62
+ st.save!
63
+ st = SchemaThing.new :id => 5, :name => 'TEST2'
64
+ st.save!
65
+ set_session_auth
66
+ end
67
+ end
68
+ end
69
+
70
+ private
71
+ def set_session_auth auth = nil
72
+ @connection.execute "SET SESSION AUTHORIZATION #{auth || 'default'}"
73
+ end
74
+
75
+ end
@@ -0,0 +1,131 @@
1
+ require 'abstract_unit'
2
+ require "#{File.dirname(__FILE__)}/../lib/active_record/schema_dumper"
3
+ require 'stringio'
4
+
5
+ if ActiveRecord::Base.connection.respond_to?(:tables)
6
+
7
+ class SchemaDumperTest < Test::Unit::TestCase
8
+ def standard_dump
9
+ stream = StringIO.new
10
+ ActiveRecord::SchemaDumper.ignore_tables = []
11
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
12
+ stream.string
13
+ end
14
+
15
+ def test_schema_dump
16
+ output = standard_dump
17
+ assert_match %r{create_table "accounts"}, output
18
+ assert_match %r{create_table "authors"}, output
19
+ assert_no_match %r{create_table "schema_info"}, output
20
+ end
21
+
22
+ def test_schema_dump_excludes_sqlite_sequence
23
+ output = standard_dump
24
+ assert_no_match %r{create_table "sqlite_sequence"}, output
25
+ end
26
+
27
+ def assert_line_up(lines, pattern, required = false)
28
+ return assert(true) if lines.empty?
29
+ matches = lines.map { |line| line.match(pattern) }
30
+ assert matches.all? if required
31
+ matches.compact!
32
+ return assert(true) if matches.empty?
33
+ assert_equal 1, matches.map{ |match| match.offset(0).first }.uniq.length
34
+ end
35
+
36
+ def column_definition_lines(output = standard_dump)
37
+ output.scan(/^( *)create_table.*?\n(.*?)^\1end/m).map{ |m| m.last.split(/\n/) }
38
+ end
39
+
40
+ def test_types_line_up
41
+ column_definition_lines.each do |column_set|
42
+ next if column_set.empty?
43
+
44
+ lengths = column_set.map do |column|
45
+ if match = column.match(/t\.(?:integer|decimal|float|datetime|timestamp|time|date|text|binary|string|boolean)\s+"/)
46
+ match[0].length
47
+ end
48
+ end
49
+
50
+ assert_equal 1, lengths.uniq.length
51
+ end
52
+ end
53
+
54
+ def test_arguments_line_up
55
+ column_definition_lines.each do |column_set|
56
+ assert_line_up(column_set, /:default => /)
57
+ assert_line_up(column_set, /:limit => /)
58
+ assert_line_up(column_set, /:null => /)
59
+ end
60
+ end
61
+
62
+ def test_no_dump_errors
63
+ output = standard_dump
64
+ assert_no_match %r{\# Could not dump table}, output
65
+ end
66
+
67
+ def test_schema_dump_includes_not_null_columns
68
+ stream = StringIO.new
69
+
70
+ ActiveRecord::SchemaDumper.ignore_tables = [/^[^r]/]
71
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
72
+ output = stream.string
73
+ assert_match %r{:null => false}, output
74
+ end
75
+
76
+ def test_schema_dump_with_string_ignored_table
77
+ stream = StringIO.new
78
+
79
+ ActiveRecord::SchemaDumper.ignore_tables = ['accounts']
80
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
81
+ output = stream.string
82
+ assert_no_match %r{create_table "accounts"}, output
83
+ assert_match %r{create_table "authors"}, output
84
+ assert_no_match %r{create_table "schema_info"}, output
85
+ end
86
+
87
+
88
+ def test_schema_dump_with_regexp_ignored_table
89
+ stream = StringIO.new
90
+
91
+ ActiveRecord::SchemaDumper.ignore_tables = [/^account/]
92
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
93
+ output = stream.string
94
+ assert_no_match %r{create_table "accounts"}, output
95
+ assert_match %r{create_table "authors"}, output
96
+ assert_no_match %r{create_table "schema_info"}, output
97
+ end
98
+
99
+
100
+ def test_schema_dump_illegal_ignored_table_value
101
+ stream = StringIO.new
102
+ ActiveRecord::SchemaDumper.ignore_tables = [5]
103
+ assert_raise(StandardError) do
104
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
105
+ end
106
+ end
107
+
108
+ if current_adapter?(:MysqlAdapter)
109
+ def test_schema_dump_should_not_add_default_value_for_mysql_text_field
110
+ output = standard_dump
111
+ assert_match %r{t.text\s+"body",\s+:default => "",\s+:null => false$}, output
112
+ end
113
+
114
+ def test_mysql_schema_dump_should_honor_nonstandard_primary_keys
115
+ output = standard_dump
116
+ match = output.match(%r{create_table "movies"(.*)do})
117
+ assert_not_nil(match, "nonstandardpk table not found")
118
+ assert_match %r(:primary_key => "movieid"), match[1], "non-standard primary key not preserved"
119
+ end
120
+ end
121
+
122
+ def test_schema_dump_includes_decimal_options
123
+ stream = StringIO.new
124
+ ActiveRecord::SchemaDumper.ignore_tables = [/^[^n]/]
125
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
126
+ output = stream.string
127
+ assert_match %r{:precision => 3,[[:space:]]+:scale => 2,[[:space:]]+:default => 2.78}, output
128
+ end
129
+ end
130
+
131
+ end
@@ -0,0 +1,64 @@
1
+ require 'abstract_unit'
2
+
3
+ class SchemaTest < Test::Unit::TestCase
4
+ self.use_transactional_fixtures = false
5
+
6
+ SCHEMA_NAME = 'test_schema'
7
+ TABLE_NAME = 'things'
8
+ COLUMNS = [
9
+ 'id integer',
10
+ 'name character varying(50)',
11
+ 'moment timestamp without time zone default now()'
12
+ ]
13
+
14
+ def setup
15
+ @connection = ActiveRecord::Base.connection
16
+ @connection.execute "CREATE SCHEMA #{SCHEMA_NAME} CREATE TABLE #{TABLE_NAME} (#{COLUMNS.join(',')})"
17
+ end
18
+
19
+ def teardown
20
+ @connection.execute "DROP SCHEMA #{SCHEMA_NAME} CASCADE"
21
+ end
22
+
23
+ def test_with_schema_prefixed_table_name
24
+ assert_nothing_raised do
25
+ assert_equal COLUMNS, columns("#{SCHEMA_NAME}.#{TABLE_NAME}")
26
+ end
27
+ end
28
+
29
+ def test_with_schema_search_path
30
+ assert_nothing_raised do
31
+ with_schema_search_path(SCHEMA_NAME) do
32
+ assert_equal COLUMNS, columns(TABLE_NAME)
33
+ end
34
+ end
35
+ end
36
+
37
+ def test_raise_on_unquoted_schema_name
38
+ assert_raise(ActiveRecord::StatementInvalid) do
39
+ with_schema_search_path '$user,public'
40
+ end
41
+ end
42
+
43
+ def test_without_schema_search_path
44
+ assert_raise(ActiveRecord::StatementInvalid) { columns(TABLE_NAME) }
45
+ end
46
+
47
+ def test_ignore_nil_schema_search_path
48
+ assert_nothing_raised { with_schema_search_path nil }
49
+ end
50
+
51
+ private
52
+ def columns(table_name)
53
+ @connection.send(:column_definitions, table_name).map do |name, type, default|
54
+ "#{name} #{type}" + (default ? " default #{default}" : '')
55
+ end
56
+ end
57
+
58
+ def with_schema_search_path(schema_search_path)
59
+ @connection.schema_search_path = schema_search_path
60
+ yield if block_given?
61
+ ensure
62
+ @connection.schema_search_path = "'$user', public"
63
+ end
64
+ end
@@ -0,0 +1,47 @@
1
+ require 'abstract_unit'
2
+ require 'fixtures/contact'
3
+
4
+ class SerializationTest < Test::Unit::TestCase
5
+ FORMATS = [ :xml, :json ]
6
+
7
+ def setup
8
+ @contact_attributes = {
9
+ :name => 'aaron stack',
10
+ :age => 25,
11
+ :avatar => 'binarydata',
12
+ :created_at => Time.utc(2006, 8, 1),
13
+ :awesome => false,
14
+ :preferences => { :gem => '<strong>ruby</strong>' }
15
+ }
16
+
17
+ @contact = Contact.new(@contact_attributes)
18
+ end
19
+
20
+ def test_serialize_should_be_reversible
21
+ for format in FORMATS
22
+ @serialized = Contact.new.send("to_#{format}")
23
+ contact = Contact.new.send("from_#{format}", @serialized)
24
+
25
+ assert_equal @contact_attributes.keys.collect(&:to_s).sort, contact.attributes.keys.collect(&:to_s).sort, "For #{format}"
26
+ end
27
+ end
28
+
29
+ def test_serialize_should_allow_attribute_only_filtering
30
+ for format in FORMATS
31
+ @serialized = Contact.new(@contact_attributes).send("to_#{format}", :only => [ :age, :name ])
32
+ contact = Contact.new.send("from_#{format}", @serialized)
33
+ assert_equal @contact_attributes[:name], contact.name, "For #{format}"
34
+ assert_nil contact.avatar, "For #{format}"
35
+ end
36
+ end
37
+
38
+ def test_serialize_should_allow_attribute_except_filtering
39
+ for format in FORMATS
40
+ @serialized = Contact.new(@contact_attributes).send("to_#{format}", :except => [ :age, :name ])
41
+ contact = Contact.new.send("from_#{format}", @serialized)
42
+ assert_nil contact.name, "For #{format}"
43
+ assert_nil contact.age, "For #{format}"
44
+ assert_equal @contact_attributes[:awesome], contact.awesome, "For #{format}"
45
+ end
46
+ end
47
+ end