Skip to content

Commit c8e3cd1

Browse files
committed
API v2
1 parent 9789e25 commit c8e3cd1

File tree

6 files changed

+349
-18
lines changed

6 files changed

+349
-18
lines changed

.rubocop.yml

+1-14
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,11 @@ AllCops:
55
- "vendor/**/*"
66

77
Metrics:
8-
Exclude:
9-
- "lib/bcdice_wrap.rb"
10-
- "lib/bcdice_api/app.rb"
11-
12-
Metrics/ClassLength:
13-
Exclude:
14-
- "test/**/*"
15-
16-
Metrics/AbcSize:
178
Exclude:
189
- "test/**/*"
1910
- "lib/bcdice_wrap.rb"
2011
- "lib/bcdice_api/app.rb"
21-
22-
Metrics/BlockLength:
23-
Exclude:
24-
- "test/**/*"
25-
- "lib/bcdice_api/app.rb"
12+
- "lib/bcdice_api/v2/app.rb"
2613

2714
Lint/RaiseException:
2815
Enabled: true

Rakefile

+8
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ Rake::TestTask.new do |t|
1212
t.verbose = true
1313
end
1414

15+
namespace :test do
16+
Rake::TestTask.new(:v2) do |t|
17+
t.libs += ['lib']
18+
t.test_files = ['test/test_api_v2.rb', 'test/test_dicebot_v2.rb']
19+
t.verbose = true
20+
end
21+
end
22+
1523
RuboCop::RakeTask.new
1624

1725
Rake::Task[:test].enhance do

lib/bcdice_api/app.rb

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
require 'sinatra/reloader' if development?
77
require 'exception'
88

9+
require_relative 'v2/app'
10+
911
module BCDiceAPI
1012
class App < Sinatra::Application
1113
class << self
@@ -20,6 +22,8 @@ class << self
2022
register Sinatra::Reloader
2123
end
2224

25+
use V2::App
26+
2327
helpers Sinatra::Jsonp
2428

2529
helpers do
@@ -48,10 +52,6 @@ def diceroll(system, command)
4852
end
4953
end
5054

51-
before do
52-
response.headers['Access-Control-Allow-Origin'] = '*'
53-
end
54-
5555
get '/' do
5656
'Hello. This is BCDice-API.'
5757
end

lib/bcdice_api/v2/app.rb

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# frozen_string_literal: true
2+
3+
require 'sinatra'
4+
require 'sinatra/base'
5+
require 'sinatra/jsonp'
6+
7+
require 'sinatra/reloader' if development?
8+
9+
require 'bcdice/user_defined_dice_table'
10+
11+
module BCDiceAPI
12+
module V2
13+
class App < Sinatra::Base
14+
class << self
15+
attr_accessor :test_rands
16+
end
17+
18+
before do
19+
response.headers['Access-Control-Allow-Origin'] = '*'
20+
end
21+
22+
helpers Sinatra::Jsonp
23+
24+
helpers do
25+
def roll(id, command)
26+
klass = BCDiceAPI::DICEBOTS[id]
27+
raise UnsupportedDicebot if klass.nil?
28+
raise CommandError if command.nil? || command.empty?
29+
30+
game_system = klass.new(command)
31+
game_system.randomizer = RandomizerMock.new(App.test_rands) if App.test_rands
32+
33+
result = game_system.eval
34+
raise CommandError if result.nil?
35+
36+
{
37+
ok: true,
38+
text: result.text,
39+
secret: result.secret?,
40+
success: result.success?,
41+
failure: result.failure?,
42+
critical: result.critical?,
43+
fumble: result.fumble?,
44+
rands: result.detailed_rands.map(&:to_h)
45+
}
46+
end
47+
end
48+
49+
get '/v2/version' do
50+
jsonp api: BCDiceAPI::VERSION, bcdice: BCDice::VERSION
51+
end
52+
53+
get '/v2/admin' do
54+
jsonp BCDiceAPI::ADMIN
55+
end
56+
57+
get '/v2/game_system' do
58+
game_system = BCDice.all_game_systems.sort_by { |game| game::SORT_KEY } .map do |game|
59+
{ id: game::ID, name: game::NAME, sort_key: game::SORT_KEY }
60+
end
61+
62+
jsonp game_system: game_system
63+
end
64+
65+
get '/v2/game_system/:id' do |id|
66+
game_system = BCDice.game_system_class(id)
67+
raise UnsupportedDicebot if game_system.nil?
68+
69+
ret = {
70+
ok: true,
71+
id: game_system::ID,
72+
name: game_system::NAME,
73+
sort_key: game_system::SORT_KEY,
74+
command_pattern: game_system.command_pattern.source,
75+
help_message: game_system::HELP_MESSAGE
76+
}
77+
78+
jsonp ret
79+
end
80+
81+
get '/v2/game_system/:id/roll' do |id|
82+
jsonp roll(id, params[:command])
83+
end
84+
85+
post '/v2/game_system/:id/roll' do |id|
86+
jsonp roll(id, params[:command])
87+
end
88+
89+
post '/v2/original_table' do
90+
table = BCDice::UserDefinedDiceTable.new(params[:table])
91+
92+
jsonp text: params[:table]
93+
94+
ret = {
95+
ok: true,
96+
text: table.roll,
97+
rands: table.randomizer.detailed_rand_results.map(&:to_h)
98+
}
99+
100+
jsonp ret
101+
end
102+
103+
error UnsupportedDicebot do
104+
status 400
105+
jsonp ok: false, reason: 'unsupported game system'
106+
end
107+
108+
error CommandError do
109+
status 400
110+
jsonp ok: false, reason: 'unsupported command'
111+
end
112+
end
113+
end
114+
end

