neverbounce-api 1.0.0

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 (108) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +8 -0
  3. data/.gitignore +21 -0
  4. data/.rspec +4 -0
  5. data/.rubocop.yml +1161 -0
  6. data/.travis.yml +27 -0
  7. data/.yardopts +2 -0
  8. data/Gemfile +17 -0
  9. data/Gemfile.lock +48 -0
  10. data/LICENSE +9 -0
  11. data/README.md +235 -0
  12. data/lib/never_bounce/api/client.rb +259 -0
  13. data/lib/never_bounce/api/error.rb +21 -0
  14. data/lib/never_bounce/api/feature/basic_initialize.rb +20 -0
  15. data/lib/never_bounce/api/feature/eigencache.rb +48 -0
  16. data/lib/never_bounce/api/feature/igetset.rb +41 -0
  17. data/lib/never_bounce/api/feature/oattrs.rb +100 -0
  18. data/lib/never_bounce/api/feature/require_attr.rb +27 -0
  19. data/lib/never_bounce/api/request/account_info.rb +29 -0
  20. data/lib/never_bounce/api/request/base.rb +102 -0
  21. data/lib/never_bounce/api/request/jobs_create.rb +90 -0
  22. data/lib/never_bounce/api/request/jobs_delete.rb +34 -0
  23. data/lib/never_bounce/api/request/jobs_download.rb +34 -0
  24. data/lib/never_bounce/api/request/jobs_parse.rb +55 -0
  25. data/lib/never_bounce/api/request/jobs_results.rb +53 -0
  26. data/lib/never_bounce/api/request/jobs_search.rb +57 -0
  27. data/lib/never_bounce/api/request/jobs_start.rb +47 -0
  28. data/lib/never_bounce/api/request/jobs_status.rb +37 -0
  29. data/lib/never_bounce/api/request/single_check.rb +67 -0
  30. data/lib/never_bounce/api/response/account_info.rb +39 -0
  31. data/lib/never_bounce/api/response/account_info/job_counts.rb +26 -0
  32. data/lib/never_bounce/api/response/address_info.rb +43 -0
  33. data/lib/never_bounce/api/response/base.rb +15 -0
  34. data/lib/never_bounce/api/response/container.rb +126 -0
  35. data/lib/never_bounce/api/response/credits_info/base.rb +30 -0
  36. data/lib/never_bounce/api/response/credits_info/monthly.rb +16 -0
  37. data/lib/never_bounce/api/response/credits_info/paid.rb +20 -0
  38. data/lib/never_bounce/api/response/error_message.rb +17 -0
  39. data/lib/never_bounce/api/response/feature/job_status_fields.rb +68 -0
  40. data/lib/never_bounce/api/response/feature/job_status_fields/total.rb +46 -0
  41. data/lib/never_bounce/api/response/jobs_create.rb +10 -0
  42. data/lib/never_bounce/api/response/jobs_delete.rb +8 -0
  43. data/lib/never_bounce/api/response/jobs_download.rb +19 -0
  44. data/lib/never_bounce/api/response/jobs_parse.rb +10 -0
  45. data/lib/never_bounce/api/response/jobs_results.rb +34 -0
  46. data/lib/never_bounce/api/response/jobs_results/item.rb +65 -0
  47. data/lib/never_bounce/api/response/jobs_results/query.rb +20 -0
  48. data/lib/never_bounce/api/response/jobs_search.rb +33 -0
  49. data/lib/never_bounce/api/response/jobs_search/query.rb +16 -0
  50. data/lib/never_bounce/api/response/jobs_search/result.rb +13 -0
  51. data/lib/never_bounce/api/response/jobs_start.rb +10 -0
  52. data/lib/never_bounce/api/response/jobs_status.rb +11 -0
  53. data/lib/never_bounce/api/response/message.rb +32 -0
  54. data/lib/never_bounce/api/response/single_check.rb +68 -0
  55. data/lib/never_bounce/api/response/status_message.rb +17 -0
  56. data/lib/never_bounce/api/response/success_message.rb +12 -0
  57. data/lib/never_bounce/api/session.rb +141 -0
  58. data/lib/never_bounce/api/version.rb +4 -0
  59. data/lib/neverbounce-api.rb +4 -0
  60. data/lib/neverbounce.rb +3 -0
  61. data/neverbounce-api.gemspec +20 -0
  62. data/spec/lib/never_bounce/api/client_spec.rb +199 -0
  63. data/spec/lib/never_bounce/api/feature/basic_initialize_spec.rb +25 -0
  64. data/spec/lib/never_bounce/api/feature/eigencache_spec.rb +28 -0
  65. data/spec/lib/never_bounce/api/feature/igetset_spec.rb +45 -0
  66. data/spec/lib/never_bounce/api/feature/oattrs_spec.rb +72 -0
  67. data/spec/lib/never_bounce/api/feature/require_attr_spec.rb +25 -0
  68. data/spec/lib/never_bounce/api/request/account_info_spec.rb +29 -0
  69. data/spec/lib/never_bounce/api/request/base_spec.rb +6 -0
  70. data/spec/lib/never_bounce/api/request/jobs_create_spec.rb +89 -0
  71. data/spec/lib/never_bounce/api/request/jobs_delete_spec.rb +31 -0
  72. data/spec/lib/never_bounce/api/request/jobs_download_spec.rb +31 -0
  73. data/spec/lib/never_bounce/api/request/jobs_parse_spec.rb +44 -0
  74. data/spec/lib/never_bounce/api/request/jobs_results_spec.rb +42 -0
  75. data/spec/lib/never_bounce/api/request/jobs_search_spec.rb +40 -0
  76. data/spec/lib/never_bounce/api/request/jobs_start_spec.rb +44 -0
  77. data/spec/lib/never_bounce/api/request/jobs_status_spec.rb +31 -0
  78. data/spec/lib/never_bounce/api/request/single_check_spec.rb +44 -0
  79. data/spec/lib/never_bounce/api/response/account_info/job_counts_spec.rb +7 -0
  80. data/spec/lib/never_bounce/api/response/account_info_spec.rb +9 -0
  81. data/spec/lib/never_bounce/api/response/address_info_spec.rb +7 -0
  82. data/spec/lib/never_bounce/api/response/base_spec.rb +6 -0
  83. data/spec/lib/never_bounce/api/response/container_spec.rb +142 -0
  84. data/spec/lib/never_bounce/api/response/credits_info/base_spec.rb +31 -0
  85. data/spec/lib/never_bounce/api/response/credits_info/monthly_spec.rb +11 -0
  86. data/spec/lib/never_bounce/api/response/credits_info/paid_spec.rb +11 -0
  87. data/spec/lib/never_bounce/api/response/feature/job_status_fields/total_spec.rb +7 -0
  88. data/spec/lib/never_bounce/api/response/feature/job_status_fields_spec.rb +42 -0
  89. data/spec/lib/never_bounce/api/response/jobs_create_spec.rb +7 -0
  90. data/spec/lib/never_bounce/api/response/jobs_delete_spec.rb +7 -0
  91. data/spec/lib/never_bounce/api/response/jobs_download_spec.rb +7 -0
  92. data/spec/lib/never_bounce/api/response/jobs_parse_spec.rb +7 -0
  93. data/spec/lib/never_bounce/api/response/jobs_results/jobs_results_item_spec.rb +7 -0
  94. data/spec/lib/never_bounce/api/response/jobs_results/jobs_results_query_spec.rb +7 -0
  95. data/spec/lib/never_bounce/api/response/jobs_results_spec.rb +7 -0
  96. data/spec/lib/never_bounce/api/response/jobs_search/jobs_search_query_spec.rb +7 -0
  97. data/spec/lib/never_bounce/api/response/jobs_search/jobs_search_result_spec.rb +7 -0
  98. data/spec/lib/never_bounce/api/response/jobs_search_spec.rb +7 -0
  99. data/spec/lib/never_bounce/api/response/jobs_start_spec.rb +7 -0
  100. data/spec/lib/never_bounce/api/response/jobs_status_spec.rb +7 -0
  101. data/spec/lib/never_bounce/api/response/single_check_spec.rb +7 -0
  102. data/spec/lib/never_bounce/api/response/spec_helper.rb +8 -0
  103. data/spec/lib/never_bounce/api/session_spec.rb +140 -0
  104. data/spec/lib/never_bounce/api_spec.rb +8 -0
  105. data/spec/spec_helper.rb +49 -0
  106. data/spec/spec_support/include_dir_context.rb +22 -0
  107. data/spec/spec_support/simplecov.rb +18 -0
  108. metadata +210 -0
