Gab Social. All are welcome.
This commit is contained in:
109
spec/models/concerns/account_finder_concern_spec.rb
Normal file
109
spec/models/concerns/account_finder_concern_spec.rb
Normal file
@@ -0,0 +1,109 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe AccountFinderConcern do
|
||||
describe 'local finders' do
|
||||
before do
|
||||
@account = Fabricate(:account, username: 'Alice')
|
||||
end
|
||||
|
||||
describe '.find_local' do
|
||||
it 'returns case-insensitive result' do
|
||||
expect(Account.find_local('alice')).to eq(@account)
|
||||
end
|
||||
|
||||
it 'returns correctly cased result' do
|
||||
expect(Account.find_local('Alice')).to eq(@account)
|
||||
end
|
||||
|
||||
it 'returns nil without a match' do
|
||||
expect(Account.find_local('a_ice')).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil for regex style username value' do
|
||||
expect(Account.find_local('al%')).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil for nil username value' do
|
||||
expect(Account.find_local(nil)).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil for blank username value' do
|
||||
expect(Account.find_local('')).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe '.find_local!' do
|
||||
it 'returns matching result' do
|
||||
expect(Account.find_local!('alice')).to eq(@account)
|
||||
end
|
||||
|
||||
it 'raises on non-matching result' do
|
||||
expect { Account.find_local!('missing') }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
|
||||
it 'raises with blank username' do
|
||||
expect { Account.find_local!('') }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
|
||||
it 'raises with nil username' do
|
||||
expect { Account.find_local!(nil) }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'remote finders' do
|
||||
before do
|
||||
@account = Fabricate(:account, username: 'Alice', domain: 'gab.com')
|
||||
end
|
||||
|
||||
describe '.find_remote' do
|
||||
it 'returns exact match result' do
|
||||
expect(Account.find_remote('alice', 'gab.com')).to eq(@account)
|
||||
end
|
||||
|
||||
it 'returns case-insensitive result' do
|
||||
expect(Account.find_remote('ALICE', 'GAB.COM')).to eq(@account)
|
||||
end
|
||||
|
||||
it 'returns nil when username does not match' do
|
||||
expect(Account.find_remote('a_ice', 'gab.com')).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil when domain does not match' do
|
||||
expect(Account.find_remote('alice', 'g_b.com')).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil for regex style domain value' do
|
||||
expect(Account.find_remote('alice', 'm%')).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil for nil username value' do
|
||||
expect(Account.find_remote(nil, 'domain')).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil for blank username value' do
|
||||
expect(Account.find_remote('', 'domain')).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe '.find_remote!' do
|
||||
it 'returns matching result' do
|
||||
expect(Account.find_remote!('alice', 'gab.com')).to eq(@account)
|
||||
end
|
||||
|
||||
it 'raises on non-matching result' do
|
||||
expect { Account.find_remote!('missing', 'gab.host') }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
|
||||
it 'raises with blank username' do
|
||||
expect { Account.find_remote!('', '') }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
|
||||
it 'raises with nil username' do
|
||||
expect { Account.find_remote!(nil, nil) }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
613
spec/models/concerns/account_interactions_spec.rb
Normal file
613
spec/models/concerns/account_interactions_spec.rb
Normal file
@@ -0,0 +1,613 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe AccountInteractions do
|
||||
let(:account) { Fabricate(:account, username: 'account') }
|
||||
let(:account_id) { account.id }
|
||||
let(:account_ids) { [account_id] }
|
||||
let(:target_account) { Fabricate(:account, username: 'target') }
|
||||
let(:target_account_id) { target_account.id }
|
||||
let(:target_account_ids) { [target_account_id] }
|
||||
|
||||
describe '.following_map' do
|
||||
subject { Account.following_map(target_account_ids, account_id) }
|
||||
|
||||
context 'account with Follow' do
|
||||
it 'returns { target_account_id => true }' do
|
||||
Fabricate(:follow, account: account, target_account: target_account)
|
||||
is_expected.to eq(target_account_id => { reblogs: true })
|
||||
end
|
||||
end
|
||||
|
||||
context 'account without Follow' do
|
||||
it 'returns {}' do
|
||||
is_expected.to eq({})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.followed_by_map' do
|
||||
subject { Account.followed_by_map(target_account_ids, account_id) }
|
||||
|
||||
context 'account with Follow' do
|
||||
it 'returns { target_account_id => true }' do
|
||||
Fabricate(:follow, account: target_account, target_account: account)
|
||||
is_expected.to eq(target_account_id => true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'account without Follow' do
|
||||
it 'returns {}' do
|
||||
is_expected.to eq({})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.blocking_map' do
|
||||
subject { Account.blocking_map(target_account_ids, account_id) }
|
||||
|
||||
context 'account with Block' do
|
||||
it 'returns { target_account_id => true }' do
|
||||
Fabricate(:block, account: account, target_account: target_account)
|
||||
is_expected.to eq(target_account_id => true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'account without Block' do
|
||||
it 'returns {}' do
|
||||
is_expected.to eq({})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.muting_map' do
|
||||
subject { Account.muting_map(target_account_ids, account_id) }
|
||||
|
||||
context 'account with Mute' do
|
||||
before do
|
||||
Fabricate(:mute, target_account: target_account, account: account, hide_notifications: hide)
|
||||
end
|
||||
|
||||
context 'if Mute#hide_notifications?' do
|
||||
let(:hide) { true }
|
||||
|
||||
it 'returns { target_account_id => { notifications: true } }' do
|
||||
is_expected.to eq(target_account_id => { notifications: true })
|
||||
end
|
||||
end
|
||||
|
||||
context 'unless Mute#hide_notifications?' do
|
||||
let(:hide) { false }
|
||||
|
||||
it 'returns { target_account_id => { notifications: false } }' do
|
||||
is_expected.to eq(target_account_id => { notifications: false })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'account without Mute' do
|
||||
it 'returns {}' do
|
||||
is_expected.to eq({})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#follow!' do
|
||||
it 'creates and returns Follow' do
|
||||
expect do
|
||||
expect(account.follow!(target_account)).to be_kind_of Follow
|
||||
end.to change { account.following.count }.by 1
|
||||
end
|
||||
end
|
||||
|
||||
describe '#block' do
|
||||
it 'creates and returns Block' do
|
||||
expect do
|
||||
expect(account.block!(target_account)).to be_kind_of Block
|
||||
end.to change { account.block_relationships.count }.by 1
|
||||
end
|
||||
end
|
||||
|
||||
describe '#mute!' do
|
||||
subject { account.mute!(target_account, notifications: arg_notifications) }
|
||||
|
||||
context 'Mute does not exist yet' do
|
||||
context 'arg :notifications is nil' do
|
||||
let(:arg_notifications) { nil }
|
||||
|
||||
it 'creates Mute, and returns Mute' do
|
||||
expect do
|
||||
expect(subject).to be_kind_of Mute
|
||||
end.to change { account.mute_relationships.count }.by 1
|
||||
end
|
||||
end
|
||||
|
||||
context 'arg :notifications is false' do
|
||||
let(:arg_notifications) { false }
|
||||
|
||||
it 'creates Mute, and returns Mute' do
|
||||
expect do
|
||||
expect(subject).to be_kind_of Mute
|
||||
end.to change { account.mute_relationships.count }.by 1
|
||||
end
|
||||
end
|
||||
|
||||
context 'arg :notifications is true' do
|
||||
let(:arg_notifications) { true }
|
||||
|
||||
it 'creates Mute, and returns Mute' do
|
||||
expect do
|
||||
expect(subject).to be_kind_of Mute
|
||||
end.to change { account.mute_relationships.count }.by 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'Mute already exists' do
|
||||
before do
|
||||
account.mute_relationships << mute
|
||||
end
|
||||
|
||||
let(:mute) do
|
||||
Fabricate(:mute,
|
||||
account: account,
|
||||
target_account: target_account,
|
||||
hide_notifications: hide_notifications)
|
||||
end
|
||||
|
||||
context 'mute.hide_notifications is true' do
|
||||
let(:hide_notifications) { true }
|
||||
|
||||
context 'arg :notifications is nil' do
|
||||
let(:arg_notifications) { nil }
|
||||
|
||||
it 'returns Mute without updating mute.hide_notifications' do
|
||||
expect do
|
||||
expect(subject).to be_kind_of Mute
|
||||
end.not_to change { mute.reload.hide_notifications? }.from(true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'arg :notifications is false' do
|
||||
let(:arg_notifications) { false }
|
||||
|
||||
it 'returns Mute, and updates mute.hide_notifications false' do
|
||||
expect do
|
||||
expect(subject).to be_kind_of Mute
|
||||
end.to change { mute.reload.hide_notifications? }.from(true).to(false)
|
||||
end
|
||||
end
|
||||
|
||||
context 'arg :notifications is true' do
|
||||
let(:arg_notifications) { true }
|
||||
|
||||
it 'returns Mute without updating mute.hide_notifications' do
|
||||
expect do
|
||||
expect(subject).to be_kind_of Mute
|
||||
end.not_to change { mute.reload.hide_notifications? }.from(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'mute.hide_notifications is false' do
|
||||
let(:hide_notifications) { false }
|
||||
|
||||
context 'arg :notifications is nil' do
|
||||
let(:arg_notifications) { nil }
|
||||
|
||||
it 'returns Mute, and updates mute.hide_notifications true' do
|
||||
expect do
|
||||
expect(subject).to be_kind_of Mute
|
||||
end.to change { mute.reload.hide_notifications? }.from(false).to(true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'arg :notifications is false' do
|
||||
let(:arg_notifications) { false }
|
||||
|
||||
it 'returns Mute without updating mute.hide_notifications' do
|
||||
expect do
|
||||
expect(subject).to be_kind_of Mute
|
||||
end.not_to change { mute.reload.hide_notifications? }.from(false)
|
||||
end
|
||||
end
|
||||
|
||||
context 'arg :notifications is true' do
|
||||
let(:arg_notifications) { true }
|
||||
|
||||
it 'returns Mute, and updates mute.hide_notifications true' do
|
||||
expect do
|
||||
expect(subject).to be_kind_of Mute
|
||||
end.to change { mute.reload.hide_notifications? }.from(false).to(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#mute_conversation!' do
|
||||
let(:conversation) { Fabricate(:conversation) }
|
||||
|
||||
subject { account.mute_conversation!(conversation) }
|
||||
|
||||
it 'creates and returns ConversationMute' do
|
||||
expect do
|
||||
is_expected.to be_kind_of ConversationMute
|
||||
end.to change { account.conversation_mutes.count }.by 1
|
||||
end
|
||||
end
|
||||
|
||||
describe '#block_domain!' do
|
||||
let(:domain) { 'example.com' }
|
||||
|
||||
subject { account.block_domain!(domain) }
|
||||
|
||||
it 'creates and returns AccountDomainBlock' do
|
||||
expect do
|
||||
is_expected.to be_kind_of AccountDomainBlock
|
||||
end.to change { account.domain_blocks.count }.by 1
|
||||
end
|
||||
end
|
||||
|
||||
describe '#unfollow!' do
|
||||
subject { account.unfollow!(target_account) }
|
||||
|
||||
context 'following target_account' do
|
||||
it 'returns destroyed Follow' do
|
||||
account.active_relationships.create(target_account: target_account)
|
||||
is_expected.to be_kind_of Follow
|
||||
expect(subject).to be_destroyed
|
||||
end
|
||||
end
|
||||
|
||||
context 'not following target_account' do
|
||||
it 'returns nil' do
|
||||
is_expected.to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#unblock!' do
|
||||
subject { account.unblock!(target_account) }
|
||||
|
||||
context 'blocking target_account' do
|
||||
it 'returns destroyed Block' do
|
||||
account.block_relationships.create(target_account: target_account)
|
||||
is_expected.to be_kind_of Block
|
||||
expect(subject).to be_destroyed
|
||||
end
|
||||
end
|
||||
|
||||
context 'not blocking target_account' do
|
||||
it 'returns nil' do
|
||||
is_expected.to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#unmute!' do
|
||||
subject { account.unmute!(target_account) }
|
||||
|
||||
context 'muting target_account' do
|
||||
it 'returns destroyed Mute' do
|
||||
account.mute_relationships.create(target_account: target_account)
|
||||
is_expected.to be_kind_of Mute
|
||||
expect(subject).to be_destroyed
|
||||
end
|
||||
end
|
||||
|
||||
context 'not muting target_account' do
|
||||
it 'returns nil' do
|
||||
is_expected.to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#unmute_conversation!' do
|
||||
let(:conversation) { Fabricate(:conversation) }
|
||||
|
||||
subject { account.unmute_conversation!(conversation) }
|
||||
|
||||
context 'muting the conversation' do
|
||||
it 'returns destroyed ConversationMute' do
|
||||
account.conversation_mutes.create(conversation: conversation)
|
||||
is_expected.to be_kind_of ConversationMute
|
||||
expect(subject).to be_destroyed
|
||||
end
|
||||
end
|
||||
|
||||
context 'not muting the conversation' do
|
||||
it 'returns nil' do
|
||||
is_expected.to be nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#unblock_domain!' do
|
||||
let(:domain) { 'example.com' }
|
||||
|
||||
subject { account.unblock_domain!(domain) }
|
||||
|
||||
context 'blocking the domain' do
|
||||
it 'returns destroyed AccountDomainBlock' do
|
||||
account_domain_block = Fabricate(:account_domain_block, domain: domain)
|
||||
account.domain_blocks << account_domain_block
|
||||
is_expected.to be_kind_of AccountDomainBlock
|
||||
expect(subject).to be_destroyed
|
||||
end
|
||||
end
|
||||
|
||||
context 'unblocking the domain' do
|
||||
it 'returns nil' do
|
||||
is_expected.to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#following?' do
|
||||
subject { account.following?(target_account) }
|
||||
|
||||
context 'following target_account' do
|
||||
it 'returns true' do
|
||||
account.active_relationships.create(target_account: target_account)
|
||||
is_expected.to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'not following target_account' do
|
||||
it 'returns false' do
|
||||
is_expected.to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#blocking?' do
|
||||
subject { account.blocking?(target_account) }
|
||||
|
||||
context 'blocking target_account' do
|
||||
it 'returns true' do
|
||||
account.block_relationships.create(target_account: target_account)
|
||||
is_expected.to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'not blocking target_account' do
|
||||
it 'returns false' do
|
||||
is_expected.to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#domain_blocking?' do
|
||||
let(:domain) { 'example.com' }
|
||||
|
||||
subject { account.domain_blocking?(domain) }
|
||||
|
||||
context 'blocking the domain' do
|
||||
it' returns true' do
|
||||
account_domain_block = Fabricate(:account_domain_block, domain: domain)
|
||||
account.domain_blocks << account_domain_block
|
||||
is_expected.to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'not blocking the domain' do
|
||||
it 'returns false' do
|
||||
is_expected.to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#muting?' do
|
||||
subject { account.muting?(target_account) }
|
||||
|
||||
context 'muting target_account' do
|
||||
it 'returns true' do
|
||||
mute = Fabricate(:mute, account: account, target_account: target_account)
|
||||
account.mute_relationships << mute
|
||||
is_expected.to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'not muting target_account' do
|
||||
it 'returns false' do
|
||||
is_expected.to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#muting_conversation?' do
|
||||
let(:conversation) { Fabricate(:conversation) }
|
||||
|
||||
subject { account.muting_conversation?(conversation) }
|
||||
|
||||
context 'muting the conversation' do
|
||||
it 'returns true' do
|
||||
account.conversation_mutes.create(conversation: conversation)
|
||||
is_expected.to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'not muting the conversation' do
|
||||
it 'returns false' do
|
||||
is_expected.to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#muting_notifications?' do
|
||||
before do
|
||||
mute = Fabricate(:mute, target_account: target_account, account: account, hide_notifications: hide)
|
||||
account.mute_relationships << mute
|
||||
end
|
||||
|
||||
subject { account.muting_notifications?(target_account) }
|
||||
|
||||
context 'muting notifications of target_account' do
|
||||
let(:hide) { true }
|
||||
|
||||
it 'returns true' do
|
||||
is_expected.to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'not muting notifications of target_account' do
|
||||
let(:hide) { false }
|
||||
|
||||
it 'returns false' do
|
||||
is_expected.to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#requested?' do
|
||||
subject { account.requested?(target_account) }
|
||||
|
||||
context 'requested by target_account' do
|
||||
it 'returns true' do
|
||||
Fabricate(:follow_request, account: account, target_account: target_account)
|
||||
is_expected.to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'not requested by target_account' do
|
||||
it 'returns false' do
|
||||
is_expected.to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#favourited?' do
|
||||
let(:status) { Fabricate(:status, account: account, favourites: favourites) }
|
||||
|
||||
subject { account.favourited?(status) }
|
||||
|
||||
context 'favorited' do
|
||||
let(:favourites) { [Fabricate(:favourite, account: account)] }
|
||||
|
||||
it 'returns true' do
|
||||
is_expected.to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'not favorited' do
|
||||
let(:favourites) { [] }
|
||||
|
||||
it 'returns false' do
|
||||
is_expected.to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#reblogged?' do
|
||||
let(:status) { Fabricate(:status, account: account, reblogs: reblogs) }
|
||||
|
||||
subject { account.reblogged?(status) }
|
||||
|
||||
context 'reblogged' do
|
||||
let(:reblogs) { [Fabricate(:status, account: account)] }
|
||||
|
||||
it 'returns true' do
|
||||
is_expected.to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'not reblogged' do
|
||||
let(:reblogs) { [] }
|
||||
|
||||
it 'returns false' do
|
||||
is_expected.to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#pinned?' do
|
||||
let(:status) { Fabricate(:status, account: account) }
|
||||
|
||||
subject { account.pinned?(status) }
|
||||
|
||||
context 'pinned' do
|
||||
it 'returns true' do
|
||||
Fabricate(:status_pin, account: account, status: status)
|
||||
is_expected.to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'not pinned' do
|
||||
it 'returns false' do
|
||||
is_expected.to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'muting an account' do
|
||||
let(:me) { Fabricate(:account, username: 'Me') }
|
||||
let(:you) { Fabricate(:account, username: 'You') }
|
||||
|
||||
context 'with the notifications option unspecified' do
|
||||
before do
|
||||
me.mute!(you)
|
||||
end
|
||||
|
||||
it 'defaults to muting notifications' do
|
||||
expect(me.muting_notifications?(you)).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'with the notifications option set to false' do
|
||||
before do
|
||||
me.mute!(you, notifications: false)
|
||||
end
|
||||
|
||||
it 'does not mute notifications' do
|
||||
expect(me.muting_notifications?(you)).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'with the notifications option set to true' do
|
||||
before do
|
||||
me.mute!(you, notifications: true)
|
||||
end
|
||||
|
||||
it 'does mute notifications' do
|
||||
expect(me.muting_notifications?(you)).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'ignoring reblogs from an account' do
|
||||
before do
|
||||
@me = Fabricate(:account, username: 'Me')
|
||||
@you = Fabricate(:account, username: 'You')
|
||||
end
|
||||
|
||||
context 'with the reblogs option unspecified' do
|
||||
before do
|
||||
@me.follow!(@you)
|
||||
end
|
||||
|
||||
it 'defaults to showing reblogs' do
|
||||
expect(@me.muting_reblogs?(@you)).to be(false)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with the reblogs option set to false' do
|
||||
before do
|
||||
@me.follow!(@you, reblogs: false)
|
||||
end
|
||||
|
||||
it 'does mute reblogs' do
|
||||
expect(@me.muting_reblogs?(@you)).to be(true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with the reblogs option set to true' do
|
||||
before do
|
||||
@me.follow!(@you, reblogs: true)
|
||||
end
|
||||
|
||||
it 'does not mute reblogs' do
|
||||
expect(@me.muting_reblogs?(@you)).to be(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
219
spec/models/concerns/remotable_spec.rb
Normal file
219
spec/models/concerns/remotable_spec.rb
Normal file
@@ -0,0 +1,219 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Remotable do
|
||||
class Foo
|
||||
def initialize
|
||||
@attrs = {}
|
||||
end
|
||||
|
||||
def [](arg)
|
||||
@attrs[arg]
|
||||
end
|
||||
|
||||
def []=(arg1, arg2)
|
||||
@attrs[arg1] = arg2
|
||||
end
|
||||
|
||||
def hoge=(arg); end
|
||||
|
||||
def hoge_file_name=(arg); end
|
||||
|
||||
def has_attribute?(arg); end
|
||||
|
||||
def self.attachment_definitions
|
||||
{ hoge: nil }
|
||||
end
|
||||
end
|
||||
|
||||
context 'Remotable module is included' do
|
||||
before do
|
||||
class Foo
|
||||
include Remotable
|
||||
remotable_attachment :hoge, 1.kilobyte
|
||||
end
|
||||
end
|
||||
|
||||
let(:attribute_name) { "#{hoge}_remote_url".to_sym }
|
||||
let(:code) { 200 }
|
||||
let(:file) { 'filename="foo.txt"' }
|
||||
let(:foo) { Foo.new }
|
||||
let(:headers) { { 'content-disposition' => file } }
|
||||
let(:hoge) { :hoge }
|
||||
let(:url) { 'https://google.com' }
|
||||
|
||||
let(:request) do
|
||||
stub_request(:get, url)
|
||||
.to_return(status: code, headers: headers)
|
||||
end
|
||||
|
||||
it 'defines a method #hoge_remote_url=' do
|
||||
expect(foo).to respond_to(:hoge_remote_url=)
|
||||
end
|
||||
|
||||
it 'defines a method #reset_hoge!' do
|
||||
expect(foo).to respond_to(:reset_hoge!)
|
||||
end
|
||||
|
||||
describe '#hoge_remote_url' do
|
||||
before do
|
||||
request
|
||||
end
|
||||
|
||||
it 'always returns arg' do
|
||||
[nil, '', [], {}].each do |arg|
|
||||
expect(foo.hoge_remote_url = arg).to be arg
|
||||
end
|
||||
end
|
||||
|
||||
context 'Addressable::URI::InvalidURIError raised' do
|
||||
it 'makes no request' do
|
||||
allow(Addressable::URI).to receive_message_chain(:parse, :normalize)
|
||||
.with(url).with(no_args).and_raise(Addressable::URI::InvalidURIError)
|
||||
|
||||
foo.hoge_remote_url = url
|
||||
expect(request).not_to have_been_requested
|
||||
end
|
||||
end
|
||||
|
||||
context 'scheme is neither http nor https' do
|
||||
let(:url) { 'ftp://google.com' }
|
||||
|
||||
it 'makes no request' do
|
||||
foo.hoge_remote_url = url
|
||||
expect(request).not_to have_been_requested
|
||||
end
|
||||
end
|
||||
|
||||
context 'parsed_url.host is empty' do
|
||||
it 'makes no request' do
|
||||
parsed_url = double(scheme: 'https', host: double(blank?: true))
|
||||
allow(Addressable::URI).to receive_message_chain(:parse, :normalize)
|
||||
.with(url).with(no_args).and_return(parsed_url)
|
||||
|
||||
foo.hoge_remote_url = url
|
||||
expect(request).not_to have_been_requested
|
||||
end
|
||||
end
|
||||
|
||||
context 'parsed_url.host is nil' do
|
||||
it 'makes no request' do
|
||||
parsed_url = Addressable::URI.parse('https:https://example.com/path/file.png')
|
||||
allow(Addressable::URI).to receive_message_chain(:parse, :normalize)
|
||||
.with(url).with(no_args).and_return(parsed_url)
|
||||
|
||||
foo.hoge_remote_url = url
|
||||
expect(request).not_to have_been_requested
|
||||
end
|
||||
end
|
||||
|
||||
context 'foo[attribute_name] == url' do
|
||||
it 'makes no request' do
|
||||
allow(foo).to receive(:[]).with(attribute_name).and_return(url)
|
||||
|
||||
foo.hoge_remote_url = url
|
||||
expect(request).not_to have_been_requested
|
||||
end
|
||||
end
|
||||
|
||||
context "scheme is https, parsed_url.host isn't empty, and foo[attribute_name] != url" do
|
||||
it 'makes a request' do
|
||||
foo.hoge_remote_url = url
|
||||
expect(request).to have_been_requested
|
||||
end
|
||||
|
||||
context 'response.code != 200' do
|
||||
let(:code) { 500 }
|
||||
|
||||
it 'calls not send' do
|
||||
expect(foo).not_to receive(:send).with("#{hoge}=", any_args)
|
||||
expect(foo).not_to receive(:send).with("#{hoge}_file_name=", any_args)
|
||||
foo.hoge_remote_url = url
|
||||
end
|
||||
end
|
||||
|
||||
context 'response.code == 200' do
|
||||
let(:code) { 200 }
|
||||
|
||||
context 'response contains headers["content-disposition"]' do
|
||||
let(:file) { 'filename="foo.txt"' }
|
||||
let(:headers) { { 'content-disposition' => file } }
|
||||
|
||||
it 'calls send' do
|
||||
string_io = StringIO.new('')
|
||||
extname = '.txt'
|
||||
basename = '0123456789abcdef'
|
||||
|
||||
allow(SecureRandom).to receive(:hex).and_return(basename)
|
||||
allow(StringIO).to receive(:new).with(anything).and_return(string_io)
|
||||
|
||||
expect(foo).to receive(:send).with("#{hoge}=", string_io)
|
||||
expect(foo).to receive(:send).with("#{hoge}_file_name=", basename + extname)
|
||||
foo.hoge_remote_url = url
|
||||
end
|
||||
end
|
||||
|
||||
context 'if has_attribute?' do
|
||||
it 'calls foo[attribute_name] = url' do
|
||||
allow(foo).to receive(:has_attribute?).with(attribute_name).and_return(true)
|
||||
expect(foo).to receive('[]=').with(attribute_name, url)
|
||||
foo.hoge_remote_url = url
|
||||
end
|
||||
end
|
||||
|
||||
context 'unless has_attribute?' do
|
||||
it 'calls not foo[attribute_name] = url' do
|
||||
allow(foo).to receive(:has_attribute?)
|
||||
.with(attribute_name).and_return(false)
|
||||
expect(foo).not_to receive('[]=').with(attribute_name, url)
|
||||
foo.hoge_remote_url = url
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'an error raised during the request' do
|
||||
let(:request) { stub_request(:get, url).to_raise(error_class) }
|
||||
|
||||
error_classes = [
|
||||
HTTP::TimeoutError,
|
||||
HTTP::ConnectionError,
|
||||
OpenSSL::SSL::SSLError,
|
||||
Paperclip::Errors::NotIdentifiedByImageMagickError,
|
||||
Addressable::URI::InvalidURIError,
|
||||
]
|
||||
|
||||
error_classes.each do |error_class|
|
||||
let(:error_class) { error_class }
|
||||
|
||||
it 'calls Rails.logger.debug' do
|
||||
expect(Rails.logger).to receive(:debug).with(/^Error fetching remote #{hoge}: /)
|
||||
foo.hoge_remote_url = url
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#reset_hoge!' do
|
||||
context 'if url.blank?' do
|
||||
it 'returns nil, without clearing foo[attribute_name] and calling #hoge_remote_url=' do
|
||||
url = nil
|
||||
expect(foo).not_to receive(:send).with(:hoge_remote_url=, url)
|
||||
foo[attribute_name] = url
|
||||
expect(foo.reset_hoge!).to be_nil
|
||||
expect(foo[attribute_name]).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'unless url.blank?' do
|
||||
it 'clears foo[attribute_name] and calls #hoge_remote_url=' do
|
||||
foo[attribute_name] = url
|
||||
expect(foo).to receive(:send).with(:hoge_remote_url=, url)
|
||||
foo.reset_hoge!
|
||||
expect(foo[attribute_name]).to be ''
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
132
spec/models/concerns/status_threading_concern_spec.rb
Normal file
132
spec/models/concerns/status_threading_concern_spec.rb
Normal file
@@ -0,0 +1,132 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe StatusThreadingConcern do
|
||||
describe '#ancestors' do
|
||||
let!(:alice) { Fabricate(:account, username: 'alice') }
|
||||
let!(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com') }
|
||||
let!(:jeff) { Fabricate(:account, username: 'jeff') }
|
||||
let!(:status) { Fabricate(:status, account: alice) }
|
||||
let!(:reply1) { Fabricate(:status, thread: status, account: jeff) }
|
||||
let!(:reply2) { Fabricate(:status, thread: reply1, account: bob) }
|
||||
let!(:reply3) { Fabricate(:status, thread: reply2, account: alice) }
|
||||
let!(:viewer) { Fabricate(:account, username: 'viewer') }
|
||||
|
||||
it 'returns conversation history' do
|
||||
expect(reply3.ancestors(4)).to include(status, reply1, reply2)
|
||||
end
|
||||
|
||||
it 'does not return conversation history user is not allowed to see' do
|
||||
reply1.update(visibility: :private)
|
||||
status.update(visibility: :direct)
|
||||
|
||||
expect(reply3.ancestors(4, viewer)).to_not include(reply1, status)
|
||||
end
|
||||
|
||||
it 'does not return conversation history from blocked users' do
|
||||
viewer.block!(jeff)
|
||||
expect(reply3.ancestors(4, viewer)).to_not include(reply1)
|
||||
end
|
||||
|
||||
it 'does not return conversation history from muted users' do
|
||||
viewer.mute!(jeff)
|
||||
expect(reply3.ancestors(4, viewer)).to_not include(reply1)
|
||||
end
|
||||
|
||||
it 'does not return conversation history from silenced and not followed users' do
|
||||
jeff.silence!
|
||||
expect(reply3.ancestors(4, viewer)).to_not include(reply1)
|
||||
end
|
||||
|
||||
it 'does not return conversation history from blocked domains' do
|
||||
viewer.block_domain!('example.com')
|
||||
expect(reply3.ancestors(4, viewer)).to_not include(reply2)
|
||||
end
|
||||
|
||||
it 'ignores deleted records' do
|
||||
first_status = Fabricate(:status, account: bob)
|
||||
second_status = Fabricate(:status, thread: first_status, account: alice)
|
||||
|
||||
# Create cache and delete cached record
|
||||
second_status.ancestors(4)
|
||||
first_status.destroy
|
||||
|
||||
expect(second_status.ancestors(4)).to eq([])
|
||||
end
|
||||
|
||||
it 'can return more records than previously requested' do
|
||||
first_status = Fabricate(:status, account: bob)
|
||||
second_status = Fabricate(:status, thread: first_status, account: alice)
|
||||
third_status = Fabricate(:status, thread: second_status, account: alice)
|
||||
|
||||
# Create cache
|
||||
second_status.ancestors(1)
|
||||
|
||||
expect(third_status.ancestors(2)).to eq([first_status, second_status])
|
||||
end
|
||||
|
||||
it 'can return fewer records than previously requested' do
|
||||
first_status = Fabricate(:status, account: bob)
|
||||
second_status = Fabricate(:status, thread: first_status, account: alice)
|
||||
third_status = Fabricate(:status, thread: second_status, account: alice)
|
||||
|
||||
# Create cache
|
||||
second_status.ancestors(2)
|
||||
|
||||
expect(third_status.ancestors(1)).to eq([second_status])
|
||||
end
|
||||
end
|
||||
|
||||
describe '#descendants' do
|
||||
let!(:alice) { Fabricate(:account, username: 'alice') }
|
||||
let!(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com') }
|
||||
let!(:jeff) { Fabricate(:account, username: 'jeff') }
|
||||
let!(:status) { Fabricate(:status, account: alice) }
|
||||
let!(:reply1) { Fabricate(:status, thread: status, account: alice) }
|
||||
let!(:reply2) { Fabricate(:status, thread: status, account: bob) }
|
||||
let!(:reply3) { Fabricate(:status, thread: reply1, account: jeff) }
|
||||
let!(:viewer) { Fabricate(:account, username: 'viewer') }
|
||||
|
||||
it 'returns replies' do
|
||||
expect(status.descendants(4)).to include(reply1, reply2, reply3)
|
||||
end
|
||||
|
||||
it 'does not return replies user is not allowed to see' do
|
||||
reply1.update(visibility: :private)
|
||||
reply3.update(visibility: :direct)
|
||||
|
||||
expect(status.descendants(4, viewer)).to_not include(reply1, reply3)
|
||||
end
|
||||
|
||||
it 'does not return replies from blocked users' do
|
||||
viewer.block!(jeff)
|
||||
expect(status.descendants(4, viewer)).to_not include(reply3)
|
||||
end
|
||||
|
||||
it 'does not return replies from muted users' do
|
||||
viewer.mute!(jeff)
|
||||
expect(status.descendants(4, viewer)).to_not include(reply3)
|
||||
end
|
||||
|
||||
it 'does not return replies from silenced and not followed users' do
|
||||
jeff.silence!
|
||||
expect(status.descendants(4, viewer)).to_not include(reply3)
|
||||
end
|
||||
|
||||
it 'does not return replies from blocked domains' do
|
||||
viewer.block_domain!('example.com')
|
||||
expect(status.descendants(4, viewer)).to_not include(reply2)
|
||||
end
|
||||
|
||||
it 'promotes self-replies to the top while leaving the rest in order' do
|
||||
a = Fabricate(:status, account: alice)
|
||||
d = Fabricate(:status, account: jeff, thread: a)
|
||||
e = Fabricate(:status, account: bob, thread: d)
|
||||
c = Fabricate(:status, account: alice, thread: a)
|
||||
f = Fabricate(:status, account: bob, thread: c)
|
||||
|
||||
expect(a.descendants(20)).to eq [c, d, e, f]
|
||||
end
|
||||
end
|
||||
end
|
||||
63
spec/models/concerns/streamable_spec.rb
Normal file
63
spec/models/concerns/streamable_spec.rb
Normal file
@@ -0,0 +1,63 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Streamable do
|
||||
class Parent
|
||||
def title; end
|
||||
|
||||
def target; end
|
||||
|
||||
def thread; end
|
||||
|
||||
def self.has_one(*); end
|
||||
|
||||
def self.after_create; end
|
||||
end
|
||||
|
||||
class Child < Parent
|
||||
include Streamable
|
||||
end
|
||||
|
||||
child = Child.new
|
||||
|
||||
describe '#title' do
|
||||
it 'calls Parent#title' do
|
||||
expect_any_instance_of(Parent).to receive(:title)
|
||||
child.title
|
||||
end
|
||||
end
|
||||
|
||||
describe '#content' do
|
||||
it 'calls #title' do
|
||||
expect_any_instance_of(Parent).to receive(:title)
|
||||
child.content
|
||||
end
|
||||
end
|
||||
|
||||
describe '#target' do
|
||||
it 'calls Parent#target' do
|
||||
expect_any_instance_of(Parent).to receive(:target)
|
||||
child.target
|
||||
end
|
||||
end
|
||||
|
||||
describe '#object_type' do
|
||||
it 'returns :activity' do
|
||||
expect(child.object_type).to eq :activity
|
||||
end
|
||||
end
|
||||
|
||||
describe '#thread' do
|
||||
it 'calls Parent#thread' do
|
||||
expect_any_instance_of(Parent).to receive(:thread)
|
||||
child.thread
|
||||
end
|
||||
end
|
||||
|
||||
describe '#hidden?' do
|
||||
it 'returns false' do
|
||||
expect(child.hidden?).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user