mavenlink 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +3 -0
  6. data/README.md +241 -0
  7. data/Rakefile +28 -0
  8. data/bin/mavenlink-console +18 -0
  9. data/doc/ml_logo_lb-primary.png +0 -0
  10. data/lib/config/specification.yml +1665 -0
  11. data/lib/mavenlink.rb +134 -0
  12. data/lib/mavenlink/account_invitation.rb +4 -0
  13. data/lib/mavenlink/account_membership.rb +4 -0
  14. data/lib/mavenlink/additional_item.rb +4 -0
  15. data/lib/mavenlink/assignment.rb +5 -0
  16. data/lib/mavenlink/attachment.rb +11 -0
  17. data/lib/mavenlink/backup_approver_association.rb +4 -0
  18. data/lib/mavenlink/client.rb +116 -0
  19. data/lib/mavenlink/concerns/custom_fieldable.rb +9 -0
  20. data/lib/mavenlink/concerns/indestructible.rb +11 -0
  21. data/lib/mavenlink/concerns/locked_record.rb +30 -0
  22. data/lib/mavenlink/cost_rate.rb +4 -0
  23. data/lib/mavenlink/custom_field.rb +4 -0
  24. data/lib/mavenlink/custom_field_choice.rb +5 -0
  25. data/lib/mavenlink/custom_field_value.rb +4 -0
  26. data/lib/mavenlink/errors.rb +47 -0
  27. data/lib/mavenlink/expense.rb +4 -0
  28. data/lib/mavenlink/expense_category.rb +4 -0
  29. data/lib/mavenlink/expense_report_submission.rb +7 -0
  30. data/lib/mavenlink/external_payment.rb +4 -0
  31. data/lib/mavenlink/external_reference.rb +24 -0
  32. data/lib/mavenlink/fixed_fee_item.rb +4 -0
  33. data/lib/mavenlink/holiday.rb +4 -0
  34. data/lib/mavenlink/holiday_calendar.rb +4 -0
  35. data/lib/mavenlink/holiday_calendar_association.rb +4 -0
  36. data/lib/mavenlink/holiday_calendar_membership.rb +4 -0
  37. data/lib/mavenlink/invoice.rb +4 -0
  38. data/lib/mavenlink/logger.rb +62 -0
  39. data/lib/mavenlink/model.rb +279 -0
  40. data/lib/mavenlink/organization.rb +4 -0
  41. data/lib/mavenlink/organization_membership.rb +4 -0
  42. data/lib/mavenlink/participation.rb +4 -0
  43. data/lib/mavenlink/post.rb +4 -0
  44. data/lib/mavenlink/project_template.rb +4 -0
  45. data/lib/mavenlink/project_template_assignment.rb +4 -0
  46. data/lib/mavenlink/railtie.rb +7 -0
  47. data/lib/mavenlink/rate_card.rb +4 -0
  48. data/lib/mavenlink/rate_card_role.rb +4 -0
  49. data/lib/mavenlink/rate_card_set.rb +4 -0
  50. data/lib/mavenlink/rate_card_set_version.rb +30 -0
  51. data/lib/mavenlink/rate_card_version.rb +4 -0
  52. data/lib/mavenlink/request.rb +241 -0
  53. data/lib/mavenlink/resolution.rb +4 -0
  54. data/lib/mavenlink/response.rb +22 -0
  55. data/lib/mavenlink/role.rb +5 -0
  56. data/lib/mavenlink/settings.rb +11 -0
  57. data/lib/mavenlink/skill.rb +4 -0
  58. data/lib/mavenlink/skill_category.rb +4 -0
  59. data/lib/mavenlink/skill_membership.rb +4 -0
  60. data/lib/mavenlink/specificators/association.rb +13 -0
  61. data/lib/mavenlink/specificators/attribute.rb +13 -0
  62. data/lib/mavenlink/specificators/base.rb +24 -0
  63. data/lib/mavenlink/specificators/validation.rb +27 -0
  64. data/lib/mavenlink/status_report.rb +4 -0
  65. data/lib/mavenlink/story.rb +8 -0
  66. data/lib/mavenlink/story_allocation_day.rb +5 -0
  67. data/lib/mavenlink/story_dependency.rb +5 -0
  68. data/lib/mavenlink/story_task.rb +5 -0
  69. data/lib/mavenlink/tag.rb +5 -0
  70. data/lib/mavenlink/time_adjustment.rb +4 -0
  71. data/lib/mavenlink/time_entry.rb +4 -0
  72. data/lib/mavenlink/time_off_entry.rb +4 -0
  73. data/lib/mavenlink/timesheet_submission.rb +4 -0
  74. data/lib/mavenlink/user.rb +5 -0
  75. data/lib/mavenlink/vendor.rb +4 -0
  76. data/lib/mavenlink/workspace.rb +21 -0
  77. data/lib/mavenlink/workspace_group.rb +5 -0
  78. data/lib/mavenlink/workspace_invoice_preference.rb +4 -0
  79. data/lib/mavenlink/workweek.rb +4 -0
  80. data/lib/mavenlink/workweek_membership.rb +4 -0
  81. data/mavenlink.gemspec +29 -0
  82. data/spec/lib/mavenlink/account_membership_spec.rb +8 -0
  83. data/spec/lib/mavenlink/assignment_spec.rb +17 -0
  84. data/spec/lib/mavenlink/attachment_spec.rb +30 -0
  85. data/spec/lib/mavenlink/backup_approver_association_spec.rb +9 -0
  86. data/spec/lib/mavenlink/client_spec.rb +187 -0
  87. data/spec/lib/mavenlink/concerns/indestructible_spec.rb +13 -0
  88. data/spec/lib/mavenlink/concerns/locked_record_spec.rb +28 -0
  89. data/spec/lib/mavenlink/cost_rate_spec.rb +9 -0
  90. data/spec/lib/mavenlink/custom_field_value_spec.rb +10 -0
  91. data/spec/lib/mavenlink/expense_report_submission_spec.rb +16 -0
  92. data/spec/lib/mavenlink/expense_spec.rb +23 -0
  93. data/spec/lib/mavenlink/external_references_spec.rb +144 -0
  94. data/spec/lib/mavenlink/holiday_calendar_association_spec.rb +8 -0
  95. data/spec/lib/mavenlink/holiday_calendar_membership_spec.rb +8 -0
  96. data/spec/lib/mavenlink/holiday_spec.rb +7 -0
  97. data/spec/lib/mavenlink/invalid_request_error_spec.rb +9 -0
  98. data/spec/lib/mavenlink/invoice_spec.rb +176 -0
  99. data/spec/lib/mavenlink/model_spec.rb +439 -0
  100. data/spec/lib/mavenlink/post_spec.rb +23 -0
  101. data/spec/lib/mavenlink/rate_card_set_version_spec.rb +119 -0
  102. data/spec/lib/mavenlink/record_invalid_error_spec.rb +16 -0
  103. data/spec/lib/mavenlink/record_not_found_error_spec.rb +9 -0
  104. data/spec/lib/mavenlink/request_spec.rb +381 -0
  105. data/spec/lib/mavenlink/response_spec.rb +50 -0
  106. data/spec/lib/mavenlink/role_spec.rb +9 -0
  107. data/spec/lib/mavenlink/settings_spec.rb +23 -0
  108. data/spec/lib/mavenlink/skill_category_spec.rb +7 -0
  109. data/spec/lib/mavenlink/skill_membership_spec.rb +9 -0
  110. data/spec/lib/mavenlink/skill_spec.rb +8 -0
  111. data/spec/lib/mavenlink/specificators/association_spec.rb +25 -0
  112. data/spec/lib/mavenlink/specificators/attribute_spec.rb +25 -0
  113. data/spec/lib/mavenlink/specificators/validation_spec.rb +39 -0
  114. data/spec/lib/mavenlink/story_allocation_day_spec.rb +64 -0
  115. data/spec/lib/mavenlink/story_dependency_spec.rb +16 -0
  116. data/spec/lib/mavenlink/story_spec.rb +69 -0
  117. data/spec/lib/mavenlink/time_adjustment_spec.rb +13 -0
  118. data/spec/lib/mavenlink/time_entry_spec.rb +43 -0
  119. data/spec/lib/mavenlink/time_off_entry_spec.rb +9 -0
  120. data/spec/lib/mavenlink/user_spec.rb +138 -0
  121. data/spec/lib/mavenlink/workspace_group_spec.rb +25 -0
  122. data/spec/lib/mavenlink/workspace_spec.rb +431 -0
  123. data/spec/lib/mavenlink_spec.rb +43 -0
  124. data/spec/spec_helper.rb +31 -0
  125. data/spec/support/shared_examples.rb +148 -0
  126. metadata +267 -0