@@ -0,0 +1,142 @@
1
+
2
+ module NeverBounce; module API; module Response
3
+ describe Container do
4
+ include_dir_context __dir__
5
+
6
+ it_behaves_like "instantiatable"
7
+ it_behaves_like "properly inherited"
8
+
9
+ describe "#body_hash" do
10
+ it "requires `raw`" do
11
+ expect { newo.body_hash }.to raise_error(AttributeError, "Attribute must be set: raw")
12
+ end
13
+
14
+ it "generally works" do
15
+ r = newo(raw: '{"a":10}')
16
+ expect(r.body_hash).to eq({"a" => 10})
17
+ end
18
+ end
19
+
20
+ describe ".oattr" do
21
+ # NOTE: Tests for this section are a few "matrix" scenarios which reasonably cover possible combinations.
22
+ context "case 1" do
23
+ let(:klass) do
24
+ Class.new(described_class) do
25
+ oattr :a, :scalar
26
+ oattr :b, :scalar, type: :integer
27
+ oattr :c, :scalar, type: :integer, allow_nil: true
28
+ oattr :d, :writer
29
+ oattr :e, :custom
30
+ oattr :f, :scalar, type: :float
31
+ oattr :g, :scalar, type: :float, allow_nil: true
32
+
33
+ def d
34
+ @d ||= body_hash.fetch("d")
35
+ end
36
+
37
+ def e
38
+ @e ||= body_hash.fetch("e")
39
+ end
40
+
41
+ def e=(v)
42
+ @e = v
43
+ end
44
+ end
45
+ end
46
+
47
+ it "generally works" do
48
+ expect(klass.oattrs).to eq [:a, :b, :c, :d, :e, :f, :g]
49
+
50
+ r = klass.new(body_hash: {})
51
+ expect { r.a }.to raise_error KeyError
52
+ expect { r.d }.to raise_error KeyError
53
+ expect { r.e }.to raise_error KeyError
54
+ expect { r.f }.to raise_error KeyError
55
+
56
+ # Numeric conversion, valid values.
57
+ r = klass.new(body_hash: {
58
+ "b" => "12",
59
+ "c" => "34",
60
+ "f" => "1.2",
61
+ "g" => "3.4",
62
+ })
63
+ expect(r.b).to eq 12
64
+ expect(r.c).to eq 34
65
+ expect(r.f).to eq 1.2
66
+ expect(r.g).to eq 3.4
67
+
68
+ # Numeric conversion, empty strings.
69
+ r = klass.new(body_hash: {
70
+ "b" => "",
71
+ "c" => "",
72
+ "f" => "",
73
+ "g" => "",
74
+ })
75
+ expect { r.b }.to raise_error(ArgumentError, /^invalid value for Integer/)
76
+ expect { r.c }.to raise_error(ArgumentError, /^invalid value for Integer/)
77
+ expect { r.f }.to raise_error(ArgumentError, /^invalid value for Float/)
78
+ expect { r.g }.to raise_error(ArgumentError, /^invalid value for Float/)
79
+
80
+ # Numeric conversion, invalid strings.
81
+ r = klass.new(body_hash: {
82
+ "b" => "xyz",
83
+ "c" => "xyz",
84
+ "f" => "xyz",
85
+ "g" => "xyz",
86
+ })
87
+ expect { r.b }.to raise_error(ArgumentError, /^invalid value for Integer/)
88
+ expect { r.c }.to raise_error(ArgumentError, /^invalid value for Integer/)
89
+ expect { r.f }.to raise_error(ArgumentError, /^invalid value for Float/)
90
+ expect { r.g }.to raise_error(ArgumentError, /^invalid value for Float/)
91
+
92
+ # Nill allowance.
93
+ r = klass.new(body_hash: {
94
+ "b" => nil,
95
+ "c" => nil,
96
+ "f" => nil,
97
+ "g" => nil,
98
+ })
99
+ expect { r.b }.to raise_error(TypeError, /nil into Integer/)
100
+ expect(r.c).to be nil
101
+ expect { r.f }.to raise_error(TypeError, /nil into Float/)
102
+ expect(r.g).to be nil
103
+
104
+ # Complete set.
105
+ r = klass.new(body_hash: {
106
+ "a" => "hello",
107
+ "b" => 10,
108
+ "c" => 20,
109
+ "d" => [1, 2, 3],
110
+ "e" => {kk: 1},
111
+ "f" => 1.5,
112
+ "g" => 2.6,
113
+ })
114
+
115
+ expect { r.touch }.not_to raise_error # An important one.
116
+
117
+ expect(r.a).to eq "hello"
118
+ expect(r.b).to eq 10
119
+ expect(r.c).to eq 20
120
+ expect(r.d).to eq([1, 2, 3])
121
+ expect(r.e).to eq({kk: 1})
122
+ expect(r.f).to eq 1.5
123
+ expect(r.g).to eq 2.6
124
+
125
+ # Accessors.
126
+ r.a += "!"
127
+ expect(r.a).to eq "hello!"
128
+ r.b += 1
129
+ expect(r.b).to eq 11
130
+ r.c += 1
131
+ expect(r.c).to eq 21
132
+ r.d += [4]
133
+ expect(r.d).to eq [1, 2, 3, 4]
134
+ r.f += 0.1
135
+ expect(r.f).to eq 1.6
136
+ r.g += 0.1
137
+ expect(r.g).to eq 2.7
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end; end; end
@@ -0,0 +1,31 @@
1
+
2
+ describe NeverBounce::API::Response::CreditsInfo::Base do
3
+ include_dir_context __dir__
4
+
5
+ it_behaves_like "instantiatable"
6
+ it_behaves_like "properly inherited"
7
+
8
+ let(:klass) do
9
+ Class.new(described_class) do
10
+ attr_accessor :subscription_type
11
+ end
12
+ end
13
+
14
+ describe "#monthly?" do
15
+ it "generally works" do
16
+ r = klass.new
17
+ r.subscription_type = :monthly
18
+ expect(r.monthly?).to be true
19
+ expect(r.paid?).to be false
20
+ end
21
+ end
22
+
23
+ describe "#paid?" do
24
+ it "generally works" do
25
+ r = klass.new
26
+ r.subscription_type = :paid
27
+ expect(r.monthly?).to be false
28
+ expect(r.paid?).to be true
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,11 @@
1
+
2
+ describe NeverBounce::API::Response::CreditsInfo::Monthly do
3
+ include_dir_context __dir__
4
+
5
+ it_behaves_like "instantiatable"
6
+ it_behaves_like "properly inherited"
7
+
8
+ describe "#subscription_type" do
9
+ it { expect(newo.subscription_type).to eq :monthly }
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+
2
+ describe NeverBounce::API::Response::CreditsInfo::Paid do
3
+ include_dir_context __dir__
4
+
5
+ it_behaves_like "instantiatable"
6
+ it_behaves_like "properly inherited"
7
+
8
+ describe "#subscription_type" do
9
+ it { expect(newo.subscription_type).to eq :paid }
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+
2
+ describe NeverBounce::API::Response::Feature::JobStatusFields::Total do
3
+ include_dir_context __dir__
4
+
5
+ it_behaves_like "instantiatable"
6
+ it_behaves_like "properly inherited"
7
+ end
@@ -0,0 +1,42 @@
1
+
2
+ module NeverBounce; module API; module Response; module Feature
3
+ describe JobStatusFields do
4
+ context "when invalid class" do
5
+ it "generally works" do
6
+ feature = described_class
7
+ expect { Class.new { feature.load(self) } }.to raise_error(ArgumentError, /is not an ancestor of Response::Container$/)
8
+ end
9
+ end
10
+
11
+ context "when valid class" do
12
+ it "generally works" do
13
+ feature = described_class
14
+
15
+ klass = Class.new(Response::StatusMessage) { feature.load(self) }
16
+
17
+ # Use a complete real-world example.
18
+ r = klass.new(body_hash: {"status"=>"success", "id"=>302499, "job_status"=>"complete", "filename"=>"20170815-103321.csv", "created_at"=>"2017-08-15 17:19:41", "started_at"=>"2017-08-15 17:19:42", "finished_at"=>"2017-08-15 17:19:45", "total"=>{"records"=>11, "billable"=>12, "processed"=>13, "valid"=>14, "invalid"=>15, "catchall"=>16, "disposable"=>17, "unknown"=>18, "duplicates"=>19, "bad_syntax"=>20}, "bounce_estimate"=>34.56, "percent_complete"=>100, "execution_time"=>99})
19
+ expect(r.id).to eq 302499
20
+ expect(r.job_status).to eq "complete"
21
+ expect(r.filename).to eq "20170815-103321.csv"
22
+ expect(r.created_at).to eq "2017-08-15 17:19:41"
23
+ expect(r.started_at).to eq "2017-08-15 17:19:42"
24
+ expect(r.finished_at).to eq "2017-08-15 17:19:45"
25
+ expect(r.bounce_estimate).to eq 34.56
26
+ expect(r.percent_complete).to eq 100
27
+ expect(r.execution_time).to eq 99
28
+ expect(total = r.total).to be_a described_class::Total
29
+ expect(total.records).to eq 11
30
+ expect(total.billable).to eq 12
31
+ expect(total.processed).to eq 13
32
+ expect(total.valid).to eq 14
33
+ expect(total.invalid).to eq 15
34
+ expect(total.catchall).to eq 16
35
+ expect(total.disposable).to eq 17
36
+ expect(total.unknown).to eq 18
37
+ expect(total.duplicates).to eq 19
38
+ expect(total.bad_syntax).to eq 20
39
+ end
40
+ end
41
+ end
42
+ end; end; end; end
@@ -0,0 +1,7 @@
1
+
2
+ describe NeverBounce::API::Response::JobsCreate do
3
+ include_dir_context __dir__
4
+
5
+ it_behaves_like "instantiatable"
6
+ it_behaves_like "properly inherited"
7
+ end
@@ -0,0 +1,7 @@
1
+
2
+ describe NeverBounce::API::Response::JobsDelete do
3
+ include_dir_context __dir__
4
+
5
+ it_behaves_like "instantiatable"
6
+ it_behaves_like "properly inherited"
7
+ end
@@ -0,0 +1,7 @@
1
+
2
+ describe NeverBounce::API::Response::JobsDownload do
3
+ include_dir_context __dir__
4
+
5
+ it_behaves_like "instantiatable"
6
+ it_behaves_like "properly inherited"
7
+ end
@@ -0,0 +1,7 @@
1
+
2
+ describe NeverBounce::API::Response::JobsParse do
3
+ include_dir_context __dir__
4
+
5
+ it_behaves_like "instantiatable"
6
+ it_behaves_like "properly inherited"
7
+ end
@@ -0,0 +1,7 @@
1
+
2
+ describe NeverBounce::API::Response::JobsResults::Item do
3
+ include_dir_context __dir__
4
+
5
+ it_behaves_like "instantiatable"
6
+ it_behaves_like "properly inherited"
7
+ end
@@ -0,0 +1,7 @@
1
+
2
+ describe NeverBounce::API::Response::JobsResults::Query do
3
+ include_dir_context __dir__
4
+
5
+ it_behaves_like "instantiatable"
6
+ it_behaves_like "properly inherited"
7
+ end
@@ -0,0 +1,7 @@
1
+
2
+ describe NeverBounce::API::Response::JobsResults do
3
+ include_dir_context __dir__
4
+
5
+ it_behaves_like "instantiatable"
6
+ it_behaves_like "properly inherited"
7
+ end
@@ -0,0 +1,7 @@
1
+
2
+ describe NeverBounce::API::Response::JobsSearch::Query do
3
+ include_dir_context __dir__
4
+
5
+ it_behaves_like "instantiatable"
6
+ it_behaves_like "properly inherited"
7
+ end
@@ -0,0 +1,7 @@
1
+
2
+ describe NeverBounce::API::Response::JobsSearch::Result do
3
+ include_dir_context __dir__
4
+
5
+ it_behaves_like "instantiatable"
6
+ it_behaves_like "properly inherited"
7
+ end
@@ -0,0 +1,7 @@
1
+
2
+ describe NeverBounce::API::Response::JobsSearch do
3
+ include_dir_context __dir__
4
+
5
+ it_behaves_like "instantiatable"
6
+ it_behaves_like "properly inherited"
7
+ end
@@ -0,0 +1,7 @@
1
+
2
+ describe NeverBounce::API::Response::JobsStart do
3
+ include_dir_context __dir__
4
+
5
+ it_behaves_like "instantiatable"
6
+ it_behaves_like "properly inherited"
7
+ end
@@ -0,0 +1,7 @@
1
+
2
+ describe NeverBounce::API::Response::JobsStatus do
3
+ include_dir_context __dir__
4
+
5
+ it_behaves_like "instantiatable"
6
+ it_behaves_like "properly inherited"
7
+ end
@@ -0,0 +1,7 @@
1
+
2
+ describe NeverBounce::API::Response::SingleCheck do
3
+ include_dir_context __dir__
4
+
5
+ it_behaves_like "instantiatable"
6
+ it_behaves_like "properly inherited"
7
+ end
@@ -0,0 +1,8 @@
1
+
2
+ shared_context __dir__ do
3
+ shared_examples "properly inherited" do
4
+ it "doesn't have duplicate oattrs" do
5
+ expect((oattrs = described_class.oattrs).uniq).to eq oattrs
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,140 @@
1
+
2
+ module NeverBounce; module API
3
+ describe Session do
4
+ include_dir_context __dir__
5
+
6
+ it_behaves_like "instantiatable"
7
+
8
+ describe "#server_raw" do
9
+ let(:m) { :server_raw }
10
+ context "when NOK" do
11
+ it "generally works" do
12
+ r = newo(
13
+ server_obj: Class.new do
14
+ def code; 123; end
15
+ def ok?; false; end
16
+ end.new
17
+ )
18
+ expect { r.send(m) }.to raise_error(RequestError, "Code not OK: 123")
19
+ end
20
+ end
21
+
22
+ context "when OK" do
23
+ it "generally works" do
24
+ r = newo(
25
+ server_obj: Class.new do
26
+ def body; "abc"; end
27
+ def ok?; true; end
28
+ end.new,
29
+ )
30
+ expect(r.send(m)).to eq "abc"
31
+ end
32
+ end
33
+ end # describe "#server_raw"
34
+
35
+ describe "#robj_hash_preview" do
36
+ let(:m) { :robj_hash_preview }
37
+
38
+ context "when unknown content type" do
39
+ it "generally works" do
40
+ r = newo(server_content_type: "type/a")
41
+ expect(r.send(m)).to be false
42
+ end
43
+ end
44
+
45
+ context "when 'application/json'" do
46
+ it "generally works" do
47
+ r = newo(
48
+ server_content_type: "application/json",
49
+ server_raw: "xyz",
50
+ )
51
+ expect { r.send(m) }.to raise_error(FormatError, /^JSON::ParserError: /)
52
+
53
+ r = newo(
54
+ server_content_type: "application/json",
55
+ server_raw: '{"a":12,"b":"abc"}',
56
+ )
57
+ expect(r.send(m)).to eq({"a" => 12, "b" => "abc"})
58
+ end
59
+ end
60
+ end
61
+
62
+ describe "#robj_klass_and_attrs" do
63
+ let(:m) { :robj_klass_and_attrs }
64
+
65
+ # A minimum viable instance for tests below.
66
+ def newo(attrs = {})
67
+ request_klass = Class.new do
68
+ def self.response_klass; Response::JobsParse; end
69
+ end
70
+
71
+ Class.new(described_class) do
72
+ def server_obj; raise "This must never be called"; end
73
+ end.new({
74
+ request: request_klass.new,
75
+ server_raw: "server_raw",
76
+ }.merge(attrs))
77
+ end
78
+
79
+ it "validates `robj_hash_preview`" do
80
+ r = newo(robj_hash_preview: "abc")
81
+ expect { r.send(m) }.to raise_error(AttributeError, "Unknown `robj_hash_preview`: \"abc\"")
82
+ end
83
+
84
+ it "works for raw data" do
85
+ r = newo(
86
+ robj_hash_preview: false,
87
+ )
88
+ #expect { r.send(m) }.to raise_error(FormatError, /^Key 'status' not found: /)
89
+ expect(r.send(m)).to eq [Response::JobsParse, {:raw => "server_raw"}]
90
+ end
91
+
92
+ it "works for invalid data" do
93
+ # Valid JSON.
94
+ r = newo(
95
+ robj_hash_preview: {"a" => 12},
96
+ )
97
+ expect { r.send(m) }.to raise_error(FormatError, /^Key 'status' not found: /)
98
+ end
99
+
100
+ it "works for valid data" do
101
+ r = newo(
102
+ robj_hash_preview: {"status" => "success"},
103
+ )
104
+ expect(r.send(m)).to eq [Response::JobsParse, {:body_hash=>{"status"=>"success"}}]
105
+
106
+ r = newo(
107
+ robj_hash_preview: {"status" => "not-a-success"}, # Not necessarily "error".
108
+ )
109
+ expect(r.send(m)).to eq [Response::ErrorMessage, {:body_hash=>{"status"=>"not-a-success"}}]
110
+ end
111
+ end
112
+
113
+ describe "#server_obj" do
114
+ it "requires `request`" do
115
+ r = newo
116
+ expect { r.server_obj }.to raise_error "Attribute must be set: request"
117
+ end
118
+
119
+ it "generally works" do
120
+ # See implementation notes below.
121
+ r = newo(
122
+ httparty: (httparty = cllggr.new),
123
+ request: Request::JobsParse.new(api_key: "api_key", job_id: "123"),
124
+ )
125
+ expect(r.server_obj).to eq 1 # Result of `cllggr`.
126
+ args = httparty._calls[0]
127
+ expect(args).to be_a Array
128
+ expect(args).not_to be_empty
129
+ end
130
+ end
131
+ end
132
+ end; end
133
+
134
+ # Implementation notes:
135
+ #
136
+ # * We test class's general abilities on a real request class.
137
+ # * Consider this great hack to debug tests easier:
138
+ # Class.new(described_class) do
139
+ # def server_obj; raise "This must never be called"; end
140
+ # end.new(...)