textmagic 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ gem 'httparty'
3
+ require 'httparty'
4
+ require 'charset'
5
+ require 'validation'
6
+ require 'api'
7
+ require 'response'
8
+ require 'executor'
9
+ require 'error'
10
+
11
+ module TextMagic #:nodoc:
12
+ end
@@ -0,0 +1,34 @@
1
+ module TextMagic
2
+
3
+ class API
4
+
5
+ module Validation
6
+
7
+ MAX_LENGTH_GSM = [160, 306, 459]
8
+ MAX_LENGTH_UNICODE = [70, 134, 201]
9
+
10
+ # Validates message text length. Returns +true+ if the text length is
11
+ # within the limits for the unicode/parts combination, otherwise it
12
+ # returns +false+.
13
+ #
14
+ # Note: <em>Maximum lengths for 1, 2 and 3-part GSM 03.38 messages are
15
+ # 160, 306 and 459 respectively.
16
+ # Maximum lengths for 1, 2 and 3-part unicode messages are
17
+ # 70, 134 and 201 respectively.</em>
18
+ def validate_text_length(text, unicode, parts = 3)
19
+ max_text_length = (unicode ? MAX_LENGTH_UNICODE : MAX_LENGTH_GSM)[parts - 1]
20
+ text.size <= max_text_length
21
+ end
22
+
23
+ # Validates a list of phone numbers. Returns +true+ if the list is not empty
24
+ # and all phone numbers are digit-only strings of maximum length of 15,
25
+ # otherwise it returns +false+.
26
+ def validate_phones(*phones)
27
+ phones.flatten!
28
+ return false if phones.empty?
29
+ phones.each { |phone| return false unless phone =~ /^\d{1,15}$/ }
30
+ true
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,246 @@
1
+ require 'test_helper'
2
+
3
+ class APITest < Test::Unit::TestCase
4
+
5
+ context 'Initialization' do
6
+
7
+ should 'require username and password' do
8
+ lambda { TextMagic::API.new }.should raise_error(ArgumentError)
9
+ TextMagic::API.new(random_string, random_string)
10
+ end
11
+ end
12
+
13
+ context 'Account command' do
14
+
15
+ setup do
16
+ @balance = 0.01 * rand(1e4)
17
+ @username, @password = random_string, random_string
18
+ @api = TextMagic::API.new(@username, @password)
19
+ end
20
+
21
+ should 'call Executor execute with correct arguments' do
22
+ TextMagic::API::Executor.expects(:execute).with('account', @username, @password).returns({})
23
+ @api.account
24
+ end
25
+
26
+ should 'return a hash extended with TextMagic::API::Response::Account' do
27
+ TextMagic::API::Executor.expects(:execute).returns({ 'balance' => @balance.to_s })
28
+ response = @api.account
29
+ response.class.should == Hash
30
+ response.is_a?(TextMagic::API::Response::Account).should == true
31
+ end
32
+
33
+ should 'return a hash with balance value' do
34
+ TextMagic::API::Executor.expects(:execute).returns({ 'balance' => @balance.to_s })
35
+ response = @api.account
36
+ response['balance'].should be_close(@balance, 1e-10)
37
+ end
38
+ end
39
+
40
+ context 'Send command' do
41
+
42
+ setup do
43
+ @username, @password = random_string, random_string
44
+ @text, @phone = random_string, random_phone
45
+ @api = TextMagic::API.new(@username, @password)
46
+ TextMagic::API::Executor.stubs(:execute)
47
+ end
48
+
49
+ should 'call Executor execute with correct arguments' do
50
+ TextMagic::API::Executor.expects(:execute).with('send', @username, @password, :text => @text, :phone => @phone, :unicode => 0)
51
+ @api.send(@text, @phone)
52
+ end
53
+
54
+ should 'join multiple phone numbers supplied as an array' do
55
+ phones = Array.new(3) { random_phone }
56
+ TextMagic::API::Executor.expects(:execute).with('send', @username, @password, :text => @text, :phone => phones.join(','), :unicode => 0)
57
+ @api.send(@text, phones)
58
+ end
59
+
60
+ should 'join multiple phone numbers supplied as arguments' do
61
+ phones = Array.new(3) { random_phone }
62
+ TextMagic::API::Executor.expects(:execute).with('send', @username, @password, :text => @text, :phone => phones.join(','), :unicode => 0)
63
+ @api.send(@text, *phones)
64
+ end
65
+
66
+ should 'replace true with 1 for unicode' do
67
+ TextMagic::API::Executor.expects(:execute).with('send', @username, @password, :text => @text, :phone => @phone, :unicode => 1)
68
+ @api.send(@text, @phone, :unicode => true)
69
+ end
70
+
71
+ should 'set unicode value to 0 if it is not set to by user and text contains only characters from GSM 03.38 charset' do
72
+ TextMagic::API::Executor.expects(:execute).with('send', @username, @password, :text => @text, :phone => @phone, :unicode => 0).times(2)
73
+ @api.send(@text, @phone)
74
+ @api.send(@text, @phone, :unicode => false)
75
+ end
76
+
77
+ should 'raise an error if unicode is set to 0 and text contains characters outside of GSM 03.38 charset' do
78
+ text = 'Вильма Привет'
79
+ lambda { @api.send(text, @phone, :unicode => false) }.should raise_error(TextMagic::API::Error)
80
+ end
81
+
82
+ should 'raise an error if unicode value is not valid' do
83
+ lambda { @api.send(@text, @phone, :unicode => 2 + rand(10)) }.should raise_error(TextMagic::API::Error)
84
+ lambda { @api.send(@text, @phone, :unicode => random_string) }.should raise_error(TextMagic::API::Error)
85
+ end
86
+
87
+ should 'raise an error if no phone numbers are specified' do
88
+ lambda { @api.send(@text) }.should raise_error(TextMagic::API::Error)
89
+ lambda { @api.send(@text, []) }.should raise_error(TextMagic::API::Error)
90
+ end
91
+
92
+ should 'raise an error if format of any of the specified phone numbers is invalid' do
93
+ TextMagic::API.expects(:validate_phones).returns(false)
94
+ lambda { @api.send(@text, random_string) }.should raise_error(TextMagic::API::Error)
95
+ end
96
+
97
+ should 'raise an error if text is empty' do
98
+ lambda { @api.send('', @phone) }.should raise_error(TextMagic::API::Error)
99
+ end
100
+
101
+ should 'raise an error if text is too long' do
102
+ TextMagic::API.expects(:validate_text_length).returns(false)
103
+ lambda { @api.send(@text, @phone) }.should raise_error(TextMagic::API::Error)
104
+ end
105
+
106
+ should 'return a hash extended with TextMagic::API::Response::Send' do
107
+ message_id = random_string
108
+ TextMagic::API::Executor.expects(:execute).returns({ 'message_id' => { message_id => @phone }, 'sent_text' => @text, 'parts_count' => 1 })
109
+ response = @api.send(@text, @phone)
110
+ response.class.should == Hash
111
+ response.is_a?(TextMagic::API::Response::Send).should == true
112
+ end
113
+
114
+ should 'return a hash with message_id_hash, message_ids, sent_text and parts_count values' do
115
+ message_id = random_string
116
+ TextMagic::API::Executor.expects(:execute).returns({ 'message_id' => { message_id => @phone }, 'sent_text' => @text, 'parts_count' => 1 })
117
+ response = @api.send(@text, @phone)
118
+ response['message_id_hash'].should == { @phone => message_id }
119
+ response['message_ids'].should == [message_id]
120
+ response['parts_count'].should == 1
121
+ end
122
+ end
123
+
124
+ context 'Message status command' do
125
+
126
+ setup do
127
+ @username, @password = random_string, random_string
128
+ @api = TextMagic::API.new(@username, @password)
129
+ end
130
+
131
+ should 'call Executor execute with correct arguments' do
132
+ id = random_string
133
+ TextMagic::API::Executor.expects(:execute).with('message_status', @username, @password, :ids => id)
134
+ @api.message_status(id)
135
+ end
136
+
137
+ should 'join ids supplied as array' do
138
+ ids = Array.new(3) { random_string }
139
+ TextMagic::API::Executor.expects(:execute).with('message_status', @username, @password, :ids => ids.join(','))
140
+ @api.message_status(ids)
141
+ end
142
+
143
+ should 'join ids supplied as arguments' do
144
+ ids = Array.new(3) { random_string }
145
+ TextMagic::API::Executor.expects(:execute).with('message_status', @username, @password, :ids => ids.join(','))
146
+ @api.message_status(*ids)
147
+ end
148
+
149
+ should 'not call execute and should raise an exception if no ids are specified' do
150
+ TextMagic::API::Executor.expects(:execute).never
151
+ lambda { @api.message_status }.should raise_error(TextMagic::API::Error)
152
+ end
153
+
154
+ should 'return a hash extended with TextMagic::API::Response::MessageStatus' do
155
+ TextMagic::API::Executor.expects(:execute).returns({ '8659912' => {} })
156
+ response = @api.message_status(random_string)
157
+ response.class.should == Hash
158
+ response.is_a?(TextMagic::API::Response::MessageStatus).should == true
159
+ end
160
+
161
+ should 'return a hash with message ids as keys' do
162
+ TextMagic::API::Executor.expects(:execute).returns({ '8659912' => {} })
163
+ response = @api.message_status(random_string)
164
+ response['8659912'].should == {}
165
+ end
166
+ end
167
+
168
+ context 'Receive command' do
169
+
170
+ setup do
171
+ @username, @password = random_string, random_string
172
+ @api = TextMagic::API.new(@username, @password)
173
+ end
174
+
175
+ should 'call Executor execute with correct arguments' do
176
+ TextMagic::API::Executor.expects(:execute).with('receive', @username, @password, :last_retrieved_id => nil)
177
+ @api.receive
178
+ end
179
+
180
+ should 'accept last_retrieved_id optional value' do
181
+ last_retrieved_id = rand(1e10)
182
+ TextMagic::API::Executor.expects(:execute).with('receive', @username, @password, :last_retrieved_id => last_retrieved_id)
183
+ @api.receive(last_retrieved_id)
184
+ end
185
+
186
+ should 'return a hash extended with TextMagic::API::Response::Receive' do
187
+ TextMagic::API::Executor.expects(:execute).returns({ 'messages' => [], 'unread' => 0 })
188
+ response = @api.receive
189
+ response.class.should == Hash
190
+ response.is_a?(TextMagic::API::Response::Receive).should == true
191
+ end
192
+
193
+ should 'return a hash with unread and messages values' do
194
+ TextMagic::API::Executor.expects(:execute).returns({ 'messages' => [], 'unread' => 0 })
195
+ response = @api.receive
196
+ response['unread'].should == 0
197
+ response['messages'].should == []
198
+ end
199
+ end
200
+
201
+ context 'Delete reply command' do
202
+
203
+ setup do
204
+ @username, @password = random_string, random_string
205
+ @api = TextMagic::API.new(@username, @password)
206
+ end
207
+
208
+ should 'call Executor execute with correct arguments' do
209
+ id = random_string
210
+ TextMagic::API::Executor.expects(:execute).with('delete_reply', @username, @password, :ids => id)
211
+ @api.delete_reply(id)
212
+ end
213
+
214
+ should 'join ids supplied as array' do
215
+ ids = Array.new(3) { random_string }
216
+ TextMagic::API::Executor.expects(:execute).with('delete_reply', @username, @password, :ids => ids.join(','))
217
+ @api.delete_reply(ids)
218
+ end
219
+
220
+ should 'join ids supplied as arguments' do
221
+ ids = Array.new(3) { random_string }
222
+ TextMagic::API::Executor.expects(:execute).with('delete_reply', @username, @password, :ids => ids.join(','))
223
+ @api.delete_reply(*ids)
224
+ end
225
+
226
+ should 'not call execute and should raise an exception if no ids are specified' do
227
+ TextMagic::API::Executor.expects(:execute).never
228
+ lambda { @api.delete_reply }.should raise_error(TextMagic::API::Error)
229
+ end
230
+
231
+ should 'return a hash extended with TextMagic::API::Response::DeleteReply' do
232
+ ids = Array.new(3) { random_string }
233
+ TextMagic::API::Executor.expects(:execute).returns({ 'deleted' => ids })
234
+ response = @api.delete_reply(ids)
235
+ response.class.should == Hash
236
+ response.is_a?(TextMagic::API::Response::DeleteReply).should == true
237
+ end
238
+
239
+ should 'return a hash with deleted value' do
240
+ ids = Array.new(3) { random_string }
241
+ TextMagic::API::Executor.expects(:execute).returns({ 'deleted' => ids })
242
+ response = @api.delete_reply(ids)
243
+ response.deleted.should == ids
244
+ end
245
+ end
246
+ end
@@ -0,0 +1,28 @@
1
+ require 'test_helper'
2
+ require 'json'
3
+
4
+ class CharsetTest < Test::Unit::TestCase
5
+
6
+ context 'is_gsm method' do
7
+
8
+ should 'return true if all characters are in GSM 03.38 charset' do
9
+ TextMagic::API.is_gsm(('a'..'z').to_a.join).should == true
10
+ TextMagic::API.is_gsm(('A'..'Z').to_a.join).should == true
11
+ TextMagic::API.is_gsm(('0'..'9').to_a.join).should == true
12
+ TextMagic::API.is_gsm("@£$¥€").should == true
13
+ TextMagic::API.is_gsm("\n\r\e\f\\\"").should == true
14
+ TextMagic::API.is_gsm("èéùìòÇØøÅåÉÆæß").should == true
15
+ TextMagic::API.is_gsm("ΔΦΓΛΩΠΨΣΘΞ").should == true
16
+ TextMagic::API.is_gsm("^{}[~]| !#¤%&'()").should == true
17
+ TextMagic::API.is_gsm("*+,-./_:;<=>?¡¿§").should == true
18
+ TextMagic::API.is_gsm("ÖÑÜöñüàäÄ").should == true
19
+ end
20
+
21
+ should 'return false if some characters are outside of GSM 03.38 charset' do
22
+ TextMagic::API.is_gsm('Arabic: مرحبا فيلما').should == false
23
+ TextMagic::API.is_gsm('Chinese: 您好').should == false
24
+ TextMagic::API.is_gsm('Cyrilic: Вильма Привет').should == false
25
+ TextMagic::API.is_gsm('Thai: สวัสดี').should == false
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,24 @@
1
+ require 'test_helper'
2
+
3
+ class ErrorTest < Test::Unit::TestCase
4
+
5
+ context 'Initialization' do
6
+
7
+ setup do
8
+ @code = rand(1e3)
9
+ @message = random_string
10
+ end
11
+
12
+ should 'accept a hash with error_code and error_message' do
13
+ e = TextMagic::API::Error.new('error_code' => @code, 'error_message' => @message)
14
+ e.code.should == @code
15
+ e.message.should == @message
16
+ end
17
+
18
+ should 'accept error_code and error_message' do
19
+ e = TextMagic::API::Error.new(@code, @message)
20
+ e.code.should == @code
21
+ e.message.should == @message
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,70 @@
1
+ require 'test_helper'
2
+ require 'json'
3
+
4
+ class ExecutorTest < Test::Unit::TestCase
5
+
6
+ context "execute method" do
7
+
8
+ setup do
9
+ FakeWeb.allow_net_connect = false
10
+
11
+ @username, @password = random_string, random_string
12
+ @command, @options = random_string, random_hash
13
+ @uri = build_uri(@command, @username, @password, @options)
14
+ end
15
+
16
+ should 'not send HTTP request without command' do
17
+ TextMagic::API::Executor.expects(:get).never
18
+ lambda {
19
+ TextMagic::API::Executor.execute(nil, @username, @password, @options)
20
+ }.should raise_error(TextMagic::API::Error)
21
+ end
22
+
23
+ should 'not send HTTP request without username' do
24
+ TextMagic::API::Executor.expects(:get).never
25
+ lambda {
26
+ TextMagic::API::Executor.execute(@command, nil, @password, @options)
27
+ }.should raise_error(TextMagic::API::Error)
28
+ end
29
+
30
+ should 'not send HTTP request without password' do
31
+ TextMagic::API::Executor.expects(:get).never
32
+ lambda {
33
+ TextMagic::API::Executor.execute(@command, @username, nil, @options)
34
+ }.should raise_error(TextMagic::API::Error)
35
+ end
36
+
37
+ should 'send a GET request to proper uri' do
38
+ response = random_string
39
+ FakeWeb.register_uri(:get, @uri, :string => response)
40
+ TextMagic::API::Executor.execute(@command, @username, @password, @options)
41
+ end
42
+
43
+ should 'not send parameters with empty keys' do
44
+ options_with_empty_values = @options.merge(nil => random_string, '' => random_string)
45
+ TextMagic::API::Executor.expects(:get).with('/api', :query => @options, :format => :json)
46
+ TextMagic::API::Executor.execute(@command, @username, @password, options_with_empty_values)
47
+ end
48
+
49
+ should 'not send parameters with empty values' do
50
+ options_with_empty_values = @options.merge(random_string => nil, random_string => '')
51
+ TextMagic::API::Executor.expects(:get).with('/api', :query => @options, :format => :json)
52
+ TextMagic::API::Executor.execute(@command, @username, @password, options_with_empty_values)
53
+ end
54
+
55
+ should 'raise an error if the response contains error_code' do
56
+ response = "{error_code:#{1 + rand(10)}}"
57
+ FakeWeb.register_uri(:get, @uri, :string => response)
58
+ lambda {
59
+ TextMagic::API::Executor.execute(@command, @username, @password, @options)
60
+ }.should raise_error(TextMagic::API::Error)
61
+ end
62
+
63
+ should 'return a hash with values from the response' do
64
+ hash = random_hash
65
+ FakeWeb.register_uri(:get, @uri, :string => hash.to_json)
66
+ response = TextMagic::API::Executor.execute(@command, @username, @password, @options)
67
+ response.should == hash
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,38 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'mocha'
5
+ require 'matchy'
6
+ require 'fakeweb'
7
+
8
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
9
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
10
+
11
+ require 'textmagic'
12
+
13
+ class Test::Unit::TestCase
14
+ end
15
+
16
+ def random_string(legth = 5)
17
+ Array.new(legth) { rand(36).to_s(36) }.join
18
+ end
19
+
20
+ def random_phone
21
+ rand(10 ** 12).to_s
22
+ end
23
+
24
+ def random_hash
25
+ hash = {}
26
+ 3.times { hash[random_string] = random_string }
27
+ hash
28
+ end
29
+
30
+ def build_uri(command, username, password, options = {})
31
+ options.merge!(:cmd => command, :username => username, :password => password)
32
+ uri = "http://www.textmagic.com/app/api?"
33
+ uri << options.collect { |key, value| "#{key}=#{value}"}.join('&')
34
+ end
35
+
36
+ def load_response(filename)
37
+ File.read(File.join(File.dirname(__FILE__), 'fixtures', filename) + '.json')
38
+ end