@@ -0,0 +1,9 @@
1
+ require "spec_helper"
2
+
3
+ describe Mavenlink::CostRate, stub_requests: true do
4
+ it_should_behave_like "model", "cost_rates"
5
+
6
+ describe "association" do
7
+ it { should respond_to :account_membership }
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mavenlink::CustomFieldValue, stub_requests: true do
4
+ it_should_behave_like 'model', 'custom_field_values'
5
+
6
+ describe 'associations' do
7
+ it { should respond_to :setter }
8
+ it { should respond_to :custom_field }
9
+ end
10
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mavenlink::ExpenseReportSubmission, stub_requests: true do
4
+ let(:report) { described_class.new(id: 4) }
5
+
6
+ describe "#reject_submission" do
7
+ before do
8
+ allow(report.client).to receive(:put)
9
+ report.reject_submission
10
+ end
11
+
12
+ it "uses a put method with the correct api endpoint and id" do
13
+ expect(report.client).to have_received(:put).with("expense_report_submissions/4/reject")
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mavenlink::Expense, stub_requests: true do
4
+ it_should_behave_like 'model', 'expenses'
5
+
6
+ describe 'validations' do
7
+ it { should validate_presence_of :workspace_id }
8
+ it { should validate_presence_of :date }
9
+ it { should validate_presence_of :category }
10
+ it { should validate_presence_of :amount_in_cents }
11
+ end
12
+
13
+ describe 'associations' do
14
+ it { should respond_to :expense_category }
15
+ it { should respond_to :workspace }
16
+ it { should respond_to :user }
17
+ it { should respond_to :receipt }
18
+ it { should respond_to :external_references }
19
+ it { should respond_to :active_submission }
20
+ it { should respond_to :role }
21
+ it { should respond_to :vendor }
22
+ end
23
+ end
@@ -0,0 +1,144 @@
1
+ require "spec_helper"
2
+
3
+ describe Mavenlink::ExternalReference, stub_requests: true do
4
+ let(:model) { described_class }
5
+ let(:external_reference) { model.new(attributes) }
6
+ let(:uri) { "external_references/create_or_update" }
7
+ let(:attributes) {
8
+ {
9
+ "subject_type" => "TimeEntry",
10
+ "subject_id" => 1,
11
+ "service_name" => "Netsuite",
12
+ "service_model_ref" => "1",
13
+ "service_model" => "TimeBill"
14
+ }.merge(attribute_options)
15
+ }
16
+ let(:attribute_options) { {} }
17
+ let(:response) do
18
+ {
19
+ "count" => 1,
20
+ "results" => [{"key" => "external_references", "id" => "7"}],
21
+ "external_references" => {
22
+ "7" => {
23
+ "id" => "7",
24
+ "subject_id" => "1",
25
+ "subject_type" => "TimeEntry",
26
+ "service_model_ref" => "1",
27
+ "service_name" => "Netsuite",
28
+ "service_model" => "TimeBill"
29
+ }
30
+ }
31
+ }
32
+ end
33
+
34
+ describe "validations" do
35
+ it { should validate_presence_of :service_model_ref }
36
+ it { should validate_presence_of :service_name }
37
+ it { should validate_presence_of :service_model }
38
+ it { should validate_presence_of :subject_id }
39
+ it { should validate_presence_of :subject_type }
40
+ end
41
+
42
+ describe "#save" do
43
+ before do
44
+ allow(external_reference.client).to receive(:post).and_call_original
45
+ stub_request :post, "/api/v1/external_references/create_or_update", response
46
+ end
47
+
48
+ context "when the model is valid" do
49
+ it "the record is valid" do
50
+ external_reference.save
51
+ expect(external_reference).to be_a model
52
+ expect(external_reference).to be_valid
53
+ expect(external_reference).to be_persisted
54
+ end
55
+
56
+ it "makes the request with the correct params" do
57
+ external_reference.save
58
+ expect(external_reference.client).to have_received(:post).with(uri, { external_reference: attributes })
59
+ end
60
+
61
+ it "returns true" do
62
+ expect(external_reference.save).to be_true
63
+ end
64
+
65
+ it "loads the response attributes into the integrated resource model" do
66
+ external_reference.save
67
+ expect(external_reference).to eq(response["external_references"]["7"])
68
+ end
69
+ end
70
+
71
+ context "when an invalid attribute is set on the model" do
72
+ let(:attribute_options) { { foo: 666 } }
73
+
74
+ it "the record is valid" do
75
+ external_reference.save
76
+ expect(external_reference).to be_a model
77
+ expect(external_reference).to be_valid
78
+ expect(external_reference).to be_persisted
79
+ end
80
+
81
+ it "ignores invalid attributes when making the request" do
82
+ external_reference.save
83
+ expect(external_reference.client).to have_received(:post).with(uri, { external_reference: attributes.except(:foo)})
84
+ end
85
+
86
+ it "returns true" do
87
+ expect(external_reference.save).to be_true
88
+ end
89
+
90
+ it "loads the response attributes into the integrated resource model" do
91
+ external_reference.save
92
+ expect(external_reference).to include(response["external_references"]["7"])
93
+ end
94
+ end
95
+
96
+ context "when required attributes are missing" do
97
+ let(:attribute_options) { { subject_type: nil } }
98
+
99
+ it "the record is not valid" do
100
+ external_reference.save
101
+ expect(external_reference).to be_a model
102
+ expect(external_reference).to_not be_valid
103
+ expect(external_reference).to_not be_persisted
104
+ end
105
+
106
+ it "does not make the request" do
107
+ external_reference.save
108
+ expect(external_reference.client).to_not have_received(:post)
109
+ end
110
+
111
+ it "returns false" do
112
+ expect(external_reference.save).to be_false
113
+ end
114
+
115
+ it "logs an error on the modal" do
116
+ external_reference.save
117
+ expect(external_reference.errors.full_messages).to eq(["Subject type can't be blank"])
118
+ end
119
+ end
120
+
121
+ context "when the server responds with error" do
122
+ let(:response) do
123
+ {
124
+ "errors" => [
125
+ {
126
+ "type" => "syntax",
127
+ "message" => "Missing required parameters. Please see our documentation at http://developer.mavenlink.com"
128
+ }
129
+ ]
130
+ }
131
+ end
132
+
133
+ after do
134
+ expect(external_reference).to be_a model
135
+ expect(external_reference).to be_valid
136
+ expect(external_reference).to_not be_persisted
137
+ end
138
+
139
+ it "raise a Mavenlink InvalidRequestError" do
140
+ expect { external_reference.save }.to raise_error Mavenlink::InvalidRequestError, /Missing required parameters/
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,8 @@
1
+ require "spec_helper"
2
+
3
+ describe Mavenlink::HolidayCalendarAssociation do
4
+ describe "associations" do
5
+ it { should respond_to :holiday }
6
+ it { should respond_to :holiday_calendar }
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require "spec_helper"
2
+
3
+ describe Mavenlink::HolidayCalendarMembership do
4
+ describe "associations" do
5
+ it { should respond_to :holiday_calendar }
6
+ it { should respond_to :user }
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ require "spec_helper"
2
+
3
+ describe Mavenlink::Holiday do
4
+ describe "associations" do
5
+ it { should respond_to :holiday_calendar_associations }
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mavenlink::InvalidRequestError do
4
+ subject { described_class.new({response: :data}) }
5
+
6
+ specify do
7
+ expect { raise subject }.to raise_error Mavenlink::InvalidRequestError, /response.*data/
8
+ end
9
+ end
@@ -0,0 +1,176 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mavenlink::Invoice, stub_requests: true do
4
+ subject { described_class.send(:new) }
5
+
6
+ describe 'associations' do
7
+ it { should respond_to :workspaces }
8
+ it { should respond_to :user }
9
+ it { should respond_to :recipient }
10
+ it { should respond_to :time_entries }
11
+ it { should respond_to :expenses }
12
+ it { should respond_to :fixed_fee_items }
13
+ it { should respond_to :additional_items }
14
+ end
15
+
16
+ let(:collection_name) { 'invoices' }
17
+
18
+ let(:model) { described_class }
19
+
20
+ let(:response) {
21
+ {
22
+ 'count' => 1,
23
+ 'results' => [{'key' => collection_name, 'id' => '7'}],
24
+ collection_name => {
25
+ '7' => {'title' => 'My new record', 'id' => '7'}
26
+ }
27
+ }
28
+ }
29
+
30
+ before do
31
+ stub_request :get, "/api/v1/#{collection_name}?only=7", response
32
+ stub_request :get, "/api/v1/#{collection_name}?only=8", {'count' => 0, 'results' => []}
33
+ stub_request :post, "/api/v1/#{collection_name}", response
34
+ stub_request :delete, "/api/v1/#{collection_name}/4", {}
35
+ end
36
+
37
+ describe 'class methods' do
38
+ subject { model }
39
+ its(:collection_name) { should == collection_name }
40
+
41
+ describe '.scoped' do
42
+ subject { model.scoped }
43
+
44
+ it { should be_a Mavenlink::Request }
45
+ its(:collection_name) { should == collection_name }
46
+ end
47
+
48
+ describe '.find' do
49
+ specify do
50
+ expect(model.find(7)).to be_a model
51
+ end
52
+
53
+ specify do
54
+ expect(model.find(7).id).to eq('7')
55
+ end
56
+
57
+ specify do
58
+ expect(model.find(8)).to be_nil
59
+ end
60
+ end
61
+
62
+ describe '.models' do
63
+ specify do
64
+ expect(model.models).to be_empty
65
+ end
66
+
67
+ specify do
68
+ expect(Mavenlink::Model.models).to include({collection_name => model})
69
+ end
70
+ end
71
+
72
+ describe '.specification' do
73
+ specify do
74
+ expect(model.specification).to be_a Hash
75
+ end
76
+
77
+ specify do
78
+ expect(model.specification).not_to be_empty
79
+ end
80
+ end
81
+
82
+ describe '.attributes' do
83
+ specify do
84
+ expect(model.attributes).to be_an Array
85
+ end
86
+
87
+ specify do
88
+ expect(model.attributes).not_to be_empty
89
+ end
90
+ end
91
+
92
+ describe '.available_attributes' do
93
+ specify do
94
+ expect(model.available_attributes).to be_an Array
95
+ end
96
+
97
+ specify do
98
+ expect(model.available_attributes).not_to be_empty
99
+ end
100
+ end
101
+
102
+ describe '.wrap' do
103
+ context 'existing record' do
104
+ let(:brainstem_record) do
105
+ BrainstemAdaptor::Record.new(collection_name, '7', Mavenlink::Response.new(response))
106
+ end
107
+
108
+ specify do
109
+ expect(model.wrap(brainstem_record)).not_to be_a_new_record
110
+ end
111
+
112
+ specify do
113
+ expect(model.wrap(brainstem_record)).to be_a model
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ describe '#initialize' do
120
+ it 'accepts attributes' do
121
+ expect(model.send(:new, any_custom_key: 'value set')).to include(any_custom_key: 'value set')
122
+ end
123
+ end
124
+
125
+ describe '#persisted?' do
126
+ before do
127
+ @instance = model.new
128
+ end
129
+
130
+ context 'when the model does not have an ID' do
131
+ before do
132
+ expect(@instance.id).to be_nil
133
+ end
134
+
135
+ it 'is false' do
136
+ expect(@instance).to_not be_persisted
137
+ end
138
+ end
139
+
140
+ context 'when the model has an ID' do
141
+ before do
142
+ @instance.id = 5
143
+ end
144
+
145
+ it 'is true' do
146
+ expect(@instance).to be_persisted
147
+ end
148
+ end
149
+ end
150
+
151
+ describe '#new_record?' do
152
+ before do
153
+ @instance = model.new
154
+ end
155
+
156
+ context 'when the model does not have an ID' do
157
+ before do
158
+ expect(@instance.id).to be_nil
159
+ end
160
+
161
+ it 'is true' do
162
+ expect(@instance).to be_new_record
163
+ end
164
+ end
165
+
166
+ context 'when the model has an ID' do
167
+ before do
168
+ @instance.id = 5
169
+ end
170
+
171
+ it 'is false' do
172
+ expect(@instance).to_not be_new_record
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,439 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mavenlink::Model, stub_requests: true do
4
+ # see workspace_model_spec.rb
5
+
6
+ before do
7
+ Mavenlink.stub(:specification).and_return({ 'monkeys' => {'validations' => {'name' => {'presence' => true}},
8
+ 'attributes' => ['name'],
9
+ 'create_attributes' => ['name'],
10
+ 'update_attributes' => ['name', 'age']} })
11
+ end
12
+
13
+ subject :model do
14
+ class Monkey < Mavenlink::Model
15
+ def self.name
16
+ 'Mavenlink::Monkey'
17
+ end
18
+ end
19
+ Monkey
20
+ end
21
+
22
+ its(:collection_name) { should == 'monkeys'}
23
+
24
+ let(:response) {
25
+ {
26
+ 'count' => 1,
27
+ 'results' => [{'key' => 'monkeys', 'id' => '7'}],
28
+ 'monkeys' => {
29
+ '7' => {'name' => 'Masha', 'id' => '7'}
30
+ }
31
+ }
32
+ }
33
+
34
+ let(:updated_response) {
35
+ {
36
+ 'count' => 1,
37
+ 'results' => [{'key' => 'monkeys', 'id' => '7'}],
38
+ 'monkeys' => {
39
+ '7' => {'name' => 'Mashka', 'id' => '7'}
40
+ }
41
+ }
42
+ }
43
+
44
+ before do
45
+ stub_request :get, '/api/v1/monkeys?only=7', response
46
+ stub_request :get, '/api/v1/monkeys?only=8', {'count' => 0, 'results' => []}
47
+ stub_request :post, '/api/v1/monkeys', response
48
+ stub_request :put, '/api/v1/monkeys/7', updated_response
49
+ stub_request :delete, '/api/v1/monkeys/7', {}
50
+ end
51
+
52
+ describe '.find' do
53
+ specify do
54
+ expect(model.find(7)).to be_a model
55
+ end
56
+
57
+ specify do
58
+ expect(model.find(7).id).to eq('7')
59
+ end
60
+
61
+ specify do
62
+ expect(model.find(8)).to be_nil
63
+ end
64
+ end
65
+
66
+ describe '.create' do
67
+ context 'valid record' do
68
+ specify do
69
+ expect(model.create(name: 'Masha')).to be_a model
70
+ end
71
+
72
+ specify do
73
+ expect(model.create(name: 'Masha')).to be_valid
74
+ end
75
+
76
+ specify do
77
+ expect(model.create(name: 'Masha')).to be_persisted
78
+ end
79
+ end
80
+
81
+ context 'invalid record' do
82
+ specify do
83
+ expect(model.create(name: '')).to be_a model
84
+ end
85
+
86
+ specify do
87
+ expect(model.create(name: '')).not_to be_valid
88
+ end
89
+
90
+ specify do
91
+ expect(model.create(name: '')).to be_a_new_record
92
+ end
93
+ end
94
+ end
95
+
96
+ describe '.create!' do
97
+ context 'valid record' do
98
+ specify do
99
+ expect { model.create!(name: 'Masha') }.not_to raise_error
100
+ end
101
+ end
102
+
103
+ context 'invalid record' do
104
+ specify do
105
+ expect { model.create!(name: '') }.to raise_error Mavenlink::RecordInvalidError, /Name.*blank/
106
+ end
107
+ end
108
+ end
109
+
110
+ describe '.models' do
111
+ specify do
112
+ expect(model.models).to be_empty
113
+ end
114
+
115
+ specify do
116
+ expect(Mavenlink::Model.models).to include({'monkeys' => Monkey})
117
+ end
118
+ end
119
+
120
+ describe '.specification' do
121
+ specify do
122
+ expect(model.specification).to be_a Hash
123
+ end
124
+
125
+ specify do
126
+ expect(model.specification).not_to be_empty
127
+ end
128
+ end
129
+
130
+ describe '.attributes' do
131
+ specify do
132
+ expect(model.attributes).to eq(['name'])
133
+ end
134
+ end
135
+
136
+ describe '.available_attributes' do
137
+ specify do
138
+ expect(model.available_attributes).to eq(['name', 'age'])
139
+ end
140
+ end
141
+
142
+ describe '.create_attributes' do
143
+ specify do
144
+ expect(model.create_attributes).to eq(['name'])
145
+ end
146
+ end
147
+
148
+ describe '.update_attributes' do
149
+ specify do
150
+ expect(model.update_attributes).to eq(['name', 'age'])
151
+ end
152
+ end
153
+
154
+ describe '.wrap' do
155
+ specify do
156
+ expect(model.wrap(nil)).to be_a_new_record
157
+ end
158
+
159
+ context 'existing record' do
160
+ let(:brainstem_record) do
161
+ BrainstemAdaptor::Record.new('monkeys', '7', Mavenlink::Response.new(response))
162
+ end
163
+
164
+ specify do
165
+ expect(model.wrap(brainstem_record)).not_to be_a_new_record
166
+ end
167
+
168
+ specify do
169
+ expect(model.wrap(brainstem_record)).to be_a Monkey
170
+ end
171
+ end
172
+ end
173
+
174
+ describe '#initialize' do
175
+ it 'accepts attributes' do
176
+ expect(model.new(any_custom_key: 'value set')).to include(any_custom_key: 'value set')
177
+ end
178
+
179
+ it 'checks for client' do
180
+ expect(model.new).to respond_to (:client)
181
+ expect(model.new.client).to be_a Mavenlink::Client
182
+ end
183
+ end
184
+
185
+ describe '#client' do
186
+ specify 'default client' do
187
+ expect(model.new.client).to be_a Mavenlink::Client
188
+ end
189
+
190
+ context 'custom client set' do
191
+ let(:client) { Mavenlink::Client.new(oauth_token: 'new one') }
192
+ subject { described_class.new({test: 'set'}, nil, client) }
193
+
194
+ its(:client) { should eq(client) }
195
+ end
196
+ end
197
+
198
+ describe '#persisted?' do
199
+ specify do
200
+ expect(model.new).not_to be_persisted
201
+ end
202
+
203
+ specify do
204
+ expect(model.new(id: 1)).to be_persisted
205
+ end
206
+ end
207
+
208
+ describe '#new_record?' do
209
+ specify do
210
+ expect(model.new).to be_new_record
211
+ end
212
+
213
+ specify do
214
+ expect(model.new(id: 1)).not_to be_new_record
215
+ end
216
+ end
217
+
218
+ describe 'attributes' do
219
+ specify do
220
+ expect(model.new).to respond_to :name
221
+ end
222
+
223
+ specify do
224
+ expect(model.new).to respond_to :age
225
+ end
226
+ end
227
+
228
+ describe '#attributes=' do
229
+ subject { model.new(name: 'old') }
230
+
231
+ specify do
232
+ expect { subject.attributes = {name: 'new'} }.to change { subject['name'] }.from('old').to('new')
233
+ end
234
+ end
235
+
236
+ describe '#to_param' do
237
+ specify do
238
+ expect(model.new(id: 1).to_param).to eq('1')
239
+ end
240
+
241
+ specify do
242
+ expect(model.new(id: nil).to_param).to eq(nil)
243
+ end
244
+ end
245
+
246
+ describe '#save' do
247
+ context 'valid record' do
248
+ context 'new record' do
249
+ subject { model.new(name: 'Maria') }
250
+
251
+ specify do
252
+ expect(subject.save).to eq(true)
253
+ end
254
+
255
+ specify do
256
+ expect { subject.save }.to change(subject, :persisted?).from(false).to(true)
257
+ end
258
+
259
+ it 'reloads record fields taking it from response' do
260
+ expect { subject.save }.to change { subject.name }.from('Maria').to('Masha')
261
+ end
262
+ end
263
+
264
+ context 'persisted record' do
265
+ subject { model.create(name: 'Maria') }
266
+
267
+ it { should be_persisted }
268
+
269
+ specify do
270
+ expect(subject.save).to eq(true)
271
+ end
272
+
273
+ specify do
274
+ expect { subject.save }.not_to change(subject, :persisted?)
275
+ end
276
+
277
+ it 'reloads record fields taking it from response' do
278
+ expect { subject.save }.to change { subject.name }.from('Masha').to('Mashka')
279
+ end
280
+ end
281
+ end
282
+
283
+ context 'invalid record' do
284
+ context 'new record' do
285
+ subject { model.new(name: '') }
286
+
287
+ specify do
288
+ expect(subject.save).to eq(false)
289
+ end
290
+
291
+ specify do
292
+ expect { subject.save }.not_to change(subject, :persisted?)
293
+ end
294
+
295
+ it 'does not perform any requests' do
296
+ expect { subject.save }.not_to change { subject.name }
297
+ end
298
+ end
299
+
300
+ context 'persisted record' do
301
+ subject { model.create(name: 'Maria') }
302
+ before { subject.name = '' }
303
+
304
+ it { should be_persisted }
305
+
306
+ specify do
307
+ expect(subject.save).to eq(false)
308
+ end
309
+
310
+ specify do
311
+ expect { subject.save }.not_to change(subject, :persisted?)
312
+ end
313
+
314
+ it 'does not change anything' do
315
+ expect { subject.save }.not_to change { subject.name }
316
+ end
317
+ end
318
+ end
319
+ end
320
+
321
+ describe '#save!' do
322
+ context 'valid record' do
323
+ context 'new record' do
324
+ subject { model.new(name: 'Maria') }
325
+
326
+ specify do
327
+ expect(subject.save!).to eq(true)
328
+ end
329
+
330
+ specify do
331
+ expect { subject.save! }.to change(subject, :persisted?).from(false).to(true)
332
+ end
333
+
334
+ it 'reloads record fields taking it from response' do
335
+ expect { subject.save! }.to change { subject.name }.from('Maria').to('Masha')
336
+ end
337
+ end
338
+
339
+ context 'persisted record' do
340
+ subject { model.create(name: 'Maria') }
341
+
342
+ it { should be_persisted }
343
+
344
+ specify do
345
+ expect(subject.save!).to eq(true)
346
+ end
347
+
348
+ specify do
349
+ expect { subject.save! }.not_to change(subject, :persisted?)
350
+ end
351
+
352
+ it 'reloads record fields taking it from response' do
353
+ expect { subject.save! }.to change { subject.name }.from('Masha').to('Mashka')
354
+ end
355
+ end
356
+ end
357
+
358
+ context 'invalid record' do
359
+ context 'new record' do
360
+ subject { model.new(name: '') }
361
+
362
+ specify do
363
+ expect { subject.save! }.to raise_error Mavenlink::RecordInvalidError, /Name.*blank/
364
+ end
365
+
366
+ specify do
367
+ expect { subject.save! rescue nil }.not_to change(subject, :persisted?)
368
+ end
369
+
370
+ it 'does not perform any requests' do
371
+ expect { subject.save! rescue nil }.not_to change { subject.name }
372
+ end
373
+ end
374
+
375
+ context 'persisted record' do
376
+ subject { model.create(name: 'Maria') }
377
+ before { subject.name = '' }
378
+
379
+ it { should be_persisted }
380
+
381
+ specify do
382
+ expect { subject.save! }.to raise_error Mavenlink::RecordInvalidError, /Name.*blank/
383
+ end
384
+
385
+ specify do
386
+ expect { subject.save! rescue nil }.not_to change(subject, :persisted?)
387
+ end
388
+
389
+ it 'does not change anything' do
390
+ expect { subject.save! rescue nil }.not_to change { subject.name }
391
+ end
392
+ end
393
+ end
394
+ end
395
+
396
+ describe '#update_attributes' do
397
+ context 'valid record' do
398
+ context 'new record' do
399
+ subject { model.new }
400
+
401
+ specify do
402
+ expect(subject.update_attributes(name: 'Maria')).to eq(true)
403
+ end
404
+
405
+ specify do
406
+ expect { subject.update_attributes(name: 'Maria') }.to change(subject, :persisted?).from(false).to(true)
407
+ end
408
+ end
409
+
410
+ context 'persisted record' do
411
+ subject { model.create(name: 'Maria') }
412
+
413
+ it { should be_persisted }
414
+
415
+ specify do
416
+ expect(subject.update_attributes(name: 'mashka')).to eq(true)
417
+ end
418
+
419
+ specify do
420
+ expect { subject.update_attributes(name: 'test') }.not_to change(subject, :persisted?)
421
+ end
422
+
423
+ it 'reloads record fields taking it from response' do
424
+ expect { subject.update_attributes(name: 'test') }.to change { subject.name }.from('Masha').to('Mashka')
425
+ end
426
+ end
427
+ end
428
+
429
+ # TODO: invalid record, update_attributes!
430
+ end
431
+
432
+ describe '#destroy' do
433
+ subject { model.create(name: 'Maria') }
434
+
435
+ specify do
436
+ expect { subject.destroy }.not_to raise_error
437
+ end
438
+ end
439
+ end