upgrow 0.0.2 → 0.0.3

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/lib/upgrow.rb +2 -8
  4. data/lib/upgrow/action.rb +66 -16
  5. data/lib/upgrow/actions.rb +31 -0
  6. data/lib/upgrow/active_record_adapter.rb +24 -15
  7. data/lib/upgrow/active_record_schema.rb +63 -0
  8. data/lib/upgrow/basic_model.rb +64 -0
  9. data/lib/upgrow/basic_repository.rb +49 -22
  10. data/lib/upgrow/error.rb +19 -0
  11. data/lib/upgrow/immutable_object.rb +26 -21
  12. data/lib/upgrow/input.rb +7 -0
  13. data/lib/upgrow/model.rb +12 -12
  14. data/lib/upgrow/model_schema.rb +31 -0
  15. data/lib/upgrow/repository.rb +3 -0
  16. data/lib/upgrow/result.rb +18 -55
  17. data/lib/upgrow/schema.rb +33 -0
  18. data/test/application_system_test_case.rb +11 -0
  19. data/test/dummy/app/actions/application_action.rb +10 -0
  20. data/test/dummy/app/actions/articles/create_action.rb +15 -0
  21. data/test/dummy/app/actions/articles/destroy_action.rb +9 -0
  22. data/test/dummy/app/actions/articles/edit_action.rb +12 -0
  23. data/test/dummy/app/actions/articles/index_action.rb +11 -0
  24. data/test/dummy/app/actions/articles/new_action.rb +8 -0
  25. data/test/dummy/app/actions/articles/show_action.rb +11 -0
  26. data/test/dummy/app/actions/articles/update_action.rb +15 -0
  27. data/test/dummy/app/actions/comments/create_action.rb +15 -0
  28. data/test/dummy/app/actions/comments/destroy_action.rb +9 -0
  29. data/test/dummy/app/actions/comments/new_action.rb +8 -0
  30. data/test/dummy/app/actions/sessions/create_action.rb +23 -0
  31. data/test/dummy/app/actions/sessions/destroy_action.rb +6 -0
  32. data/test/dummy/app/actions/sessions/new_action.rb +8 -0
  33. data/test/dummy/app/actions/user_action.rb +10 -0
  34. data/test/dummy/app/actions/users/create_action.rb +13 -0
  35. data/test/dummy/app/actions/users/new_action.rb +8 -0
  36. data/test/dummy/app/controllers/application_controller.rb +10 -0
  37. data/test/dummy/app/controllers/articles_controller.rb +32 -28
  38. data/test/dummy/app/controllers/comments_controller.rb +41 -0
  39. data/test/dummy/app/controllers/sessions_controller.rb +34 -0
  40. data/test/dummy/app/controllers/users_controller.rb +29 -0
  41. data/test/dummy/app/helpers/application_helper.rb +27 -3
  42. data/test/dummy/app/helpers/users_helper.rb +15 -0
  43. data/test/dummy/app/inputs/article_input.rb +3 -0
  44. data/test/dummy/app/inputs/comment_input.rb +11 -0
  45. data/test/dummy/app/inputs/session_input.rb +9 -0
  46. data/test/dummy/app/inputs/user_input.rb +9 -0
  47. data/test/dummy/app/models/article.rb +0 -2
  48. data/test/dummy/app/models/comment.rb +4 -0
  49. data/test/dummy/app/models/user.rb +4 -0
  50. data/test/dummy/app/records/article_record.rb +2 -0
  51. data/test/dummy/app/records/comment_record.rb +7 -0
  52. data/test/dummy/app/records/user_record.rb +9 -0
  53. data/test/dummy/app/repositories/article_repository.rb +26 -0
  54. data/test/dummy/app/repositories/comment_repository.rb +3 -0
  55. data/test/dummy/app/repositories/user_repository.rb +12 -0
  56. data/test/dummy/config/routes.rb +6 -1
  57. data/test/dummy/db/migrate/20210320140432_create_comments.rb +12 -0
  58. data/test/dummy/db/migrate/20210409164927_create_users.rb +22 -0
  59. data/test/dummy/db/schema.rb +24 -1
  60. data/test/system/articles_test.rb +87 -29
  61. data/test/system/comments_test.rb +81 -0
  62. data/test/system/guest_user_test.rb +14 -0
  63. data/test/system/sign_in_test.rb +57 -0
  64. data/test/system/sign_out_test.rb +19 -0
  65. data/test/system/sign_up_test.rb +38 -0
  66. data/test/test_helper.rb +6 -1
  67. data/test/upgrow/action_test.rb +101 -9
  68. data/test/upgrow/actions_test.rb +24 -0
  69. data/test/upgrow/active_record_adapter_test.rb +12 -17
  70. data/test/upgrow/active_record_schema_test.rb +92 -0
  71. data/test/upgrow/basic_model_test.rb +95 -0
  72. data/test/upgrow/basic_repository_test.rb +48 -27
  73. data/test/upgrow/immutable_object_test.rb +43 -7
  74. data/test/upgrow/input_test.rb +19 -1
  75. data/test/upgrow/model_schema_test.rb +44 -0
  76. data/test/upgrow/model_test.rb +48 -11
  77. data/test/upgrow/result_test.rb +19 -64
  78. data/test/upgrow/schema_test.rb +44 -0
  79. metadata +128 -50
  80. data/test/dummy/app/actions/create_article_action.rb +0 -13
  81. data/test/dummy/app/actions/delete_article_action.rb +0 -7
  82. data/test/dummy/app/actions/edit_article_action.rb +0 -10
  83. data/test/dummy/app/actions/list_articles_action.rb +0 -8
  84. data/test/dummy/app/actions/show_article_action.rb +0 -10
  85. data/test/dummy/app/actions/update_article_action.rb +0 -13
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ module Upgrow
6
+ class BasicModelTest < ActiveSupport::TestCase
7
+ class SampleModel < BasicModel
8
+ attribute :title
9
+ attribute :body
10
+
11
+ belongs_to :user
12
+ end
13
+
14
+ class SubSampleModel < SampleModel
15
+ has_many :tags
16
+ end
17
+
18
+ setup do
19
+ @original_schema = BasicModel.schema.dup
20
+ end
21
+
22
+ teardown do
23
+ BasicModel.schema = @original_schema
24
+ end
25
+
26
+ test '.schema includes ID by default' do
27
+ assert_equal [:id, :title, :body], SampleModel.schema.attribute_names
28
+ end
29
+
30
+ test '.schema does not have associations by default' do
31
+ assert_empty BasicModel.schema.association_names
32
+ end
33
+
34
+ test '.schema includes the Model associations' do
35
+ assert_equal [:user], SampleModel.schema.association_names
36
+ assert_equal [:user, :tags], SubSampleModel.schema.association_names
37
+ end
38
+
39
+ test '.has_many defines an association in the Schema' do
40
+ BasicModel.has_many(:comments)
41
+ assert_equal [:comments], BasicModel.schema.association_names
42
+ end
43
+
44
+ test '.belongs_to defines an association in the Schema' do
45
+ BasicModel.belongs_to(:author)
46
+ assert_equal [:author], BasicModel.schema.association_names
47
+ end
48
+
49
+ test '.new requires all attributes' do
50
+ error = assert_raises(KeyError) do
51
+ SampleModel.new(title: 'volmer', id: 1)
52
+ end
53
+
54
+ assert_equal 'key not found: :body', error.message
55
+ end
56
+
57
+ test '.new optionally accepts associations' do
58
+ model = SampleModel.new(
59
+ title: 'volmer',
60
+ body: 'My long body',
61
+ id: 1,
62
+ user: :my_user
63
+ )
64
+
65
+ assert_equal :my_user, model.user
66
+ end
67
+
68
+ test '#respond_to? is true for association readers' do
69
+ model = SubSampleModel.new(id: 1, title: 'volmer', body: 'hello')
70
+
71
+ assert model.respond_to?(:user)
72
+ assert model.respond_to?(:tags)
73
+ end
74
+
75
+ test 'association reader raises Association Not Loaded Error for an association that was not loaded' do
76
+ model = SampleModel.new(
77
+ title: 'volmer',
78
+ body: 'My long body',
79
+ id: 1,
80
+ )
81
+
82
+ assert_raises(Model::AssociationNotLoadedError) { model.user }
83
+ end
84
+
85
+ test 'attribute readers work when association is not loaded' do
86
+ model = SampleModel.new(
87
+ title: 'volmer',
88
+ body: 'My long body',
89
+ id: 1,
90
+ )
91
+
92
+ assert_equal 'volmer', model.title
93
+ end
94
+ end
95
+ end
@@ -4,36 +4,48 @@ require 'test_helper'
4
4
 
