rack-ketai 0.1.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 (44) hide show
  1. data/.gitignore +1 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README.rdoc +122 -0
  4. data/VERSION +1 -0
  5. data/lib/rack/ketai/carrier/abstract.rb +263 -0
  6. data/lib/rack/ketai/carrier/au.rb +153 -0
  7. data/lib/rack/ketai/carrier/cidrs/au.rb +32 -0
  8. data/lib/rack/ketai/carrier/cidrs/docomo.rb +14 -0
  9. data/lib/rack/ketai/carrier/cidrs/softbank.rb +10 -0
  10. data/lib/rack/ketai/carrier/docomo.rb +157 -0
  11. data/lib/rack/ketai/carrier/emoji/ausjisstrtoemojiid.rb +1391 -0
  12. data/lib/rack/ketai/carrier/emoji/docomosjisstrtoemojiid.rb +759 -0
  13. data/lib/rack/ketai/carrier/emoji/emojidata.rb +836 -0
  14. data/lib/rack/ketai/carrier/emoji/emojiidtotypecast.rb +432 -0
  15. data/lib/rack/ketai/carrier/emoji/softbankutf8strtoemojiid.rb +1119 -0
  16. data/lib/rack/ketai/carrier/emoji/softbankwebcodetoutf8str.rb +499 -0
  17. data/lib/rack/ketai/carrier/general.rb +75 -0
  18. data/lib/rack/ketai/carrier/iphone.rb +16 -0
  19. data/lib/rack/ketai/carrier/softbank.rb +144 -0
  20. data/lib/rack/ketai/carrier/specs/au.rb +1 -0
  21. data/lib/rack/ketai/carrier/specs/docomo.rb +1 -0
  22. data/lib/rack/ketai/carrier/specs/softbank.rb +1 -0
  23. data/lib/rack/ketai/carrier.rb +18 -0
  24. data/lib/rack/ketai/display.rb +16 -0
  25. data/lib/rack/ketai/middleware.rb +36 -0
  26. data/lib/rack/ketai.rb +12 -0
  27. data/spec/spec_helper.rb +11 -0
  28. data/spec/unit/au_filter_spec.rb +96 -0
  29. data/spec/unit/au_spec.rb +240 -0
  30. data/spec/unit/carrier_spec.rb +30 -0
  31. data/spec/unit/display_spec.rb +25 -0
  32. data/spec/unit/docomo_filter_spec.rb +106 -0
  33. data/spec/unit/docomo_spec.rb +344 -0
  34. data/spec/unit/emoticon_filter_spec.rb +91 -0
  35. data/spec/unit/filter_spec.rb +38 -0
  36. data/spec/unit/iphone_spec.rb +16 -0
  37. data/spec/unit/middleware_spec.rb +38 -0
  38. data/spec/unit/softbank_filter_spec.rb +133 -0
  39. data/spec/unit/softbank_spec.rb +200 -0
  40. data/spec/unit/valid_addr_spec.rb +86 -0
  41. data/test/spec_runner.rb +29 -0
  42. data/tools/generate_emoji_dic.rb +434 -0
  43. data/tools/update_speclist.rb +87 -0
  44. metadata +138 -0
