Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add rspec rubocop #290

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require:
- rubocop-performance
- rubocop-rake
- rubocop-rspec

inherit_mode:
merge:
Expand Down Expand Up @@ -67,6 +68,24 @@ Style/SingleLineBlockParams:
- reduce: [m, e]
- inject: [m, e]


## RSpec Cops

# TODO: Requires refactoring
RSpec/ExampleLength:
Enabled: false
# Controversial cop, but 15 memoized helpers is a lot and can be a sign of a test that's doing too much
RSpec/MultipleMemoizedHelpers:
Max: 15
# Don't enforce a discordrb namespace for spec files
RSpec/SpecFilePathFormat:
CustomTransform:
Discordrb: ''
# Stubbing subjects is required for testing methods that call the another method on the same object - essential for unit tests
# We should enable this cop for integration tests if we split them out
RSpec/SubjectStub:
Enabled: false

###################################
## NEW COPS TO MAKE DECISIONS ON ##
###################################
Expand Down
1 change: 1 addition & 0 deletions discordrb.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Gem::Specification.new do |spec|
spec.add_development_dependency 'rubocop', '~> 1.0'
spec.add_development_dependency 'rubocop-performance', '~> 1.0'
spec.add_development_dependency 'rubocop-rake', '~> 0.6'
spec.add_development_dependency 'rubocop-rspec', '~> 3.0'
spec.add_development_dependency 'simplecov', '~> 0.21'
spec.add_development_dependency 'yard', '~> 0.9'
end
6 changes: 6 additions & 0 deletions lib/discordrb/events/guilds.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ def matches?(event)
end
].reduce(true, &:&)
end

alias_method :matching?, :matches?
end

# Server is created
Expand Down Expand Up @@ -159,6 +161,8 @@ def matches?(event)
matches_all(@attributes[:name], event.emoji.name) { |a, e| a == e }
].reduce(true, &:&)
end

alias_method :matching?, :matches?
end

# Event handler for {ServerEmojiCreateEvent}
Expand Down Expand Up @@ -189,5 +193,7 @@ def matches?(event)
matches_all(@attributes[:name], event.emoji.name) { |a, e| a == e }
].reduce(true, &:&)
end

alias_method :matching?, :matches?
end
end
2 changes: 2 additions & 0 deletions lib/discordrb/events/message.rb
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,8 @@ def matches?(event)
].reduce(true, &:&)
end

alias_method :matching?, :matches?

# @see EventHandler#after_call
def after_call(event)
if event.file.nil?
Expand Down
40 changes: 16 additions & 24 deletions spec/api/channel_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,76 +3,68 @@
require 'discordrb'

describe Discordrb::API::Channel do
let(:token) { double('token', to_s: 'bot_token') }
let(:token) { instance_double(String, 'token', to_s: 'bot_token') }
let(:channel_id) { instance_double(String, 'channel_id', to_s: 'channel_id') }
let(:message_id) { instance_double(String, 'message_id', to_s: 'message_id') }

describe '.get_reactions' do
let(:message_id) { double('message_id', to_s: 'message_id') }
let(:before_id) { double('before_id', to_s: 'before_id') }
let(:after_id) { double('after_id', to_s: 'after_id') }
before do
allow(Discordrb::API).to receive(:request).with(anything, channel_id, instance_of(Symbol), any_args)
end

before do
allow(Discordrb::API).to receive(:request)
.with(anything, channel_id, :get, kind_of(String), any_args)
end
describe '.get_reactions' do
let(:before_id) { instance_double(String, 'before_id', to_s: 'before_id') }
let(:after_id) { instance_double(String, 'after_id', to_s: 'after_id') }

it 'sends requests' do
expect(Discordrb::API).to receive(:request)
described_class.get_reactions(token, channel_id, message_id, 'test', before_id, after_id, 27)
expect(Discordrb::API).to have_received(:request)
.with(
anything,
channel_id,
:get,
"#{Discordrb::API.api_base}/channels/#{channel_id}/messages/#{message_id}/reactions/test?limit=27&before=#{before_id}&after=#{after_id}",
any_args
)
Discordrb::API::Channel.get_reactions(token, channel_id, message_id, 'test', before_id, after_id, 27)
end

it 'percent-encodes emoji' do
expect(Discordrb::API).to receive(:request)
described_class.get_reactions(token, channel_id, message_id, "\u{1F44D}", before_id, after_id, 27)
expect(Discordrb::API).to have_received(:request)
.with(
anything,
channel_id,
:get,
"#{Discordrb::API.api_base}/channels/#{channel_id}/messages/#{message_id}/reactions/%F0%9F%91%8D?limit=27&before=#{before_id}&after=#{after_id}",
any_args
)
Discordrb::API::Channel.get_reactions(token, channel_id, message_id, "\u{1F44D}", before_id, after_id, 27)
end