5
5
  module Upgrow
6
6
  class BasicRepositoryTest < ActiveSupport::TestCase
7
- class User < Model; end
7
+ class User < BasicModel; end
8
+
9
+ class Car < BasicModel
10
+ attribute :wheels
11
+ end
8
12
 
9
13
  class UserRepository < BasicRepository; end
10
14
 
11
15
  class NoModelRepository < BasicRepository; end
12
16
 
13
17
  setup do
14
- freeze_time
15
-
18
+ @original_base = UserRepository.base
19
+ @original_model_class = UserRepository.model_class
16
20
  @repository = UserRepository.new
17
21
  end
18
22
 
19
- test '.new instantiates a new Repository with a base and a Model class' do
20
- repository = UserRepository.new(base: :my_base, model_class: User)
23
+ teardown do
24
+ UserRepository.base = @original_base
25
+ UserRepository.model_class = @original_model_class
26
+ end
27
+
28
+ test '.base is nil by default' do
29
+ assert_nil UserRepository.base
30
+ end
21
31
 
22
- assert_equal :my_base, repository.base
23
- assert_equal User, repository.model_class
32
+ test '.base can be set' do
33
+ UserRepository.base = :my_base
34
+ assert_equal :my_base, UserRepository.base
24
35
  end
25
36
 