test/test_api_v2.rb

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
# frozen_string_literal: true
2+
3+
ENV['RACK_ENV'] = 'test'
4+
require 'test/unit'
5+
require 'rack/test'
6+
7+
require 'cgi'
8+
9+
require 'bcdice_api'
10+
11+
class V2APITest < Test::Unit::TestCase
12+
include Rack::Test::Methods
13+
14+
def app
15+
BCDiceAPI::App
16+
end
17+
18+
def test_version
19+
get '/v2/version'
20+
json = JSON.parse(last_response.body)
21+
22+
assert last_response.ok?
23+
assert_equal '*', last_response.headers['Access-Control-Allow-Origin']
24+
assert json.key?('bcdice')
25+
assert json.key?('api')
26+
end
27+
28+
def test_game_system_list
29+
get '/v2/game_system'
30+
json = JSON.parse(last_response.body)
31+
32+
assert last_response.ok?
33+
assert_false json['game_system'].empty?
34+
assert_instance_of Array, json['game_system']
35+
36+
first = json['game_system'].first
37+
assert first.key?('name')
38+
assert first.key?('id')
39+
assert first.key?('sort_key')
40+
end
41+
42+
def test_game_system_info
43+
get '/v2/game_system/DiceBot'
44+
json = JSON.parse(last_response.body)
45+
46+
assert last_response.ok?
47+
assert json['ok']
48+
assert_equal json['id'], 'DiceBot'
49+
assert_instance_of String, json['name']
50+
assert_instance_of String, json['command_pattern']
51+
assert_instance_of String, json['sort_key']
52+
assert_instance_of String, json['help_message']
53+
assert_false json['name'].empty?
54+
assert_false json['command_pattern'].empty?
55+
assert_false json['sort_key'].empty?
56+
57+
pend 'DiceBot::HELP_MESSAGE will be supported in BCDice v3'
58+
assert_false json['help_message'].empty?
59+
end
60+
61+
def test_diceroll
62+
get '/v2/game_system/DiceBot/roll?command=1d100<=70'
63+
64+
json = JSON.parse(last_response.body)
65+
66+
assert last_response.ok?
67+
assert json['ok']
68+
assert json['text']
69+
assert_false json['secret']
70+
assert_boolean json['success']
71+
assert_boolean json['failure']
72+
assert_false json['critical']
73+
assert_false json['fumble']
74+
assert_instance_of Array, json['rands']
75+
end
76+
77+
def test_diceroll_with_post
78+
post '/v2/game_system/DiceBot/roll', { command: '1d100<=70' }
79+
80+
json = JSON.parse(last_response.body)
81+
82+
assert last_response.ok?
83+
assert json['ok']
84+
assert json['text']
85+
assert_false json['secret']
86+
assert_boolean json['success']
87+
assert_boolean json['failure']
88+
assert_false json['critical']
89+
assert_false json['fumble']
90+
assert_instance_of Array, json['rands']
91+
end
92+
93+
def test_detailed
94+
get '/v2/game_system/Cthulhu7th/roll?command=CC1'
95+
96+
json = JSON.parse(last_response.body)
97+
98+
assert last_response.ok?
99+
assert json['ok']
100+
assert_not_empty(json['rands'].select { |r| r['kind'] == 'tens_d10' })
101+
end
102+
103+
def test_unexpected_game_system
104+
get '/v2/game_system/Hoge/roll?command=1d100<=70'
105+
106+
json = JSON.parse(last_response.body)
107+
108+
assert last_response.bad_request?
109+
assert_false json['ok']
110+
assert_equal json['reason'], 'unsupported game system'
111+
end
112+
113+
def test_unexpected_command
114+
get '/v2/game_system/DiceBot/roll?command=a'
115+
116+
json = JSON.parse(last_response.body)
117+
118+
assert last_response.bad_request?
119+
assert_false json['ok']
120+
assert_equal json['reason'], 'unsupported command'
121+
end
122+
123+
def test_no_command
124+
get '/v2/game_system/DiceBot/roll'
125+
126+
json = JSON.parse(last_response.body)
127+
128+
assert last_response.bad_request?
129+
assert_false json['ok']
130+
assert_equal json['reason'], 'unsupported command'
131+
end
132+
133+
def test_blank_command
134+
get '/v2/game_system/DiceBot/roll?command='
135+
136+
json = JSON.parse(last_response.body)
137+
138+
assert last_response.bad_request?
139+
assert_false json['ok']
140+
assert_equal json['reason'], 'unsupported command'
141+
end
142+
143+
def test_original_table
144+
table_text = <<~TABLE
145+
飲み物表
146+
1D6
147+
1:水
148+
2:緑茶
149+
3:麦茶
150+
4:コーラ
151+
5:オレンジジュース
152+
6:選ばれし者の知的飲料
153+
TABLE
154+
155+
post '/v2/original_table', { table: table_text }
156+
157+
json = JSON.parse(last_response.body)
158+
159+
assert last_response.ok?
160+
assert_true json['ok']
161+
assert_instance_of String, json['text']
162+
assert_true json['text'].start_with?('飲み物表(')
163+
assert_instance_of Array, json['rands']
164+
end
165+
end

0 commit comments

Comments
 (0)