it 'uses the maximum limit of 100 if nil is provided' do
expect(Discordrb::API).to receive(:request)
described_class.get_reactions(token, channel_id, message_id, 'test', before_id, after_id, nil)
expect(Discordrb::API).to have_received(:request)
.with(
anything,
channel_id,
:get,
"#{Discordrb::API.api_base}/channels/#{channel_id}/messages/#{message_id}/reactions/test?limit=100&before=#{before_id}&after=#{after_id}",
any_args
)
Discordrb::API::Channel.get_reactions(token, channel_id, message_id, 'test', before_id, after_id, nil)
end
end

describe '.delete_all_emoji_reactions' do
let(:message_id) { double('message_id', to_s: 'message_id') }
let(:emoji) { "\u{1F525}" }

before do
allow(Discordrb::API).to receive(:request)
.with(anything, channel_id, :delete, kind_of(String), any_args)
end

it 'sends requests' do
expect(Discordrb::API).to receive(:request)
described_class.delete_all_emoji_reactions(token, channel_id, message_id, emoji)
expect(Discordrb::API).to have_received(:request)
.with(
anything,
channel_id,
:delete,
"#{Discordrb::API.api_base}/channels/#{channel_id}/messages/#{message_id}/reactions/#{URI.encode_www_form_component(emoji)}",
any_args
)

Discordrb::API::Channel.delete_all_emoji_reactions(token, channel_id, message_id, emoji)
end
end
end
3 changes: 3 additions & 0 deletions spec/api_mock_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
expect(Discordrb::API.last_body).to be_nil
end

# TODO: Rework tests to not rely on multiple expectations
# rubocop:disable RSpec/MultipleExpectations
it 'parses headers if there is no body' do
Discordrb::API.raw_request(:post, ['https://example.com/test', nil, { a: 1, b: 2 }])

Expand All @@ -45,4 +47,5 @@
expect(Discordrb::API.last_headers[:a]).to eq 1
expect(Discordrb::API.last_headers[:b]).to eq 2
end
# rubocop:enable RSpec/MultipleExpectations
end
73 changes: 42 additions & 31 deletions spec/bot_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,47 +32,56 @@
bot.instance_variable_set(:@servers, server_id => server)
end

it 'should set up' do
expect(bot.server(server_id)).to eq(server)
expect(bot.server(server_id).emoji.size).to eq(2)
describe '#initialize' do
it 'sets up servers' do
expect(bot.server(server_id)).to eq(server)
end

it 'sets up emojis' do
expect(bot.server(server_id).emoji.size).to eq(2)
end
end

it 'raises when token string is empty or nil' do
expect { described_class.new(token: '') }.to raise_error('Token string is empty or nil')
expect { described_class.new(token: nil) }.to raise_error('Token string is empty or nil')
shared_examples 'raises when token string is' do |token, value|
it "raises when token string is #{token}" do
expect { described_class.new(token: value) }.to raise_error('Token string is empty or nil')
end
end

include_examples 'raises when token string is', 'empty', ''
include_examples 'raises when token string is', 'nil', nil

describe '#parse_mentions' do
it 'parses user mentions' do
user_a = double(:user_a)
user_b = double(:user_b)
user_a = instance_double(Discordrb::User, :user_a)
user_b = instance_double(Discordrb::User, :user_b)
allow(bot).to receive(:user).with('123').and_return(user_a)
allow(bot).to receive(:user).with('456').and_return(user_b)
mentions = bot.parse_mentions('<@!123><@!456>', server)
expect(mentions).to eq([user_a, user_b])
end

it 'parses channel mentions' do
channel_a = double(:channel_a)
channel_b = double(:channel_b)
channel_a = instance_double(Discordrb::Channel, :channel_a)
channel_b = instance_double(Discordrb::Channel, :channel_b)
allow(bot).to receive(:channel).with('123', server).and_return(channel_a)
allow(bot).to receive(:channel).with('456', server).and_return(channel_b)
mentions = bot.parse_mentions('<#123><#456>', server)
expect(mentions).to eq([channel_a, channel_b])
end

it 'parses role mentions' do
role_a = double(:role_a)
role_b = double(:role_b)
role_a = instance_double(Discordrb::Role, :role_a)
role_b = instance_double(Discordrb::Role, :role_b)
allow(server).to receive(:role).with('123').and_return(role_a)
allow(server).to receive(:role).with('456').and_return(role_b)
mentions = bot.parse_mentions('<@&123><@&456>')
expect(mentions).to eq([role_a, role_b])
end