26
- test '.new sets the base to nil by default' do
27
- assert_nil @repository.base
37
+ test '.model_class is iferred based on the Repository name' do
38
+ assert_equal User, UserRepository.model_class
28
39
  end
29
40
 
30
- test '.new sets the Model class by default to a constant derived from the Repository name' do
31
- assert_equal User, @repository.model_class
41
+ test '.model_class can be set' do
42
+ UserRepository.model_class = :my_model_class
43
+ assert_equal :my_model_class, UserRepository.model_class
32
44
  end
33
45
 
34
- test '.new raises a Name Error if the Model class is undefined' do
46
+ test '.model_class raises a Name Error if the Model class is undefined' do
35
47
  error = assert_raises(NameError) do
36
- NoModelRepository.new(base: :my_base)
48
+ NoModelRepository.model_class
37
49
  end
38
50
 
39
51
  assert_includes(
@@ -42,32 +54,41 @@ module Upgrow
42
54
  )
43
55
  end
44
56
 
45
- test '.to_model returns a new Model with the given attributes as keyword arguments' do
46
- model = @repository.to_model(
47
- id: 1, created_at: Time.now, updated_at: Time.now
48
- )
57
+ test '#base is inferred from the Repository class base' do
58
+ UserRepository.base = :my_base
59
+ assert_equal :my_base, UserRepository.new.base
60
+ end
61
+
62
+ test '#model_class is inferred from the Repository class Model class' do
63
+ UserRepository.model_class = :my_model_class
64
+ assert_equal :my_model_class, UserRepository.new.model_class
65
+ end
66
+
67
+ test '#to_model returns a new Model with the given attributes as keyword arguments' do
68
+ model = @repository.to_model(id: 1)
69
+
70
+ assert_equal 1, model.id
71
+ end
72
+
73
+ test '#to_model accepts a Model class explicitly' do
74
+ model = @repository.to_model(Car, id: 1, wheels: 4)
49
75
 
50
76
  assert_equal 1, model.id
51
- assert_equal Time.now, model.created_at
52
- assert_equal Time.now, model.updated_at
77
+ assert_equal 4, model.wheels
53
78
  end
54
79
 
55
- test '.to_model accepts a Hash of Symbols' do
56
- args = { id: 1, created_at: Time.now, updated_at: Time.now }
80
+ test '#to_model accepts a Hash of Symbols' do
81
+ args = { id: 1 }
57
82
  model = @repository.to_model(args)
58
83
 
59
84
  assert_equal 1, model.id
60
- assert_equal Time.now, model.created_at
61
- assert_equal Time.now, model.updated_at
62
85
  end
63
86
 