@@ -0,0 +1,344 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'rack/ketai/carrier/docomo'
3
+ describe "Rack::Ketai::Carrier::Docomo" do
4
+
5
+ # UAの意味
6
+ # http://www.nttdocomo.co.jp/service/imode/make/content/browser/html/useragent/
7
+
8
+ before(:each) do
9
+
10
+ end
11
+
12
+ describe "FOMA端末で" do
13
+
14
+ # http://www.nttdocomo.co.jp/service/imode/make/content/browser/html/tag/utn.html
15
+ # FOMA端末製造番号のみ、もしくはFOMAカード製造番号のみの送信はできません。
16
+
17
+ describe "iモードIDを取得できたとき" do
18
+ before(:each) do
19
+ @env = Rack::MockRequest.env_for('http://hoge.com/dummy?guid=ON',
20
+ 'HTTP_USER_AGENT' => 'DoCoMo/2.0 P903i(c10;serXXXXXXXXXXXXXXX; iccxxxxxxxxxxxxxxxxxxxx)',
21
+ 'HTTP_X_DCMGUID' => '0123abC')
22
+ @mobile = Rack::Ketai::Carrier::Docomo.new(@env)
23
+ end
24
+
25
+ it "#subscriberid でiモードIDを取得できること" do
26
+ @mobile.subscriberid.should == '0123abC'
27
+ end
28
+
29
+ it "#deviceid でFOMA端末個体識別子を取得できること" do
30
+ @mobile.deviceid.should == "XXXXXXXXXXXXXXX"
31
+ end
32
+
33
+ it "#ident でiモードIDを取得できること" do
34
+ @mobile.ident.should == @mobile.subscriberid
35
+ @mobile.ident.should == '0123abC'
36
+ end
37
+
38
+ end
39
+
40
+ describe "iモードIDが取得できず、FOMAカード個体識別子、FOMA端末個体識別子双方を取得できたとき" do
41
+
42
+ before(:each) do
43
+ @env = Rack::MockRequest.env_for('http://hoge.com/dummy',
44
+ 'HTTP_USER_AGENT' => 'DoCoMo/2.0 P903i(c10;serXXXXXXXXXXXXXXX; iccxxxxxxxxxxxxxxxxxxxx)')
45
+ @mobile = Rack::Ketai::Carrier::Docomo.new(@env)
46
+ end
47
+
48
+ it "#subscriberid でFOMAカード個体識別子を取得できること" do
49
+ @mobile.subscriberid.should == "xxxxxxxxxxxxxxxxxxxx"
50
+ end
51
+
52
+ it "#deviceid でFOMA端末個体識別子を取得できること" do
53
+ @mobile.deviceid.should == "XXXXXXXXXXXXXXX"
54
+ end
55
+
56
+ it "#ident でFOMAカード個体識別子を取得できること" do
57
+ @mobile.ident.should == @mobile.subscriberid
58
+ @mobile.ident.should == "xxxxxxxxxxxxxxxxxxxx"
59
+ end
60
+ end
61
+
62
+ describe "iモードID、FOMAカード個体識別子およびFOMA端末個体識別子が取得できないとき" do
63
+
64
+ before(:each) do
65
+ @env = Rack::MockRequest.env_for('http://hoge.com/dummy',
66
+ 'HTTP_USER_AGENT' => 'DoCoMo/2.0 SO903i')
67
+ @mobile = Rack::Ketai::Carrier::Docomo.new(@env)
68
+ end
69
+
70
+ it "#subscriberid は nil を返すこと" do
71
+ @mobile.subscriberid.should be_nil
72
+ end
73
+
74
+ it "#deviceid は nil を返すこと" do
75
+ @mobile.deviceid.should be_nil
76
+ end
77
+
78
+ it "#ident は nil を返すこと" do
79
+ @mobile.ident.should be_nil
80
+ end
81
+ end
82
+
83
+ describe "iモードIDが取得でき、FOMAカード個体識別子およびFOMA端末個体識別子が取得できないとき" do
84
+
85
+ before(:each) do
86
+ @env = Rack::MockRequest.env_for('http://hoge.com/dummy',
87
+ 'HTTP_USER_AGENT' => 'DoCoMo/2.0 SO903i',
88
+ 'HTTP_X_DCMGUID' => '0123abC')
89
+ @mobile = Rack::Ketai::Carrier::Docomo.new(@env)
90
+ end
91
+
92
+ it "#subscriberid はiモードIDを返すこと" do
93
+ @mobile.subscriberid.should == '0123abC'
94
+ end
95
+
96
+ it "#deviceid は nil を返すこと" do
97
+ @mobile.deviceid.should be_nil
98
+ end
99
+
100
+ it "#ident はiモードIDを返すこと" do
101
+ @mobile.ident.should == '0123abC'
102
+ end
103
+ end
104
+
105
+ it "#name で機種名を取得できること" do
106
+ env = Rack::MockRequest.env_for('http://hoge.com/dummy',
107
+ 'HTTP_USER_AGENT' => "DoCoMo/2.0 SH02A")
108
+ mobile = Rack::Ketai::Carrier::Docomo.new(env)
109
+ mobile.name.should == 'SH02A'
110
+ end
111
+
112
+ it "#cache_size でキャッシュサイズが取得できること" do
113
+ {
114
+ 'DoCoMo/2.0 P903i' => 5 * 1000,
115
+ 'DoCoMo/2.0 F900i(c100;TJ)' => 100 * 1000,
116
+ 'DoCoMo/2.0 F900i(c100;TC;W22H12)' => 100 * 1000,
117
+ 'DoCoMo/2.0 P903i(c100;serXXXXXXXXXXXXXXX; iccxxxxxxxxxxxxxxxxxxxx)' => 100 * 1000,
118
+ 'DoCoMo/2.0 N06A3(c500;TB;W24H16)' => 500 * 1000,
119
+ 'DoCoMo/2.0 XXXX(c500;TB;W24H16)' => 500 * 1000 # 未知の端末でも
120
+ }.each do |ua, cache_size|
121
+ env = Rack::MockRequest.env_for('http://hoge.com/dummy',
122
+ 'HTTP_USER_AGENT' => ua)
123
+ mobile = Rack::Ketai::Carrier::Docomo.new(env)
124
+ mobile.cache_size.should == cache_size
125
+ end
126
+ end
127
+
128
+ describe "ディスプレイ情報を取得できること" do
129
+
130
+ it "既知の端末のとき" do
131
+ @env = Rack::MockRequest.env_for('http://hoge.com/dummy',
132
+ 'HTTP_USER_AGENT' => "DoCoMo/2.0 SH02A(c100;TB;W30H20)")
133
+ @mobile = Rack::Ketai::Carrier::Docomo.new(@env)
134
+ display = @mobile.display
135
+ display.should_not be_nil
136
+ display.colors.should == 16777216
137
+ display.width.should == 240
138
+ display.height.should == 320
139
+ end
140
+
141
+ it "未知の端末のとき" do
142
+ @env = Rack::MockRequest.env_for('http://hoge.com/dummy',
143
+ 'HTTP_USER_AGENT' => 'DoCoMo/2.0 XX01(c100;TB;W30H20)')
144
+ @mobile = Rack::Ketai::Carrier::Docomo.new(@env)
145
+ display = @mobile.display
146
+ display.should_not be_nil
147
+ display.colors.should be_nil
148
+ display.width.should be_nil
149
+ display.height.should be_nil
150
+ end
151
+
152
+ end
153
+
154
+ end
155
+
156
+ describe "mova端末で" do
157
+
158
+ # http://www.nttdocomo.co.jp/service/imode/make/content/browser/html/tag/utn.html
159
+
160
+ describe "iモードIDと端末個体識別子を取得できたとき" do
161
+ before(:each) do
162
+ @env = Rack::MockRequest.env_for('http://hoge.com/dummy?guid=ON',
163
+ 'HTTP_USER_AGENT' => 'DoCoMo/1.0/SO503i/c10/TB/serXXXXXXXXXXX',
164
+ 'HTTP_X_DCMGUID' => '0123abC')
165
+ @mobile = Rack::Ketai::Carrier::Docomo.new(@env)
166
+ end
167
+
168
+ it "#subscriberid でiモードIDを取得できること" do
169
+ @mobile.subscriberid.should == '0123abC'
170
+ end
171
+
172
+ it "#deviceid で端末個体識別子を取得できること" do
173
+ @mobile.deviceid.should == "XXXXXXXXXXX"
174
+ end
175
+
176
+ it "#ident でiモードIDを取得できること" do
177
+ @mobile.ident.should == '0123abC'
178
+ end
179
+
180
+ end
181
+
182
+ describe "端末個体識別子のみ取得できたとき" do
183
+
184
+ before(:each) do
185
+ @env = Rack::MockRequest.env_for('http://hoge.com/dummy',
186
+ 'HTTP_USER_AGENT' => 'DoCoMo/1.0/SO503i/c10/TB/serXXXXXXXXXXX')
187
+ @mobile = Rack::Ketai::Carrier::Docomo.new(@env)
188
+ end
189
+
190
+ it "#subscriberid は nil を返すこと" do
191
+ @mobile.subscriberid.should be_nil
192
+ end
193
+
194
+ it "#deviceid で端末個体識別子を取得できること" do
195
+ @mobile.deviceid.should == "XXXXXXXXXXX"
196
+ end
197
+
198
+ it "#ident で端末個体識別子を取得できること" do
199
+ @mobile.ident.should == @mobile.deviceid
200
+ @mobile.ident.should == "XXXXXXXXXXX"
201
+ end
202
+ end
203
+
204
+ describe "iモードIDも端末個体識別子も取得できないとき" do
205
+
206
+ before(:each) do
207
+ @env = Rack::MockRequest.env_for('http://hoge.com/dummy',
208
+ 'HTTP_USER_AGENT' => 'DoCoMo/1.0/N505i/c20/TB/W24H12')
209
+ @mobile = Rack::Ketai::Carrier::Docomo.new(@env)
210
+ end
211
+
212
+ it "#subscriberid は nil を返すこと" do
213
+ @mobile.subscriberid.should be_nil
214
+ end
215
+
216
+ it "#deviceid は nil を返すこと" do
217
+ @mobile.deviceid.should be_nil
218
+ end
219
+
220
+ it "#ident は nil を返すこと" do
221
+ @mobile.ident.should be_nil
222
+ end
223
+ end
224
+
225
+ describe "iモードIDのみ取得できたとき" do
226
+
227
+ before(:each) do
228
+ @env = Rack::MockRequest.env_for('http://hoge.com/dummy',
229
+ 'HTTP_USER_AGENT' => 'DoCoMo/1.0/N505i/c20/TB/W24H12',
230
+ 'HTTP_X_DCMGUID' => '0123abC')
231
+ @mobile = Rack::Ketai::Carrier::Docomo.new(@env)
232
+ end
233
+
234
+ it "#subscriberid はiモードIDを返すこと" do
235
+ @mobile.subscriberid.should == '0123abC'
236
+ end
237
+
238
+ it "#deviceid は nil を返すこと" do
239
+ @mobile.deviceid.should be_nil
240
+ end
241
+
242
+ it "#ident はiモードIDを返すこと" do
243
+ @mobile.ident.should == '0123abC'
244
+ end
245
+ end
246
+
247
+ it "#name で機種名を取得できること" do
248
+ env = Rack::MockRequest.env_for('http://hoge.com/dummy',
249
+ 'HTTP_USER_AGENT' => "DoCoMo/1.0/SO502i")
250
+ mobile = Rack::Ketai::Carrier::Docomo.new(env)
251
+ mobile.name.should == 'SO502i'
252
+ end
253
+
254
+ it "#cache_size でキャッシュサイズが取得できること" do
255
+ {
256
+ 'DoCoMo/1.0/F502i' => 5 * 1000,
257
+ 'DoCoMo/1.0/D503i/c10' => 10 * 1000,
258
+ 'DoCoMo/1.0/N504i/c10/TB' => 10 * 1000,
259
+ 'DoCoMo/1.0/SO506iS/c20/TB/W20H10' => 20 * 1000,
260
+ }.each do |ua, cache_size|
261
+ env = Rack::MockRequest.env_for('http://hoge.com/dummy',
262
+ 'HTTP_USER_AGENT' => ua)
263
+ mobile = Rack::Ketai::Carrier::Docomo.new(env)
264
+ mobile.cache_size.should == cache_size
265
+ end
266
+ end
267
+
268
+ describe "ディスプレイ情報を取得できること" do
269
+
270
+ it "既知の端末のとき" do
271
+ @env = Rack::MockRequest.env_for('http://hoge.com/dummy',
272
+ 'HTTP_USER_AGENT' => "DoCoMo/1.0/SO502i")
273
+ @mobile = Rack::Ketai::Carrier::Docomo.new(@env)
274
+ display = @mobile.display
275
+ display.should_not be_nil
276
+ display.colors.should == 4
277
+ display.width.should == 120
278
+ display.height.should == 120
279
+ end
280
+
281
+ it "未知の端末のとき" do
282
+ @env = Rack::MockRequest.env_for('http://hoge.com/dummy',
283
+ 'HTTP_USER_AGENT' => 'DoCoMo/1.0/X000i')
284
+ @mobile = Rack::Ketai::Carrier::Docomo.new(@env)
285
+ display = @mobile.display
286
+ display.should_not be_nil
287
+ display.colors.should be_nil
288
+ display.width.should be_nil
289
+ display.height.should be_nil
290
+ end
291
+
292
+ end
293
+
294
+ end
295
+
296
+ describe "#supports_cookie? を使うとき" do
297
+
298
+ # iモードブラウザ 2.0から対応
299
+ # といっても、iモードブラウザ 2.0かどうか判断するには
300
+ # キャッシュサイズで調べるしかない(c500)
301
+ # キャッシュが不明な場合は端末データベースから判断
302
+ # (ただし信頼性が低いので最後の手段)
303
+
304
+ it "Cookie対応機種なら true を返すこと" do
305
+ env = Rack::MockRequest.env_for('http://hoge.com/dummy',
306
+ 'HTTP_USER_AGENT' => 'DoCoMo/2.0 F02B')
307
+ mobile = Rack::Ketai::Carrier::Docomo.new(env)
308
+ mobile.should be_respond_to(:supports_cookie?)
309
+ mobile.should be_supports_cookie
310
+ end
311
+
312
+ it "Cookie未対応機種なら false を返すこと" do
313
+ env = Rack::MockRequest.env_for('http://hoge.com/dummy',
314
+ 'HTTP_USER_AGENT' => 'DoCoMo/2.0 L06A')
315
+ mobile = Rack::Ketai::Carrier::Docomo.new(env)
316
+ mobile.should be_respond_to(:supports_cookie?)
317
+ mobile.should_not be_supports_cookie
318
+ end
319
+
320
+ it "不明な機種でもキャッシュサイズがわかればそれを基に判断すること" do
321
+ env = Rack::MockRequest.env_for('http://hoge.com/dummy',
322
+ 'HTTP_USER_AGENT' => 'DoCoMo/2.0 X00HOGE3(c500;TB;W24H15)')
323
+ mobile = Rack::Ketai::Carrier::Docomo.new(env)
324
+ mobile.should be_respond_to(:supports_cookie?)
325
+ mobile.should be_supports_cookie
326
+
327
+ env = Rack::MockRequest.env_for('http://hoge.com/dummy',
328
+ 'HTTP_USER_AGENT' => 'DoCoMo/2.0 X00HOGE3(c100;TB;W24H15)')
329
+ mobile = Rack::Ketai::Carrier::Docomo.new(env)
330
+ mobile.should be_respond_to(:supports_cookie?)
331
+ mobile.should_not be_supports_cookie
332
+ end
333
+
334
+ it "不明な機種でキャッシュサイズもわからないなら false を返すこと" do
335
+ env = Rack::MockRequest.env_for('http://hoge.com/dummy',
336
+ 'HTTP_USER_AGENT' => 'DoCoMo/2.0 X00HOGE')
337
+ mobile = Rack::Ketai::Carrier::Docomo.new(env)
338
+ mobile.should be_respond_to(:supports_cookie?)
339
+ mobile.should_not be_supports_cookie
340
+ end
341
+
342
+ end
343
+
344
+ end
@@ -0,0 +1,91 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'kconv'
3
+ require 'rack/ketai/carrier/general'
4
+
5
+ describe Rack::Ketai::Carrier::General::EmoticonFilter, "外部フィルタを適用する時" do
6
+
7
+ before(:each) do
8
+ @filter = Rack::Ketai::Carrier::General::EmoticonFilter.new(:emoticons_path => '/images/emoticons')
9
+ end
10
+
11
+ it "emoticons_path が与えられないときはなにもしないこと" do
12
+ filter = Rack::Ketai::Carrier::General::EmoticonFilter.new
13
+ Rack::Ketai::Carrier::General::EmoticonFilter::EMOJIID_TO_TYPECAST_EMOTICONS.each do |emojiid, filenames|
14
+ str = '今日はいい[e:'+format("%03X", emojiid)+']ですね。'
15
+ resdata = str
16
+
17
+ status, headers, body = filter.outbound(200, { "Content-Type" => "text/html"}, [str])
18
+
19
+ body[0].should == resdata
20
+ end
21
+ filter = Rack::Ketai::Carrier::General::EmoticonFilter.new(:emoticons_path => '')
22
+ Rack::Ketai::Carrier::General::EmoticonFilter::EMOJIID_TO_TYPECAST_EMOTICONS.each do |emojiid, filenames|
23
+ str = '今日はいい[e:'+format("%03X", emojiid)+']ですね。'
24
+ resdata = str
25
+
26
+ status, headers, body = filter.outbound(200, { "Content-Type" => "text/html"}, [str])
27
+
28
+ body[0].should == resdata
29
+ end
30
+ end
31
+
32
+ it "データ中の絵文字IDをimgタグに変換すること" do
33
+ Rack::Ketai::Carrier::General::EmoticonFilter::EMOJIID_TO_TYPECAST_EMOTICONS.each do |emojiid, filenames|
34
+ tag = filenames.collect{ |filename| "<img src=\"/images/emoticons/#{filename}.gif\" />" }.join('')
35
+ resdata = "今日はいい#{tag}ですね。"
36
+
37
+ status, headers, body = @filter.outbound(200, { "Content-Type" => "text/html"}, ['今日はいい[e:'+format("%03X", emojiid)+']ですね。'])
38
+
39
+ body[0].should == resdata
40
+ end
41
+ end
42
+
43
+ it "データ中に絵文字ID=絵文字IDだが絵文字≠絵文字IDのIDが含まれているとき、正しく逆変換できること" do
44
+ resdata = "たとえば<img src=\"/images/emoticons/happy01.gif\" />「e-330 HAPPY FACE WITH OPEN MOUTH」とか。"
45
+
46
+ status, headers, body = @filter.outbound(200, { "Content-Type" => "text/html"}, ["たとえば[e:330]「e-330 HAPPY FACE WITH OPEN MOUTH」とか。"])
47
+
48
+ body[0].should == resdata
49
+ end
50
+
51
+ it "データ中にTypepad絵文字にはない絵文字IDが存在するとき、代替文字を表示すること" do
52
+ resdata = "黒い矢印[#{[0x2190].pack('U')}]です" # 左黒矢印
53
+
54
+ status, headers, body = @filter.outbound(200, { "Content-Type" => "text/html"}, ['黒い矢印[e:AFB]です'])
55
+
56
+ body[0].should == resdata
57
+ end
58
+
59
+ it "Content-typeがhtmlでないときには変換しないこと(未設定の場合除く)" do
60
+ emojiid = 0x00F
61
+ filenames = ["sun","cloud"]
62
+ str = '今日はいい[e:'+format("%03X", emojiid)+']ですね。'
63
+ tag = filenames.collect{ |filename| "<img src=\"/images/emoticons/#{filename}.gif\" />" }.join('')
64
+
65
+ %w(text/plain text/xml text/json application/json text/javascript application/rss+xml image/jpeg).each do |contenttype|
66
+ resdata = str
67
+
68
+ status, headers, body = @filter.outbound(200, { "Content-Type" => contenttype}, ['今日はいい[e:'+format("%03X", emojiid)+']ですね。'])
69
+
70
+ body[0].should == resdata
71
+ end
72
+
73
+ %w(text/html application/xhtml+xml).each do |contenttype|
74
+ resdata = '今日はいい'+tag+'ですね。'
75
+
76
+ status, headers, body = @filter.outbound(200, { "Content-Type" => contenttype}, ['今日はいい[e:'+format("%03X", emojiid)+']ですね。'])
77
+
78
+ body[0].should == resdata
79
+ end
80
+
81
+ resdata = '今日はいい'+tag+'ですね。'
82
+ status, headers, body = @filter.outbound(200, { "Content-Type" => ''}, ['今日はいい[e:'+format("%03X", emojiid)+']ですね。'])
83
+ body[0].should == resdata
84
+
85
+ resdata = '今日はいい'+tag+'ですね。'
86
+ status, headers, body = @filter.outbound(200, {}, ['今日はいい[e:'+format("%03X", emojiid)+']ですね。'])
87
+ body[0].should == resdata
88
+
89
+ end
90
+
91
+ end
@@ -0,0 +1,38 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'rack/ketai/carrier/general'
3
+ describe Rack::Ketai::Carrier::General do
4
+
5
+ before(:each) do
6
+ @env = Rack::MockRequest.env_for('http://hoge.com/dummy')
7
+ @carrier = Rack::Ketai::Carrier::General.new(@env)
8
+ end
9
+
10
+ it ":disable_filter オプションを指定しないか false を渡すとフィルタが実行されること" do
11
+ options = { }
12
+ response = [200, { }, ['']]
13
+ mock_filter = mock(Rack::Ketai::Carrier::General::EmoticonFilter)
14
+ mock_filter.should_receive(:inbound).once.with(@env).and_return(@env)
15
+ mock_filter.should_receive(:outbound).once.with(*response).and_return(response)
16
+ Rack::Ketai::Carrier::General::EmoticonFilter.should_receive(:new).at_least(1).with(options).and_return(mock_filter)
17
+ @carrier.filtering(@env, options){ |env| response }
18
+
19
+ options = { :disable_filter => false }
20
+ response = [200, { }, ['']]
21
+ mock_filter = mock(Rack::Ketai::Carrier::General::EmoticonFilter)
22
+ mock_filter.should_receive(:inbound).once.with(@env).and_return(@env)
23
+ mock_filter.should_receive(:outbound).once.with(*response).and_return(response)
24
+ Rack::Ketai::Carrier::General::EmoticonFilter.should_receive(:new).at_least(1).with(options).and_return(mock_filter)
25
+ @carrier.filtering(@env, options){ |env| response }.should == response
26
+ end
27
+
28
+ it ":disable_filter オプションに true を渡すと、フィルタが実行されないこと" do
29
+ options = { :disable_filter => true }
30
+ response = [200, { }, ['']]
31
+ mock_filter = mock(Rack::Ketai::Carrier::General::EmoticonFilter)
32
+ mock_filter.should_receive(:inbound).exactly(0)
33
+ mock_filter.should_receive(:outbound).exactly(0)
34
+ Rack::Ketai::Carrier::General::EmoticonFilter.should_receive(:new).any_number_of_times.with(options).and_return(mock_filter)
35
+ @carrier.filtering(@env, options){ |env| response }.should == response
36
+ end
37
+
38
+ end
@@ -0,0 +1,16 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'rack/ketai/carrier/iphone'
3
+ describe "Rack::Ketai::Carrier::IPhone" do
4
+
5
+ describe "#supports_cookie? を使うとき" do
6
+ # iPhone はCookie対応
7
+ it "#supports_cookie? は true を返す" do
8
+ env = Rack::MockRequest.env_for('http://hoge.com/dummy',
9
+ 'HTTP_USER_AGENT' => 'Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; ja-jp) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7')
10
+ mobile = Rack::Ketai::Carrier::IPhone.new(env)
11
+ mobile.should be_respond_to(:supports_cookie?)
12
+ mobile.should be_supports_cookie
13
+ end
14
+ end
15
+
16
+ end
@@ -0,0 +1,38 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ describe Rack::Ketai::Middleware, "#call を実行するとき" do
4
+
5
+ it "適切な env['rack.ketai'] を設定できること" do
6
+ {
7
+ 'DoCoMo/1.0/N505i' => Rack::Ketai::Carrier::Docomo, # Mova
8
+ 'DoCoMo/2.0 P903i' => Rack::Ketai::Carrier::Docomo, # FOMA
9
+ 'KDDI-CA39 UP.Browser/6.2.0.13.1.5 (GUI) MMP/2.0' => Rack::Ketai::Carrier::Au, # WAP2.0 MMP2.0
10
+ 'KDDI-TS21 UP.Browser/6.0.2.273 (GUI) MMP/1.1' => Rack::Ketai::Carrier::Au, # WAP2.0 MMP1.1
11
+ 'SoftBank/1.0/930SH/SHJ001[/Serial] Browser/NetFront/3.4 Profile/MIDP-2.0 Configuration/CLDC-1.1' => Rack::Ketai::Carrier::Softbank, # SoftBank 3GC
12
+ 'Mozilla/5.0 (iPhone; U; CPU iPhone OS 2_0_1 like Mac OS X; ja-jp) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5B108 Safari/525.20' => Rack::Ketai::Carrier::IPhone,
13
+ 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.50727)' => nil, # IE8
14
+ 'Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1' => nil,
15
+ 'Opera/9.21 (Windows NT 5.1; U; ja)' => nil,
16
+ 'Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP) AppleWebKit/525.19 (KHTML, like Gecko) Version/3.1.2 Safari/525.21' => nil,
17
+ 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.29 Safari/525.13' => nil,
18
+ }.each do |ua, carrier|
19
+ mock_env = Rack::MockRequest.env_for('http://hoge.com/dummy','HTTP_USER_AGENT' => ua)
20
+
21
+ mock_app = mock('App')
22
+ mock_app.should_receive(:call) do |env|
23
+ if carrier
24
+ env['rack.ketai'].should_not be_nil
25
+ env['rack.ketai'].mobile?.should be_true
26
+ else
27
+ env['rack.ketai'].should be_nil
28
+ env['rack.ketai'].mobile?.should be_false
29
+ end
30
+ [200, { "Content-Type" => "text/plain"}, ["OK"]]
31
+ end
32
+
33
+ middleware = Rack::Ketai::Middleware.new(mock_app, { })
34
+ middleware.call(mock_env)
35
+ end
36
+ end
37
+
38
+ end
@@ -0,0 +1,133 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'kconv'
3
+ require 'rack/ketai/carrier/softbank'
4
+ describe Rack::Ketai::Carrier::Softbank::Filter, "内部フィルタを適用する時" do
5
+
6
+ before(:each) do
7
+ @filter = Rack::Ketai::Carrier::Softbank::Filter.new
8
+ end
9
+
10
+ it "POSTデータ中のUTF-8バイナリの絵文字を絵文字IDに変換すること" do
11
+ Rack::Ketai::Carrier::Softbank::Filter::EMOJI_TO_EMOJIID.should_not be_empty
12
+ Rack::Ketai::Carrier::Softbank::Filter::EMOJI_TO_EMOJIID.each do |emoji, emojiid|
13
+ postdata = CGI.escape("message=今日はいい" + emoji + "ですね。")
14
+ postdata.force_encoding('UTF-8') if postdata.respond_to?(:force_encoding)
15
+
16
+ env = Rack::MockRequest.env_for('http://hoge.com/dummy',
17
+ 'HTTP_USER_AGENT' => 'Softbank/2.0 P903i',
18
+ :method => 'POST',
19
+ :input => postdata)
20
+ env = @filter.inbound(env)
21
+ request = Rack::Request.new(env)
22
+ request.params['message'].should == '今日はいい[e:'+format("%03X", emojiid)+']ですね。'
23
+ end
24
+ end
25
+
26
+ it "POSTデータ中のウェブコードの絵文字を絵文字IDに変換すること" do
27
+ Rack::Ketai::Carrier::Softbank::Filter::WEBCODE_TO_EMOJI.should_not be_empty
28
+ Rack::Ketai::Carrier::Softbank::Filter::EMOJI_TO_EMOJIID.should_not be_empty
29
+ Rack::Ketai::Carrier::Softbank::Filter::WEBCODE_TO_EMOJI.each do |webcode, emoji|
30
+ emojiid = Rack::Ketai::Carrier::Softbank::Filter::EMOJI_TO_EMOJIID[emoji]
31
+ postdata = CGI.escape("message=今日はいい\x1B$" + webcode + "\x0Fですね。")
32
+ postdata.force_encoding('UTF-8') if postdata.respond_to?(:force_encoding)
33
+
34
+ env = Rack::MockRequest.env_for('http://hoge.com/dummy',
35
+ 'HTTP_USER_AGENT' => 'Softbank/2.0 P903i',
36
+ :method => 'POST',
37
+ :input => postdata)
38
+ env = @filter.inbound(env)
39
+ request = Rack::Request.new(env)
40
+ request.params['message'].should == '今日はいい[e:'+format("%03X", emojiid)+']ですね。'
41
+ end
42
+ end
43
+
44
+ it "POSTデータ中の連続するウェブコードの絵文字を絵文字IDに変換すること" do
45
+ postdata = CGI.escape("message=今日の天気は\x1B$Gji\x0Fです\x1B$ON\x0F")
46
+ postdata.force_encoding('UTF-8') if postdata.respond_to?(:force_encoding)
47
+
48
+ env = Rack::MockRequest.env_for('http://hoge.com/dummy',
49
+ 'HTTP_USER_AGENT' => 'Softbank/2.0 P903i',
50
+ :method => 'POST',
51
+ :input => postdata)
52
+ env = @filter.inbound(env)
53
+ request = Rack::Request.new(env)
54
+ request.params['message'].should == '今日の天気は[e:00F]です[e:B60]'
55
+ end
56
+
57
+ end
58
+
59
+ describe Rack::Ketai::Carrier::Softbank::Filter, "外部フィルタを適用する時" do
60
+
61
+ before(:each) do
62
+ @filter = Rack::Ketai::Carrier::Softbank::Filter.new
63
+ end
64
+
65
+ it "データ中の絵文字IDをウェブコードに変換すること" do
66
+ Rack::Ketai::Carrier::Softbank::Filter::WEBCODE_TO_EMOJI.should_not be_empty
67
+ Rack::Ketai::Carrier::Softbank::Filter::EMOJI_TO_EMOJIID.should_not be_empty
68
+ Rack::Ketai::Carrier::Softbank::Filter::WEBCODE_TO_EMOJI.each do |webcode, emoji|
69
+ emojiid = Rack::Ketai::Carrier::Softbank::Filter::EMOJI_TO_EMOJIID[emoji]
70
+ resdata = "今日はいい\x1B$#{webcode}\x0Fですね。"
71
+
72
+ status, headers, body = @filter.outbound(200, { "Content-Type" => "text/html"}, ['今日はいい[e:'+format("%03X", emojiid)+']ですね。'])
73
+
74
+ body[0].should == resdata
75
+ end
76
+
77
+ resdata = "今日の天気は\x1B$Gj\x0F\x1B$Gi\x0Fです\x1B$ON\x0F"
78
+ status, headers, body = @filter.outbound(200, { "Content-Type" => "text/html"}, ['今日の天気は[e:00F]です[e:B60]'])
79
+ body[0].should == resdata
80
+ end
81
+
82
+ it "Content-typeが指定なし,text/html, application/xhtml+xml 以外の時はフィルタを適用しないこと" do
83
+ Rack::Ketai::Carrier::Softbank::Filter::WEBCODE_TO_EMOJI.should_not be_empty
84
+ Rack::Ketai::Carrier::Softbank::Filter::EMOJI_TO_EMOJIID.should_not be_empty
85
+ Rack::Ketai::Carrier::Softbank::Filter::WEBCODE_TO_EMOJI.each do |webcode, emoji|
86
+ emojiid = Rack::Ketai::Carrier::Softbank::Filter::EMOJI_TO_EMOJIID[emoji]
87
+ internaldata = '今日はいい[e:'+format("%03X", emojiid)+']ですね。'
88
+ %w(text/plain text/xml text/json application/json text/javascript application/rss+xml image/jpeg).each do |contenttype|
89
+ status, headers, body = @filter.outbound(200, { "Content-Type" => contenttype }, [internaldata])
90
+ body[0].should == internaldata
91
+ end
92
+ end
93
+ end
94
+
95
+ it "データ中に絵文字ID=絵文字IDだが絵文字≠絵文字IDのIDが含まれているとき、正しく逆変換できること" do
96
+ emoji = [0xF649].pack('n')
97
+ resdata = "たとえば\x1B$P*\x0F「e-33E RELIEVED FACE」とか。"
98
+
99
+ status, headers, body = @filter.outbound(200, { "Content-Type" => "text/html"}, ["たとえば[e:33E]「e-33E RELIEVED FACE」とか。"])
100
+
101
+ body[0].should == resdata
102
+ end
103
+
104
+ it "データ中にSoftBankにはない絵文字IDが存在するとき、代替文字を表示すること" do
105
+ resdata = "Soon[SOON]です" # soon
106
+
107
+ status, headers, body = @filter.outbound(200, { "Content-Type" => "text/html"}, ['Soon[e:018]です'])
108
+
109
+ body[0].should == resdata
110
+ end
111
+
112
+ it "Content-typeを適切に書き換えられること" do
113
+ [
114
+ [nil, nil],
115
+ ['text/html', 'text/html; charset=utf-8'],
116
+ ['text/html; charset=utf-8', 'text/html; charset=utf-8'],
117
+ ['text/html;charset=utf-8', 'text/html;charset=utf-8'],
118
+ ['application/xhtml+xml', 'application/xhtml+xml; charset=utf-8'],
119
+ ['application/xhtml+xml; charset=utf-8', 'application/xhtml+xml; charset=utf-8'],
120
+ ['application/xhtml+xml;charset=utf-8', 'application/xhtml+xml;charset=utf-8'],
121
+ ['text/javascript', 'text/javascript'],
122
+ ['text/json', 'text/json'],
123
+ ['application/json', 'application/json'],
124
+ ['text/javascript+json', 'text/javascript+json'],
125
+ ['image/jpeg', 'image/jpeg'],
126
+ ['application/octet-stream', 'application/octet-stream'],
127
+ ].each do |content_type, valid_content_type|
128
+ status, headers, body = @filter.outbound(200, { "Content-Type" => content_type}, ['適当な本文'])
129
+ headers['Content-Type'].should == valid_content_type
130
+ end
131
+ end
132
+
133
+ end