it 'parses emoji mentions' do
emoji_a = double(:emoji_a)
emoji_b = double(:emoji_b)
emoji_a = instance_double(Discordrb::Emoji, :emoji_a)
emoji_b = instance_double(Discordrb::Emoji, :emoji_b)
allow(bot).to receive(:emoji).with('123').and_return(emoji_a)
allow(bot).to receive(:emoji).with('456').and_return(emoji_b)
mentions = bot.parse_mentions('<a:foo:123><a:bar:456>')
Expand All @@ -99,8 +108,9 @@
describe '#handle_dispatch' do
it 'handles GUILD_EMOJIS_UPDATE' do
type = :GUILD_EMOJIS_UPDATE
expect(bot).to receive(:raise_event).exactly(4).times
allow(bot).to receive(:raise_event)
bot.send(:handle_dispatch, type, dispatch_event)
expect(bot).to have_received(:raise_event).exactly(4).times
end

context 'when handling a PRESENCE_UPDATE' do
Expand Down Expand Up @@ -170,18 +180,20 @@
expect(bot).to have_received(:raise_event).with(instance_of(Discordrb::Events::ChannelCreateEvent))
end

it 'does not raise a ChannelCreateEvent if the DM channel is cached' do
it 'doesn\'t raise a ChannelCreateEvent if the DM channel is cached' do
allow(channel).to receive(:private?).and_return(true)
bot.instance_variable_set(:@pm_channels, { user_id => channel })

bot.send(:handle_dispatch, :MESSAGE_CREATE, message_fixture)

expect(bot).to_not have_received(:raise_event).with(instance_of(Discordrb::Events::ChannelCreateEvent))
expect(bot).not_to have_received(:raise_event).with(instance_of(Discordrb::Events::ChannelCreateEvent))
end
end
end

describe '#update_guild_emoji' do
# TODO: Rework tests to not rely on multiple expectations
# rubocop:disable RSpec/MultipleExpectations
it 'removes an emoji' do
bot.send(:update_guild_emoji, dispatch_remove)

Expand Down Expand Up @@ -217,15 +229,15 @@
expect(emoji.server).to eq(server)
expect(emoji.roles).to eq([])
end
# rubocop:enable RSpec/MultipleExpectations
end

describe '#send_file' do
let(:channel) { double(:channel, resolve_id: double) }
let(:channel) { instance_double(Discordrb::Channel, :channel, resolve_id: double) }

it 'defines original_filename when filename is passed' do
original_filename = double(:original_filename)
file = double(:file, original_filename: original_filename, read: true)
new_filename = double('new filename')
file = instance_double(File, :file, read: true)
new_filename = instance_double(String, 'new filename')

allow(Discordrb::API::Channel).to receive(:upload_file).and_return('{}')
allow(Discordrb::Message).to receive(:new)
Expand All @@ -234,19 +246,18 @@
expect(file.original_filename).to eq new_filename
end

it 'does not define original_filename when filename is nil' do
original_filename = double(:original_filename)
file = double(:file, read: true, original_filename: original_filename)
it 'doesn\'t define original_filename when filename is nil' do
file = instance_double(File, :file, read: true)

allow(Discordrb::API::Channel).to receive(:upload_file).and_return('{}')
allow(Discordrb::Message).to receive(:new)

bot.send_file(channel, file)
expect(file.original_filename).to eq original_filename
expect(file).not_to respond_to(:original_filename)
end

it 'prepends "SPOILER_" when spoiler is truthy and the filename does not start with "SPOILER_"' do
file = double(:file, read: true)
it 'prepends "SPOILER_" when spoiler is truthy and the filename doesn\'t start with "SPOILER_"' do
file = instance_double(File, :file, read: true)

allow(Discordrb::API::Channel).to receive(:upload_file).and_return('{}')
allow(Discordrb::Message).to receive(:new)
Expand All @@ -255,8 +266,8 @@
expect(file.original_filename).to eq 'SPOILER_file.txt'
end

it 'does not prepend "SPOILER_" if the filename starts with "SPOILER_"' do
file = double(:file, read: true, path: 'SPOILER_file.txt')
it 'doesn\'t prepend "SPOILER_" if the filename starts with "SPOILER_"' do
file = instance_double(File, :file, read: true, path: 'SPOILER_file.txt')

allow(Discordrb::API::Channel).to receive(:upload_file).and_return('{}')
allow(Discordrb::Message).to receive(:new)
Expand All @@ -266,7 +277,7 @@
end

it 'uses the original filename when spoiler is truthy and filename is nil' do
file = double(:file, read: true, path: 'file.txt')
file = instance_double(File, :file, read: true, path: 'file.txt')

allow(Discordrb::API::Channel).to receive(:upload_file).and_return('{}')
allow(Discordrb::Message).to receive(:new)
Expand All @@ -278,7 +289,7 @@

describe '#voice_connect' do
it 'requires encryption' do
channel = double(:channel, resolve_id: double)
channel = instance_double(Discordrb::Channel, :channel, resolve_id: double)
expect { bot.voice_connect(channel, false) }.to raise_error ArgumentError
end
end
Expand Down
Loading
Loading