64
- test '.to_model accepts a Hash of Strings' do
65
- args = { 'id' => 1, 'created_at' => Time.now, 'updated_at' => Time.now }
87
+ test '#to_model accepts a Hash of Strings' do
88
+ args = { 'id' => 1 }
66
89
  model = @repository.to_model(args)
67
90
 
68
91
  assert_equal 1, model.id
69
- assert_equal Time.now, model.created_at
70
- assert_equal Time.now, model.updated_at
71
92
  end
72
93
  end
73
94
  end
@@ -13,12 +13,26 @@ module Upgrow
13
13
  attribute :name
14
14
  end
15
15
 
16
- test '.attribute_names is empty by default' do
17
- assert_empty ImmutableObject.attribute_names
16
+ setup do
17
+ @original_schema = Sample.schema
18
18
  end
19
19
 
20
- test '.attribute_names returns a list of attribute names' do
21
- assert_equal [:title, :body, :name], SubSample.attribute_names
20
+ teardown do
21
+ Sample.schema = @original_schema
22
+ end
23
+
24
+ test '.schema is empty by default' do
25
+ assert_empty ImmutableObject.schema.attribute_names
26
+ end
27
+
28
+ test '.schema can be set' do
29
+ Sample.schema = :my_schema
30
+
31
+ assert_equal :my_schema, Sample.schema
32
+ end
33
+
34
+ test '.schema contains all declared attributes' do
35
+ assert_equal [:title, :body, :name], SubSample.schema.attribute_names
22
36
  end
23
37
 
24
38
  test '.new creates a frozen instance with the given attributes' do
@@ -29,7 +43,7 @@ module Upgrow
29
43
  assert sample.frozen?
30
44
  end
31
45
 
32
- test 'it does not allow members to be mutated' do
46
+ test 'it does not allow attributes to be mutated' do
33
47
  sample = Sample.new(title: 'volmer', body: 'hello')
34
48
 
35
49
  refute sample.respond_to?(:title=)
@@ -44,17 +58,39 @@ module Upgrow
44
58
  assert_equal 'Unknown attribute [:fake]', error.message
45
59
  end
46
60
 
47
- test '.new requires inherited attributes' do
61
+ test '.new allows inherited attributes' do
48
62
  sub_sample = SubSample.new(title: 'volmer', body: 'hello', name: 'rafael')
49
63
  assert_equal 'volmer', sub_sample.title
50
64
  assert_equal 'hello', sub_sample.body
51
65
  assert_equal 'rafael', sub_sample.name
52
66
  end
53
67
 
54
- test '#attributes returns the collection of attributes' do
68
+ test '.new allows omitting attributes' do
69
+ sub_sample = SubSample.new(title: 'volmer')
70
+ assert_equal 'volmer', sub_sample.title
71
+ assert_nil sub_sample.body
72
+ assert_nil sub_sample.name
73
+ end
74
+
75
+ test '#respond_to? is true for all attribute readers' do
76
+ sub_sample = SubSample.new(title: 'volmer')
77
+
78
+ assert sub_sample.respond_to?(:title)
79
+ assert sub_sample.respond_to?(:body)
80
+ assert sub_sample.respond_to?(:name)
81
+ end
82
+
83
+ test '#attributes returns the collection of frozen attributes' do
55
84
  sample = Sample.new(title: 'volmer', body: 'hello')
56
85
 
57
86
  assert_equal({ title: 'volmer', body: 'hello' }, sample.attributes)
87
+ assert sample.attributes.frozen?
88
+ end
89
+
90
+ test '#attributes returns attributes that were omitted' do
91
+ sample = Sample.new
92
+
93
+ assert_equal({ title: nil, body: nil }, sample.attributes)
58
94
  end
59
95
  end
60
96
  end
@@ -12,7 +12,7 @@ module Upgrow
12
12
  validates :title, presence: true
13
13
  end
14
14
 
15
- test '#errors is an empty Active Model Errors' do
15
+ test '#errors is empty' do
16
16
  input = Input.new
17
17
  errors = input.errors
18
18
  assert_empty errors
@@ -61,5 +61,23 @@ module Upgrow
61
61
  input = SampleInput.new
62
62
  refute_predicate input, :valid?
63
63
  end
64
+
65
+ test '#errors is empty when validation is successful' do
66
+ input = SampleInput.new(title: 'volmer')
67
+ assert_predicate input, :valid?
68
+ assert_empty input.errors
69
+ end
70
+
71
+ test '#errors is populated when validation fails' do
72
+ input = SampleInput.new
73
+ refute_predicate input, :valid?
74
+ assert_predicate input.errors, :one?
75
+
76
+ error = input.errors.first
77
+
78
+ assert_equal :title, error.attribute
79
+ assert_equal :blank, error.type
80
+ assert_equal "Title can't be blank", error.full_message
81
+ end
64
82
  end
65
83
  end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ module Upgrow
6
+ class ModelSchemaTest < ActiveSupport::TestCase
7
+ setup do
8
+ @schema = ModelSchema.new
9
+ end
10
+
11
+ test '#association_names is empty by default' do
12
+ assert_empty @schema.attribute_names
13
+ end
14
+
15
+ test '#association_names returns the defined associations' do
16
+ @schema.association(:user)
17
+ @schema.association(:tags)
18
+
19
+ assert_equal [:user, :tags], @schema.association_names
20
+ end
21
+
22
+ test '#association defines an association' do
23
+ @schema.association(:user)
24
+
25
+ assert_equal [:user], @schema.association_names
26
+ end
27
+
28
+ test '#association does not define the same association twice' do
29
+ @schema.association(:user)
30
+ @schema.association(:user)
31
+
32
+ assert_equal [:user], @schema.association_names
33
+ end
34
+
35
+ test '#dup creates a Schema with independent association names' do
36
+ @schema.association(:user)
37
+ new_schema = @schema.dup
38
+ new_schema.association(:tags)
39
+
40
+ assert_equal [:user], @schema.association_names
41
+ assert_equal [:user, :tags], new_schema.association_names
42
+ end
43
+ end
44
+ end
@@ -2,26 +2,63 @@
2
2
 
3
3
  require 'test_helper'
4
4
 
5
+ require 'upgrow/model'
6
+
5
7
  module Upgrow
6
8
  class ModelTest < ActiveSupport::TestCase
7
9
  class SampleModel < Model
8
- attribute :title
9
- attribute :body
10
10
  end
11
11
 
12
- test '.attribute_names includes :id, :created_at, and :updated_at' do
13
- expected = [:id, :created_at, :updated_at, :title, :body]
14
- assert_equal expected, SampleModel.attribute_names
12
+ class SubSampleModel < SampleModel
13
+ end
14
+
15
+ class SampleModelWithAttribute < Model
16
+ attribute :phone
17
+ end
18
+
19
+ class SampleModelRecord
20
+ def self.attribute_names
21
+ ['id', 'name']
22
+ end
23
+ end
24
+
25
+ class SubSampleModelRecord
26
+ def self.attribute_names
27
+ ['email']
28
+ end
29
+ end
30
+
31
+ class SampleModelWithAttributeRecord
32
+ def self.attribute_names
33
+ ['id']
34
+ end
35
+ end
36
+
37
+ class OrphanedModel < Model
38
+ end
39
+
40
+ test '.schema is inferred from the Active Record with the Model name' do
41
+ assert_equal [:id, :name], SampleModel.schema.attribute_names
42
+ end
43
+
44
+ test '.schema is populated with inherited attributes' do
45
+ assert_equal [:email, :id, :name], SubSampleModel.schema.attribute_names
46
+ end
47
+
48
+ test '.schema includes explicit attributes as well as Active Record attributes' do
49
+ assert_equal [:id, :phone],
50
+ SampleModelWithAttribute.schema.attribute_names
15
51
  end
16
52
 
17
- test '.new requires all attributes' do
18
- error = assert_raises(KeyError) do
19
- SampleModel.new(
20
- title: 'volmer', id: 1, created_at: Time.now, updated_at: Time.now
21
- )
53
+ test '.new raises a Name Error if the Record class is undefined' do
54
+ error = assert_raises(NameError) do
55
+ OrphanedModel.new
22
56
  end
23
57
 
24
- assert_equal 'key not found: :body', error.message
58
+ assert_includes(
59
+ error.message,
60
+ 'uninitialized constant Upgrow::ModelTest::OrphanedModelRecord'
61
+ )
25
62
  end
26
63
  end
27
64
  end