Merge commit 'f877aa9d70d0d600961989b8e97c0e0ce3ac1db6' into glitch-soc/merge-upstream

Conflicts:
- `.github/dependabot.yml`:
  Upstream made changes, but we had removed it.
  Discarded upstream changes.
- `.rubocop_todo.yml`:
  Upstream regenerated the file, we had some glitch-soc-specific ignores.
- `app/models/account_statuses_filter.rb`:
  Minor upstream code style change where glitch-soc had slightly different code
  due to handling of local-only posts.
  Updated to match upstream's code style.
- `app/models/status.rb`:
  Upstream moved ActiveRecord callback definitions, glitch-soc had an extra one.
  Moved the definitions as upstream did.
- `app/services/backup_service.rb`:
  Upstream rewrote a lot of the backup service, glitch-soc had changes because
  of exporting local-only posts.
  Took upstream changes and added back code to deal with local-only posts.
- `config/routes.rb`:
  Upstream split the file into different files, while glitch-soc had a few
  extra routes.
  Extra routes added to `config/routes/settings.rb`, `config/routes/api.rb`
  and `config/routes/admin.rb`
- `db/schema.rb`:
  Upstream has new migrations, while glitch-soc had an extra migration.
  Updated the expected serial number to match upstream's.
- `lib/mastodon/version.rb`:
  Upstream added support to set version tags from environment variables, while
  glitch-soc has an extra `+glitch` tag.
  Changed the code to support upstream's feature but prepending a `+glitch`.
- `spec/lib/activitypub/activity/create_spec.rb`:
  Minor code style change upstream, while glitch-soc has extra tests due to
  `directMessage` handling.
  Applied upstream's changes while keeping glitch-soc's extra tests.
- `spec/models/concerns/account_interactions_spec.rb`:
  Minor code style change upstream, while glitch-soc has extra tests.
  Applied upstream's changes while keeping glitch-soc's extra tests.
This commit is contained in:
Claire
2023-05-08 19:05:55 +02:00
429 changed files with 6138 additions and 3323 deletions

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe Account::Field, type: :model do
RSpec.describe Account::Field do
describe '#verified?' do
subject { described_class.new(account, 'name' => 'Foo', 'value' => 'Bar', 'verified_at' => verified_at) }
@ -49,10 +49,10 @@ RSpec.describe Account::Field, type: :model do
let(:account) { double('Account', local?: local) }
context 'for local accounts' do
context 'with local accounts' do
let(:local) { true }
context 'for a URL with misleading authentication' do
context 'with a URL with misleading authentication' do
let(:value) { 'https://spacex.com @h.43z.one' }
it 'returns false' do
@ -60,7 +60,7 @@ RSpec.describe Account::Field, type: :model do
end
end
context 'for a URL' do
context 'with a URL' do
let(:value) { 'https://example.com' }
it 'returns true' do
@ -68,7 +68,7 @@ RSpec.describe Account::Field, type: :model do
end
end
context 'for an IDN URL' do
context 'with an IDN URL' do
let(:value) { 'https://twitter.comdougalljstatus1590357240443437057.ê.cc/twitter.html' }
it 'returns false' do
@ -76,7 +76,7 @@ RSpec.describe Account::Field, type: :model do
end
end
context 'for a URL with a non-normalized path' do
context 'with a URL with a non-normalized path' do
let(:value) { 'https://github.com/octocatxxxxxxxx/../mastodon' }
it 'returns false' do
@ -84,7 +84,7 @@ RSpec.describe Account::Field, type: :model do
end
end
context 'for text that is not a URL' do
context 'with text that is not a URL' do
let(:value) { 'Hello world' }
it 'returns false' do
@ -92,7 +92,7 @@ RSpec.describe Account::Field, type: :model do
end
end
context 'for text that contains a URL' do
context 'with text that contains a URL' do
let(:value) { 'Hello https://example.com world' }
it 'returns false' do
@ -100,7 +100,7 @@ RSpec.describe Account::Field, type: :model do
end
end
context 'for text which is blank' do
context 'with text which is blank' do
let(:value) { '' }
it 'returns false' do
@ -109,10 +109,10 @@ RSpec.describe Account::Field, type: :model do
end
end
context 'for remote accounts' do
context 'with remote accounts' do
let(:local) { false }
context 'for a link' do
context 'with a link' do
let(:value) { '<a href="https://www.patreon.com/mastodon" target="_blank" rel="nofollow noopener noreferrer me"><span class="invisible">https://www.</span><span class="">patreon.com/mastodon</span><span class="invisible"></span></a>' }
it 'returns true' do
@ -120,7 +120,7 @@ RSpec.describe Account::Field, type: :model do
end
end
context 'for a link with misleading authentication' do
context 'with a link with misleading authentication' do
let(:value) { '<a href="https://google.com @h.43z.one" target="_blank" rel="nofollow noopener noreferrer me"><span class="invisible">https://</span><span class="">google.com</span><span class="invisible"> @h.43z.one</span></a>' }
it 'returns false' do
@ -128,7 +128,7 @@ RSpec.describe Account::Field, type: :model do
end
end
context 'for HTML that has more than just a link' do
context 'with HTML that has more than just a link' do
let(:value) { '<a href="https://google.com" target="_blank" rel="nofollow noopener noreferrer me"><span class="invisible">https://</span><span class="">google.com</span><span class="invisible"></span></a> @h.43z.one' }
it 'returns false' do
@ -136,7 +136,7 @@ RSpec.describe Account::Field, type: :model do
end
end
context 'for a link with different visible text' do
context 'with a link with different visible text' do
let(:value) { '<a href="https://google.com/bar">https://example.com/foo</a>' }
it 'returns false' do
@ -144,7 +144,7 @@ RSpec.describe Account::Field, type: :model do
end
end
context 'for text that is a URL but is not linked' do
context 'with text that is a URL but is not linked' do
let(:value) { 'https://example.com/foo' }
it 'returns false' do
@ -152,7 +152,7 @@ RSpec.describe Account::Field, type: :model do
end
end
context 'for text which is blank' do
context 'with text which is blank' do
let(:value) { '' }
it 'returns false' do

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe AccountAlias, type: :model do
RSpec.describe AccountAlias do
end

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe AccountConversation, type: :model do
RSpec.describe AccountConversation do
let!(:alice) { Fabricate(:account, username: 'alice') }
let!(:bob) { Fabricate(:account, username: 'bob') }
let!(:mark) { Fabricate(:account, username: 'mark') }

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe AccountDeletionRequest, type: :model do
RSpec.describe AccountDeletionRequest do
end

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe AccountDomainBlock, type: :model do
RSpec.describe AccountDomainBlock do
it 'removes blocking cache after creation' do
account = Fabricate(:account)
Rails.cache.write("exclude_domains_for:#{account.id}", 'a.domain.already.blocked')

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe AccountMigration, type: :model do
RSpec.describe AccountMigration do
describe 'validations' do
let(:source_account) { Fabricate(:account) }
let(:target_acct) { target_account.acct }

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe AccountModerationNote, type: :model do
RSpec.describe AccountModerationNote do
end

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe Account, type: :model do
RSpec.describe Account do
context do
subject { Fabricate(:account) }
@ -171,7 +171,7 @@ RSpec.describe Account, type: :model do
describe '#possibly_stale?' do
let(:account) { Fabricate(:account, last_webfingered_at: last_webfingered_at) }
context 'last_webfingered_at is nil' do
context 'when last_webfingered_at is nil' do
let(:last_webfingered_at) { nil }
it 'returns true' do
@ -179,7 +179,7 @@ RSpec.describe Account, type: :model do
end
end
context 'last_webfingered_at is more than 24 hours before' do
context 'when last_webfingered_at is more than 24 hours before' do
let(:last_webfingered_at) { 25.hours.ago }
it 'returns true' do
@ -187,7 +187,7 @@ RSpec.describe Account, type: :model do
end
end
context 'last_webfingered_at is less than 24 hours before' do
context 'when last_webfingered_at is less than 24 hours before' do
let(:last_webfingered_at) { 23.hours.ago }
it 'returns false' do
@ -200,7 +200,7 @@ RSpec.describe Account, type: :model do
let(:account) { Fabricate(:account, domain: domain) }
let(:acct) { account.acct }
context 'domain is nil' do
context 'when domain is nil' do
let(:domain) { nil }
it 'returns nil' do
@ -213,7 +213,7 @@ RSpec.describe Account, type: :model do
end
end
context 'domain is present' do
context 'when domain is present' do
let(:domain) { 'example.com' }
it 'calls ResolveAccountService#call' do
@ -902,7 +902,7 @@ RSpec.describe Account, type: :model do
describe 'recent' do
it 'returns a relation of accounts sorted by recent creation' do
matches = 2.times.map { Fabricate(:account) }
matches = Array.new(2) { Fabricate(:account) }
expect(Account.where('id > 0').recent).to match_array(matches)
end
end

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe AccountStatusesCleanupPolicy, type: :model do
RSpec.describe AccountStatusesCleanupPolicy do
let(:account) { Fabricate(:account, username: 'alice', domain: nil) }
describe 'validation' do

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe Admin::AccountAction, type: :model do
RSpec.describe Admin::AccountAction do
let(:account_action) { described_class.new }
describe '#save!' do
@ -20,7 +20,7 @@ RSpec.describe Admin::AccountAction, type: :model do
)
end
context 'type is "disable"' do
context 'when type is "disable"' do
let(:type) { 'disable' }
it 'disable user' do
@ -29,7 +29,7 @@ RSpec.describe Admin::AccountAction, type: :model do
end
end
context 'type is "silence"' do
context 'when type is "silence"' do
let(:type) { 'silence' }
it 'silences account' do
@ -38,7 +38,7 @@ RSpec.describe Admin::AccountAction, type: :model do
end
end
context 'type is "suspend"' do
context 'when type is "suspend"' do
let(:type) { 'suspend' }
it 'suspends account' do
@ -75,7 +75,7 @@ RSpec.describe Admin::AccountAction, type: :model do
describe '#report' do
subject { account_action.report }
context 'report_id.present?' do
context 'with report_id.present?' do
before do
account_action.report_id = Fabricate(:report).id
end
@ -85,7 +85,7 @@ RSpec.describe Admin::AccountAction, type: :model do
end
end
context '!report_id.present?' do
context 'with !report_id.present?' do
it 'returns nil' do
expect(subject).to be_nil
end
@ -95,7 +95,7 @@ RSpec.describe Admin::AccountAction, type: :model do
describe '#with_report?' do
subject { account_action.with_report? }
context '!report.nil?' do
context 'with !report.nil?' do
before do
account_action.report_id = Fabricate(:report).id
end
@ -105,7 +105,7 @@ RSpec.describe Admin::AccountAction, type: :model do
end
end
context '!(!report.nil?)' do
context 'with !(!report.nil?)' do
it 'returns false' do
expect(subject).to be false
end
@ -115,7 +115,7 @@ RSpec.describe Admin::AccountAction, type: :model do
describe '.types_for_account' do
subject { described_class.types_for_account(account) }
context 'account.local?' do
context 'when Account.local?' do
let(:account) { Fabricate(:account, domain: nil) }
it 'returns ["none", "disable", "sensitive", "silence", "suspend"]' do
@ -123,7 +123,7 @@ RSpec.describe Admin::AccountAction, type: :model do
end
end
context '!account.local?' do
context 'with !account.local?' do
let(:account) { Fabricate(:account, domain: 'hoge.com') }
it 'returns ["sensitive", "silence", "suspend"]' do

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe Admin::ActionLog, type: :model do
RSpec.describe Admin::ActionLog do
describe '#action' do
it 'returns action' do
action_log = described_class.new(action: 'hoge')

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe AnnouncementMute, type: :model do
RSpec.describe AnnouncementMute do
end

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe AnnouncementReaction, type: :model do
RSpec.describe AnnouncementReaction do
end

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe Announcement, type: :model do
RSpec.describe Announcement do
end

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe Backup, type: :model do
RSpec.describe Backup do
end

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe Block, type: :model do
RSpec.describe Block do
describe 'validations' do
it 'is invalid without an account' do
block = Fabricate.build(:block, account: nil)

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe CanonicalEmailBlock, type: :model do
RSpec.describe CanonicalEmailBlock do
describe '#email=' do
let(:target_hash) { '973dfe463ec85785f5f95af5ba3906eedb2d931c24e69824a89ea65dba4e813b' }

View File

@ -13,21 +13,21 @@ describe AccountInteractions do
describe '.following_map' do
subject { Account.following_map(target_account_ids, account_id) }
context 'account with Follow' do
it 'returns { target_account_id => { reblogs: true } }' do
context 'when Account with Follow' do
it 'returns { target_account_id => true }' do
Fabricate(:follow, account: account, target_account: target_account)
expect(subject).to eq(target_account_id => { reblogs: true, notify: false, languages: nil })
end
end
context 'account with Follow but with reblogs disabled' do
context 'when Account with Follow but with reblogs disabled' do
it 'returns { target_account_id => { reblogs: false } }' do
Fabricate(:follow, account: account, target_account: target_account, show_reblogs: false)
expect(subject).to eq(target_account_id => { reblogs: false, notify: false, languages: nil })
end
end
context 'account without Follow' do
context 'when Account without Follow' do
it 'returns {}' do
expect(subject).to eq({})
end
@ -37,14 +37,14 @@ describe AccountInteractions do
describe '.followed_by_map' do
subject { Account.followed_by_map(target_account_ids, account_id) }
context 'account with Follow' do
context 'when Account with Follow' do
it 'returns { target_account_id => true }' do
Fabricate(:follow, account: target_account, target_account: account)
expect(subject).to eq(target_account_id => true)
end
end
context 'account without Follow' do
context 'when Account without Follow' do
it 'returns {}' do
expect(subject).to eq({})
end
@ -54,14 +54,14 @@ describe AccountInteractions do
describe '.blocking_map' do
subject { Account.blocking_map(target_account_ids, account_id) }
context 'account with Block' do
context 'when Account with Block' do
it 'returns { target_account_id => true }' do
Fabricate(:block, account: account, target_account: target_account)
expect(subject).to eq(target_account_id => true)
end
end
context 'account without Block' do
context 'when Account without Block' do
it 'returns {}' do
expect(subject).to eq({})
end
@ -71,12 +71,12 @@ describe AccountInteractions do
describe '.muting_map' do
subject { Account.muting_map(target_account_ids, account_id) }
context 'account with Mute' do
context 'when Account with Mute' do
before do
Fabricate(:mute, target_account: target_account, account: account, hide_notifications: hide)
end
context 'if Mute#hide_notifications?' do
context 'when Mute#hide_notifications?' do
let(:hide) { true }
it 'returns { target_account_id => { notifications: true } }' do
@ -84,7 +84,7 @@ describe AccountInteractions do
end
end
context 'unless Mute#hide_notifications?' do
context 'when not Mute#hide_notifications?' do
let(:hide) { false }
it 'returns { target_account_id => { notifications: false } }' do
@ -93,7 +93,7 @@ describe AccountInteractions do
end
end
context 'account without Mute' do
context 'when Account without Mute' do
it 'returns {}' do
expect(subject).to eq({})
end
@ -119,8 +119,8 @@ describe AccountInteractions do
describe '#mute!' do
subject { account.mute!(target_account, notifications: arg_notifications) }
context 'Mute does not exist yet' do
context 'arg :notifications is nil' do
context 'when Mute does not exist yet' do
context 'when arg :notifications is nil' do
let(:arg_notifications) { nil }
it 'creates Mute, and returns Mute' do
@ -130,7 +130,7 @@ describe AccountInteractions do
end
end
context 'arg :notifications is false' do
context 'when arg :notifications is false' do
let(:arg_notifications) { false }
it 'creates Mute, and returns Mute' do
@ -140,7 +140,7 @@ describe AccountInteractions do
end
end
context 'arg :notifications is true' do
context 'when arg :notifications is true' do
let(:arg_notifications) { true }
it 'creates Mute, and returns Mute' do
@ -151,7 +151,7 @@ describe AccountInteractions do
end
end
context 'Mute already exists' do
context 'when Mute already exists' do
before do
account.mute_relationships << mute
end
@ -163,10 +163,10 @@ describe AccountInteractions do
hide_notifications: hide_notifications)
end
context 'mute.hide_notifications is true' do
context 'when mute.hide_notifications is true' do
let(:hide_notifications) { true }
context 'arg :notifications is nil' do
context 'when arg :notifications is nil' do
let(:arg_notifications) { nil }
it 'returns Mute without updating mute.hide_notifications' do
@ -176,7 +176,7 @@ describe AccountInteractions do
end
end
context 'arg :notifications is false' do
context 'when arg :notifications is false' do
let(:arg_notifications) { false }
it 'returns Mute, and updates mute.hide_notifications false' do
@ -186,7 +186,7 @@ describe AccountInteractions do
end
end
context 'arg :notifications is true' do
context 'when arg :notifications is true' do
let(:arg_notifications) { true }
it 'returns Mute without updating mute.hide_notifications' do
@ -197,10 +197,10 @@ describe AccountInteractions do
end
end
context 'mute.hide_notifications is false' do
context 'when mute.hide_notifications is false' do
let(:hide_notifications) { false }
context 'arg :notifications is nil' do
context 'when arg :notifications is nil' do
let(:arg_notifications) { nil }
it 'returns Mute, and updates mute.hide_notifications true' do
@ -210,7 +210,7 @@ describe AccountInteractions do
end
end
context 'arg :notifications is false' do
context 'when arg :notifications is false' do
let(:arg_notifications) { false }
it 'returns Mute without updating mute.hide_notifications' do
@ -220,7 +220,7 @@ describe AccountInteractions do
end
end
context 'arg :notifications is true' do
context 'when arg :notifications is true' do
let(:arg_notifications) { true }
it 'returns Mute, and updates mute.hide_notifications true' do
@ -260,7 +260,7 @@ describe AccountInteractions do
describe '#unfollow!' do
subject { account.unfollow!(target_account) }
context 'following target_account' do
context 'when following target_account' do
it 'returns destroyed Follow' do
account.active_relationships.create(target_account: target_account)
expect(subject).to be_a Follow
@ -268,7 +268,7 @@ describe AccountInteractions do
end
end
context 'not following target_account' do
context 'when not following target_account' do
it 'returns nil' do
expect(subject).to be_nil
end
@ -278,7 +278,7 @@ describe AccountInteractions do
describe '#unblock!' do
subject { account.unblock!(target_account) }
context 'blocking target_account' do
context 'when blocking target_account' do
it 'returns destroyed Block' do
account.block_relationships.create(target_account: target_account)
expect(subject).to be_a Block
@ -286,7 +286,7 @@ describe AccountInteractions do
end
end
context 'not blocking target_account' do
context 'when not blocking target_account' do
it 'returns nil' do
expect(subject).to be_nil
end
@ -296,7 +296,7 @@ describe AccountInteractions do
describe '#unmute!' do
subject { account.unmute!(target_account) }
context 'muting target_account' do
context 'when muting target_account' do
it 'returns destroyed Mute' do
account.mute_relationships.create(target_account: target_account)
expect(subject).to be_a Mute
@ -304,7 +304,7 @@ describe AccountInteractions do
end
end
context 'not muting target_account' do
context 'when not muting target_account' do
it 'returns nil' do
expect(subject).to be_nil
end
@ -316,7 +316,7 @@ describe AccountInteractions do
let(:conversation) { Fabricate(:conversation) }
context 'muting the conversation' do
context 'when muting the conversation' do
it 'returns destroyed ConversationMute' do
account.conversation_mutes.create(conversation: conversation)
expect(subject).to be_a ConversationMute
@ -324,7 +324,7 @@ describe AccountInteractions do
end
end
context 'not muting the conversation' do
context 'when not muting the conversation' do
it 'returns nil' do
expect(subject).to be_nil
end
@ -336,7 +336,7 @@ describe AccountInteractions do
let(:domain) { 'example.com' }
context 'blocking the domain' do
context 'when blocking the domain' do
it 'returns destroyed AccountDomainBlock' do
account_domain_block = Fabricate(:account_domain_block, domain: domain)
account.domain_blocks << account_domain_block
@ -345,7 +345,7 @@ describe AccountInteractions do
end
end
context 'unblocking the domain' do
context 'when unblocking the domain' do
it 'returns nil' do
expect(subject).to be_nil
end
@ -355,14 +355,14 @@ describe AccountInteractions do
describe '#following?' do
subject { account.following?(target_account) }
context 'following target_account' do
context 'when following target_account' do
it 'returns true' do
account.active_relationships.create(target_account: target_account)
expect(subject).to be true
end
end
context 'not following target_account' do
context 'when not following target_account' do
it 'returns false' do
expect(subject).to be false
end
@ -372,14 +372,14 @@ describe AccountInteractions do
describe '#followed_by?' do
subject { account.followed_by?(target_account) }
context 'followed by target_account' do
context 'when followed by target_account' do
it 'returns true' do
account.passive_relationships.create(account: target_account)
expect(subject).to be true
end
end
context 'not followed by target_account' do
context 'when not followed by target_account' do
it 'returns false' do
expect(subject).to be false
end
@ -389,14 +389,14 @@ describe AccountInteractions do
describe '#blocking?' do
subject { account.blocking?(target_account) }
context 'blocking target_account' do
context 'when blocking target_account' do
it 'returns true' do
account.block_relationships.create(target_account: target_account)
expect(subject).to be true
end
end
context 'not blocking target_account' do
context 'when not blocking target_account' do
it 'returns false' do
expect(subject).to be false
end
@ -408,7 +408,7 @@ describe AccountInteractions do
let(:domain) { 'example.com' }
context 'blocking the domain' do
context 'when blocking the domain' do
it 'returns true' do
account_domain_block = Fabricate(:account_domain_block, domain: domain)
account.domain_blocks << account_domain_block
@ -416,7 +416,7 @@ describe AccountInteractions do
end
end
context 'not blocking the domain' do
context 'when not blocking the domain' do
it 'returns false' do
expect(subject).to be false
end
@ -426,7 +426,7 @@ describe AccountInteractions do
describe '#muting?' do
subject { account.muting?(target_account) }
context 'muting target_account' do
context 'when muting target_account' do
it 'returns true' do
mute = Fabricate(:mute, account: account, target_account: target_account)
account.mute_relationships << mute
@ -434,7 +434,7 @@ describe AccountInteractions do
end
end
context 'not muting target_account' do
context 'when not muting target_account' do
it 'returns false' do
expect(subject).to be false
end
@ -446,14 +446,14 @@ describe AccountInteractions do
let(:conversation) { Fabricate(:conversation) }
context 'muting the conversation' do
context 'when muting the conversation' do
it 'returns true' do
account.conversation_mutes.create(conversation: conversation)
expect(subject).to be true
end
end
context 'not muting the conversation' do
context 'when not muting the conversation' do
it 'returns false' do
expect(subject).to be false
end
@ -468,7 +468,7 @@ describe AccountInteractions do
account.mute_relationships << mute
end
context 'muting notifications of target_account' do
context 'when muting notifications of target_account' do
let(:hide) { true }
it 'returns true' do
@ -476,7 +476,7 @@ describe AccountInteractions do
end
end
context 'not muting notifications of target_account' do
context 'when not muting notifications of target_account' do
let(:hide) { false }
it 'returns false' do
@ -488,14 +488,14 @@ describe AccountInteractions do
describe '#requested?' do
subject { account.requested?(target_account) }
context 'requested by target_account' do
context 'with requested by target_account' do
it 'returns true' do
Fabricate(:follow_request, account: account, target_account: target_account)
expect(subject).to be true
end
end
context 'not requested by target_account' do
context 'when not requested by target_account' do
it 'returns false' do
expect(subject).to be false
end
@ -507,7 +507,7 @@ describe AccountInteractions do
let(:status) { Fabricate(:status, account: account, favourites: favourites) }
context 'favorited' do
context 'when favorited' do
let(:favourites) { [Fabricate(:favourite, account: account)] }
it 'returns true' do
@ -515,7 +515,7 @@ describe AccountInteractions do
end
end
context 'not favorited' do
context 'when not favorited' do
let(:favourites) { [] }
it 'returns false' do
@ -529,7 +529,7 @@ describe AccountInteractions do
let(:status) { Fabricate(:status, account: account, reblogs: reblogs) }
context 'reblogged' do
context 'with reblogged' do
let(:reblogs) { [Fabricate(:status, account: account)] }
it 'returns true' do
@ -537,7 +537,7 @@ describe AccountInteractions do
end
end
context 'not reblogged' do
context 'when not reblogged' do
let(:reblogs) { [] }
it 'returns false' do
@ -551,14 +551,14 @@ describe AccountInteractions do
let(:status) { Fabricate(:status, account: account) }
context 'pinned' do
context 'when pinned' do
it 'returns true' do
Fabricate(:status_pin, account: account, status: status)
expect(subject).to be true
end
end
context 'not pinned' do
context 'when not pinned' do
it 'returns false' do
expect(subject).to be false
end
@ -690,4 +690,32 @@ describe AccountInteractions do
end
end
end
describe '#lists_for_local_distribution' do
let(:account) { Fabricate(:user, current_sign_in_at: Time.now.utc).account }
let!(:inactive_follower_user) { Fabricate(:user, current_sign_in_at: 5.years.ago) }
let!(:follower_user) { Fabricate(:user, current_sign_in_at: Time.now.utc) }
let!(:follow_request_user) { Fabricate(:user, current_sign_in_at: Time.now.utc) }
let!(:inactive_follower_list) { Fabricate(:list, account: inactive_follower_user.account) }
let!(:follower_list) { Fabricate(:list, account: follower_user.account) }
let!(:follow_request_list) { Fabricate(:list, account: follow_request_user.account) }
let!(:self_list) { Fabricate(:list, account: account) }
before do
inactive_follower_user.account.follow!(account)
follower_user.account.follow!(account)
follow_request_user.account.follow_requests.create!(target_account: account)
inactive_follower_list.accounts << account
follower_list.accounts << account
follow_request_list.accounts << account
self_list.accounts << account
end
it 'includes only the list from the active follower and from oneself' do
expect(account.lists_for_local_distribution.to_a).to contain_exactly(follower_list, self_list)
end
end
end

View File

@ -3,48 +3,47 @@
require 'rails_helper'
RSpec.describe Remotable do
class Foo
def initialize
@attrs = {}
end
let(:foo_class) do
Class.new do
def initialize
@attrs = {}
end
def [](arg)
@attrs[arg]
end
def [](arg)
@attrs[arg]
end
def []=(arg1, arg2)
@attrs[arg1] = arg2
end
def []=(arg1, arg2)
@attrs[arg1] = arg2
end
def hoge=(arg); end
def hoge=(arg); end
def hoge_file_name; end
def hoge_file_name; end
def hoge_file_name=(arg); end
def hoge_file_name=(arg); end
def has_attribute?(arg); end
def has_attribute?(arg); end
def self.attachment_definitions
{ hoge: nil }
end
end
before do
class Foo
include Remotable
remotable_attachment :hoge, 1.kilobyte
def self.attachment_definitions
{ hoge: nil }
end
end
end
let(:attribute_name) { "#{hoge}_remote_url".to_sym }
let(:code) { 200 }
let(:file) { 'filename="foo.txt"' }
let(:foo) { Foo.new }
let(:foo) { foo_class.new }
let(:headers) { { 'content-disposition' => file } }
let(:hoge) { :hoge }
let(:url) { 'https://google.com' }
before do
foo_class.include described_class
foo_class.remotable_attachment :hoge, 1.kilobyte
end
it 'defines a method #hoge_remote_url=' do
expect(foo).to respond_to(:hoge_remote_url=)
end
@ -157,7 +156,7 @@ RSpec.describe Remotable do
context 'when the response is successful' do
let(:code) { 200 }
context 'and contains Content-Disposition header' do
context 'when contains Content-Disposition header' do
let(:file) { 'filename="foo.txt"' }
let(:headers) { { 'content-disposition' => file } }

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe ConversationMute, type: :model do
RSpec.describe ConversationMute do
end

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe Conversation, type: :model do
RSpec.describe Conversation do
describe '#local?' do
it 'returns true when URI is nil' do
expect(Fabricate(:conversation).local?).to be true

View File

@ -10,8 +10,8 @@ RSpec.describe CustomEmojiFilter do
let!(:custom_emoji_1) { Fabricate(:custom_emoji, domain: 'b') }
let!(:custom_emoji_2) { Fabricate(:custom_emoji, domain: nil, shortcode: 'hoge') }
context 'params have values' do
context 'local' do
context 'when params have values' do
context 'when local' do
let(:params) { { local: true } }
it 'returns ActiveRecord::Relation' do
@ -20,7 +20,7 @@ RSpec.describe CustomEmojiFilter do
end
end
context 'remote' do
context 'when remote' do
let(:params) { { remote: true } }
it 'returns ActiveRecord::Relation' do
@ -29,7 +29,7 @@ RSpec.describe CustomEmojiFilter do
end
end
context 'by_domain' do
context 'with by_domain' do
let(:params) { { by_domain: 'a' } }
it 'returns ActiveRecord::Relation' do
@ -38,7 +38,7 @@ RSpec.describe CustomEmojiFilter do
end
end
context 'shortcode' do
context 'when shortcode' do
let(:params) { { shortcode: 'hoge' } }
it 'returns ActiveRecord::Relation' do
@ -47,7 +47,7 @@ RSpec.describe CustomEmojiFilter do
end
end
context 'else' do
context 'when some other case' do
let(:params) { { else: 'else' } }
it 'raises Mastodon::InvalidParameterError' do
@ -58,7 +58,7 @@ RSpec.describe CustomEmojiFilter do
end
end
context 'params without value' do
context 'when params without value' do
let(:params) { { hoge: nil } }
it 'returns ActiveRecord::Relation' do

View File

@ -2,13 +2,13 @@
require 'rails_helper'
RSpec.describe CustomEmoji, type: :model do
RSpec.describe CustomEmoji do
describe '#search' do
subject { described_class.search(search_term) }
let(:custom_emoji) { Fabricate(:custom_emoji, shortcode: shortcode) }
context 'shortcode is exact' do
context 'when shortcode is exact' do
let(:shortcode) { 'blobpats' }
let(:search_term) { 'blobpats' }
@ -17,7 +17,7 @@ RSpec.describe CustomEmoji, type: :model do
end
end
context 'shortcode is partial' do
context 'when shortcode is partial' do
let(:shortcode) { 'blobpats' }
let(:search_term) { 'blob' }
@ -32,7 +32,7 @@ RSpec.describe CustomEmoji, type: :model do
let(:custom_emoji) { Fabricate(:custom_emoji, domain: domain) }
context 'domain is nil' do
context 'when domain is nil' do
let(:domain) { nil }
it 'returns true' do
@ -40,7 +40,7 @@ RSpec.describe CustomEmoji, type: :model do
end
end
context 'domain is present' do
context 'when domain is present' do
let(:domain) { 'example.com' }
it 'returns false' do

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe CustomFilterKeyword, type: :model do
RSpec.describe CustomFilterKeyword do
end

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe CustomFilter, type: :model do
RSpec.describe CustomFilter do
end

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe Device, type: :model do
RSpec.describe Device do
end

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe DomainBlock, type: :model do
RSpec.describe DomainBlock do
describe 'validations' do
it 'is invalid without a domain' do
domain_block = Fabricate.build(:domain_block, domain: nil)

View File

@ -2,11 +2,11 @@
require 'rails_helper'
RSpec.describe EmailDomainBlock, type: :model do
RSpec.describe EmailDomainBlock do
describe 'block?' do
let(:input) { nil }
context 'given an e-mail address' do
context 'when given an e-mail address' do
let(:input) { "foo@#{domain}" }
context do
@ -33,7 +33,7 @@ RSpec.describe EmailDomainBlock, type: :model do
end
end
context 'given an array of domains' do
context 'when given an array of domains' do
let(:input) { %w(foo.com mail.foo.com) }
it 'returns true if the domain is blocked' do

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe EncryptedMessage, type: :model do
RSpec.describe EncryptedMessage do
end

View File

@ -10,7 +10,7 @@ describe Export do
describe 'to_csv' do
it 'returns a csv of the blocked accounts' do
target_accounts.each(&account.method(:block!))
target_accounts.each { |target_account| account.block!(target_account) }
export = Export.new(account).to_blocked_accounts_csv
results = export.strip.split
@ -20,7 +20,7 @@ describe Export do
end
it 'returns a csv of the muted accounts' do
target_accounts.each(&account.method(:mute!))
target_accounts.each { |target_account| account.mute!(target_account) }
export = Export.new(account).to_muted_accounts_csv
results = export.strip.split("\n")
@ -31,7 +31,7 @@ describe Export do
end
it 'returns a csv of the following accounts' do
target_accounts.each(&account.method(:follow!))
target_accounts.each { |target_account| account.follow!(target_account) }
export = Export.new(account).to_following_accounts_csv
results = export.strip.split("\n")
@ -51,17 +51,17 @@ describe Export do
describe 'total_follows' do
it 'returns the total number of the followed accounts' do
target_accounts.each(&account.method(:follow!))
target_accounts.each { |target_account| account.follow!(target_account) }
expect(Export.new(account.reload).total_follows).to eq 2
end
it 'returns the total number of the blocked accounts' do
target_accounts.each(&account.method(:block!))
target_accounts.each { |target_account| account.block!(target_account) }
expect(Export.new(account.reload).total_blocks).to eq 2
end
it 'returns the total number of the muted accounts' do
target_accounts.each(&account.method(:mute!))
target_accounts.each { |target_account| account.mute!(target_account) }
expect(Export.new(account.reload).total_mutes).to eq 2
end
end

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe Favourite, type: :model do
RSpec.describe Favourite do
let(:account) { Fabricate(:account) }
context 'when status is a reblog' do

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe FeaturedTag, type: :model do
RSpec.describe FeaturedTag do
end

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe FollowRecommendationSuppression, type: :model do
RSpec.describe FollowRecommendationSuppression do
end

View File

@ -2,15 +2,29 @@
require 'rails_helper'
RSpec.describe FollowRequest, type: :model do
RSpec.describe FollowRequest do
describe '#authorize!' do
let(:follow_request) { Fabricate(:follow_request, account: account, target_account: target_account) }
let(:account) { Fabricate(:account) }
let(:target_account) { Fabricate(:account) }
let!(:follow_request) { Fabricate(:follow_request, account: account, target_account: target_account) }
let(:account) { Fabricate(:account) }
let(:target_account) { Fabricate(:account) }
context 'when the to-be-followed person has been added to a list' do
let!(:list) { Fabricate(:list, account: account) }
before do
list.accounts << target_account
end
it 'updates the ListAccount' do
expect { follow_request.authorize! }.to change { [list.list_accounts.first.follow_request_id, list.list_accounts.first.follow_id] }.from([follow_request.id, nil]).to([nil, anything])
end
end
it 'calls Account#follow!, MergeWorker.perform_async, and #destroy!' do
expect(account).to receive(:follow!).with(target_account, reblogs: true, notify: false, uri: follow_request.uri, languages: nil, bypass_limit: true)
expect(MergeWorker).to receive(:perform_async).with(target_account.id, account.id)
expect(account).to receive(:follow!).with(target_account, reblogs: true, notify: false, uri: follow_request.uri, languages: nil, bypass_limit: true) do
account.active_relationships.create!(target_account: target_account)
end
expect(MergeWorker).to receive(:perform_async).with(target_account.id, account.id)
expect(follow_request).to receive(:destroy!)
follow_request.authorize!
end
@ -36,4 +50,22 @@ RSpec.describe FollowRequest, type: :model do
expect(follow_request.account.muting_reblogs?(target)).to be true
end
end
describe '#reject!' do
let!(:follow_request) { Fabricate(:follow_request, account: account, target_account: target_account) }
let(:account) { Fabricate(:account) }
let(:target_account) { Fabricate(:account) }
context 'when the to-be-followed person has been added to a list' do
let!(:list) { Fabricate(:list, account: account) }
before do
list.accounts << target_account
end
it 'deletes the ListAccount record' do
expect { follow_request.reject! }.to change { list.accounts.count }.from(1).to(0)
end
end
end
end

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe Follow, type: :model do
RSpec.describe Follow do
let(:alice) { Fabricate(:account, username: 'alice') }
let(:bob) { Fabricate(:account, username: 'bob') }

View File

@ -0,0 +1,281 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Form::Import do
subject { described_class.new(current_account: account, type: import_type, mode: import_mode, data: data) }
let(:account) { Fabricate(:account) }
let(:data) { fixture_file_upload(import_file) }
let(:import_mode) { 'merge' }
describe 'validations' do
shared_examples 'incompatible import type' do |type, file|
let(:import_file) { file }
let(:import_type) { type }
it 'has errors' do
subject.validate
expect(subject.errors[:data]).to include(I18n.t('imports.errors.incompatible_type'))
end
end
shared_examples 'too many CSV rows' do |type, file, allowed_rows|
let(:import_file) { file }
let(:import_type) { type }
before do
stub_const 'Form::Import::ROWS_PROCESSING_LIMIT', allowed_rows
end
it 'has errors' do
subject.validate
expect(subject.errors[:data]).to include(I18n.t('imports.errors.over_rows_processing_limit', count: Form::Import::ROWS_PROCESSING_LIMIT))
end
end
shared_examples 'valid import' do |type, file|
let(:import_file) { file }
let(:import_type) { type }
it 'passes validation' do
expect(subject).to be_valid
end
end
context 'when the file too large' do
let(:import_type) { 'following' }
let(:import_file) { 'imports.txt' }
before do
stub_const 'Form::Import::FILE_SIZE_LIMIT', 5
end
it 'has errors' do
subject.validate
expect(subject.errors[:data]).to include(I18n.t('imports.errors.too_large'))
end
end
context 'when the CSV file is malformed CSV' do
let(:import_type) { 'following' }
let(:import_file) { 'boop.ogg' }
it 'has errors' do
# NOTE: not testing more specific error because we don't know the string to match
expect(subject).to model_have_error_on_field(:data)
end
end
context 'when importing more follows than allowed' do
let(:import_type) { 'following' }
let(:import_file) { 'imports.txt' }
before do
allow(FollowLimitValidator).to receive(:limit_for_account).with(account).and_return(1)
end
it 'has errors' do
subject.validate
expect(subject.errors[:data]).to include(I18n.t('users.follow_limit_reached', limit: 1))
end
end
it_behaves_like 'too many CSV rows', 'following', 'imports.txt', 1
it_behaves_like 'too many CSV rows', 'blocking', 'imports.txt', 1
it_behaves_like 'too many CSV rows', 'muting', 'imports.txt', 1
it_behaves_like 'too many CSV rows', 'domain_blocking', 'domain_blocks.csv', 2
it_behaves_like 'too many CSV rows', 'bookmarks', 'bookmark-imports.txt', 3
# Importing list of addresses with no headers into various types
it_behaves_like 'valid import', 'following', 'imports.txt'
it_behaves_like 'valid import', 'blocking', 'imports.txt'
it_behaves_like 'valid import', 'muting', 'imports.txt'
# Importing domain blocks with headers into expected type
it_behaves_like 'valid import', 'domain_blocking', 'domain_blocks.csv'
# Importing bookmarks list with no headers into expected type
it_behaves_like 'valid import', 'bookmarks', 'bookmark-imports.txt'
# Importing followed accounts with headers into various compatible types
it_behaves_like 'valid import', 'following', 'following_accounts.csv'
it_behaves_like 'valid import', 'blocking', 'following_accounts.csv'
it_behaves_like 'valid import', 'muting', 'following_accounts.csv'
# Importing domain blocks with headers into incompatible types
it_behaves_like 'incompatible import type', 'following', 'domain_blocks.csv'
it_behaves_like 'incompatible import type', 'blocking', 'domain_blocks.csv'
it_behaves_like 'incompatible import type', 'muting', 'domain_blocks.csv'
it_behaves_like 'incompatible import type', 'bookmarks', 'domain_blocks.csv'
# Importing followed accounts with headers into incompatible types
it_behaves_like 'incompatible import type', 'domain_blocking', 'following_accounts.csv'
it_behaves_like 'incompatible import type', 'bookmarks', 'following_accounts.csv'
end
describe '#guessed_type' do
shared_examples 'with enough information' do |type, file, original_filename, expected_guess|
let(:import_file) { file }
let(:import_type) { type }
before do
allow(data).to receive(:original_filename).and_return(original_filename)
end
it 'guesses the expected type' do
expect(subject.guessed_type).to eq expected_guess
end
end
context 'when the headers are enough to disambiguate' do
it_behaves_like 'with enough information', 'following', 'following_accounts.csv', 'import.csv', :following
it_behaves_like 'with enough information', 'blocking', 'following_accounts.csv', 'import.csv', :following
it_behaves_like 'with enough information', 'muting', 'following_accounts.csv', 'import.csv', :following
it_behaves_like 'with enough information', 'following', 'muted_accounts.csv', 'imports.csv', :muting
it_behaves_like 'with enough information', 'blocking', 'muted_accounts.csv', 'imports.csv', :muting
it_behaves_like 'with enough information', 'muting', 'muted_accounts.csv', 'imports.csv', :muting
end
context 'when the file name is enough to disambiguate' do
it_behaves_like 'with enough information', 'following', 'imports.txt', 'following_accounts.csv', :following
it_behaves_like 'with enough information', 'blocking', 'imports.txt', 'following_accounts.csv', :following
it_behaves_like 'with enough information', 'muting', 'imports.txt', 'following_accounts.csv', :following
it_behaves_like 'with enough information', 'following', 'imports.txt', 'follows.csv', :following
it_behaves_like 'with enough information', 'blocking', 'imports.txt', 'follows.csv', :following
it_behaves_like 'with enough information', 'muting', 'imports.txt', 'follows.csv', :following
it_behaves_like 'with enough information', 'following', 'imports.txt', 'blocked_accounts.csv', :blocking
it_behaves_like 'with enough information', 'blocking', 'imports.txt', 'blocked_accounts.csv', :blocking
it_behaves_like 'with enough information', 'muting', 'imports.txt', 'blocked_accounts.csv', :blocking
it_behaves_like 'with enough information', 'following', 'imports.txt', 'blocks.csv', :blocking
it_behaves_like 'with enough information', 'blocking', 'imports.txt', 'blocks.csv', :blocking
it_behaves_like 'with enough information', 'muting', 'imports.txt', 'blocks.csv', :blocking
it_behaves_like 'with enough information', 'following', 'imports.txt', 'muted_accounts.csv', :muting
it_behaves_like 'with enough information', 'blocking', 'imports.txt', 'muted_accounts.csv', :muting
it_behaves_like 'with enough information', 'muting', 'imports.txt', 'muted_accounts.csv', :muting
it_behaves_like 'with enough information', 'following', 'imports.txt', 'mutes.csv', :muting
it_behaves_like 'with enough information', 'blocking', 'imports.txt', 'mutes.csv', :muting
it_behaves_like 'with enough information', 'muting', 'imports.txt', 'mutes.csv', :muting
end
end
describe '#likely_mismatched?' do
shared_examples 'with matching types' do |type, file, original_filename = nil|
let(:import_file) { file }
let(:import_type) { type }
before do
allow(data).to receive(:original_filename).and_return(original_filename) if original_filename.present?
end
it 'returns false' do
expect(subject.likely_mismatched?).to be false
end
end
shared_examples 'with mismatching types' do |type, file, original_filename = nil|
let(:import_file) { file }
let(:import_type) { type }
before do
allow(data).to receive(:original_filename).and_return(original_filename) if original_filename.present?
end
it 'returns true' do
expect(subject.likely_mismatched?).to be true
end
end
it_behaves_like 'with matching types', 'following', 'following_accounts.csv'
it_behaves_like 'with matching types', 'following', 'following_accounts.csv', 'imports.txt'
it_behaves_like 'with matching types', 'following', 'imports.txt'
it_behaves_like 'with matching types', 'blocking', 'imports.txt', 'blocks.csv'
it_behaves_like 'with matching types', 'blocking', 'imports.txt'
it_behaves_like 'with matching types', 'muting', 'muted_accounts.csv'
it_behaves_like 'with matching types', 'muting', 'muted_accounts.csv', 'imports.txt'
it_behaves_like 'with matching types', 'muting', 'imports.txt'
it_behaves_like 'with matching types', 'domain_blocking', 'domain_blocks.csv'
it_behaves_like 'with matching types', 'domain_blocking', 'domain_blocks.csv', 'imports.txt'
it_behaves_like 'with matching types', 'bookmarks', 'bookmark-imports.txt'
it_behaves_like 'with matching types', 'bookmarks', 'bookmark-imports.txt', 'imports.txt'
it_behaves_like 'with mismatching types', 'following', 'imports.txt', 'blocks.csv'
it_behaves_like 'with mismatching types', 'following', 'imports.txt', 'blocked_accounts.csv'
it_behaves_like 'with mismatching types', 'following', 'imports.txt', 'mutes.csv'
it_behaves_like 'with mismatching types', 'following', 'imports.txt', 'muted_accounts.csv'
it_behaves_like 'with mismatching types', 'following', 'muted_accounts.csv'
it_behaves_like 'with mismatching types', 'following', 'muted_accounts.csv', 'imports.txt'
it_behaves_like 'with mismatching types', 'blocking', 'following_accounts.csv'
it_behaves_like 'with mismatching types', 'blocking', 'following_accounts.csv', 'imports.txt'
it_behaves_like 'with mismatching types', 'blocking', 'muted_accounts.csv'
it_behaves_like 'with mismatching types', 'blocking', 'muted_accounts.csv', 'imports.txt'
it_behaves_like 'with mismatching types', 'blocking', 'imports.txt', 'follows.csv'
it_behaves_like 'with mismatching types', 'blocking', 'imports.txt', 'following_accounts.csv'
it_behaves_like 'with mismatching types', 'blocking', 'imports.txt', 'mutes.csv'
it_behaves_like 'with mismatching types', 'blocking', 'imports.txt', 'muted_accounts.csv'
it_behaves_like 'with mismatching types', 'muting', 'following_accounts.csv'
it_behaves_like 'with mismatching types', 'muting', 'following_accounts.csv', 'imports.txt'
it_behaves_like 'with mismatching types', 'muting', 'imports.txt', 'follows.csv'
it_behaves_like 'with mismatching types', 'muting', 'imports.txt', 'following_accounts.csv'
it_behaves_like 'with mismatching types', 'muting', 'imports.txt', 'blocks.csv'
it_behaves_like 'with mismatching types', 'muting', 'imports.txt', 'blocked_accounts.csv'
end
describe 'save' do
shared_examples 'on successful import' do |type, mode, file, expected_rows|
let(:import_type) { type }
let(:import_file) { file }
let(:import_mode) { mode }
before do
subject.save
end
it 'creates the expected rows' do
expect(account.bulk_imports.first.rows.pluck(:data)).to match_array(expected_rows)
end
it 'creates a BulkImport with expected attributes' do
bulk_import = account.bulk_imports.first
expect(bulk_import).to_not be_nil
expect(bulk_import.type.to_sym).to eq subject.type.to_sym
expect(bulk_import.original_filename).to eq subject.data.original_filename
expect(bulk_import.likely_mismatched?).to eq subject.likely_mismatched?
expect(bulk_import.overwrite?).to eq !!subject.overwrite # rubocop:disable Style/DoubleNegation
expect(bulk_import.processed_items).to eq 0
expect(bulk_import.imported_items).to eq 0
expect(bulk_import.total_items).to eq bulk_import.rows.count
expect(bulk_import.unconfirmed?).to be true
end
end
it_behaves_like 'on successful import', 'following', 'merge', 'imports.txt', (%w(user@example.com user@test.com).map { |acct| { 'acct' => acct } })
it_behaves_like 'on successful import', 'following', 'overwrite', 'imports.txt', (%w(user@example.com user@test.com).map { |acct| { 'acct' => acct } })
it_behaves_like 'on successful import', 'blocking', 'merge', 'imports.txt', (%w(user@example.com user@test.com).map { |acct| { 'acct' => acct } })
it_behaves_like 'on successful import', 'blocking', 'overwrite', 'imports.txt', (%w(user@example.com user@test.com).map { |acct| { 'acct' => acct } })
it_behaves_like 'on successful import', 'muting', 'merge', 'imports.txt', (%w(user@example.com user@test.com).map { |acct| { 'acct' => acct } })
it_behaves_like 'on successful import', 'domain_blocking', 'merge', 'domain_blocks.csv', (%w(bad.domain worse.domain reject.media).map { |domain| { 'domain' => domain } })
it_behaves_like 'on successful import', 'bookmarks', 'merge', 'bookmark-imports.txt', (%w(https://example.com/statuses/1312 https://local.com/users/foo/statuses/42 https://unknown-remote.com/users/bar/statuses/1 https://example.com/statuses/direct).map { |uri| { 'uri' => uri } })
it_behaves_like 'on successful import', 'following', 'merge', 'following_accounts.csv', [
{ 'acct' => 'user@example.com', 'show_reblogs' => true, 'notify' => false, 'languages' => nil },
{ 'acct' => 'user@test.com', 'show_reblogs' => true, 'notify' => true, 'languages' => ['en', 'fr'] },
]
it_behaves_like 'on successful import', 'muting', 'merge', 'muted_accounts.csv', [
{ 'acct' => 'user@example.com', 'hide_notifications' => true },
{ 'acct' => 'user@test.com', 'hide_notifications' => false },
]
# Based on the bug report 20571 where UTF-8 encoded domains were rejecting import of their users
#
# https://github.com/mastodon/mastodon/issues/20571
it_behaves_like 'on successful import', 'following', 'merge', 'utf8-followers.txt', [{ 'acct' => 'nare@թութ.հայ' }]
end
end

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe HomeFeed, type: :model do
RSpec.describe HomeFeed do
subject { described_class.new(account) }
let(:account) { Fabricate(:account) }

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe Identity, type: :model do
RSpec.describe Identity do
describe '.find_for_oauth' do
let(:auth) { Fabricate(:identity, user: Fabricate(:user)) }

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe Import, type: :model do
RSpec.describe Import do
let(:account) { Fabricate(:account) }
let(:type) { 'following' }
let(:data) { attachment_fixture('imports.txt') }
@ -22,20 +22,5 @@ RSpec.describe Import, type: :model do
import = Import.create(account: account, type: type)
expect(import).to model_have_error_on_field(:data)
end
it 'is invalid with malformed data' do
import = Import.create(account: account, type: type, data: StringIO.new('\"test'))
expect(import).to model_have_error_on_field(:data)
end
it 'is invalid with too many rows in data' do
import = Import.create(account: account, type: type, data: StringIO.new("foo@bar.com\n" * (ImportService::ROWS_PROCESSING_LIMIT + 10)))
expect(import).to model_have_error_on_field(:data)
end
it 'is invalid when there are more rows when following limit' do
import = Import.create(account: account, type: type, data: StringIO.new("foo@bar.com\n" * (FollowLimitValidator.limit_for_account(account) + 10)))
expect(import).to model_have_error_on_field(:data)
end
end
end

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe Invite, type: :model do
RSpec.describe Invite do
describe '#valid_for_use?' do
it 'returns true when there are no limitations' do
invite = Fabricate(:invite, max_uses: nil, expires_at: nil)

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe ListAccount, type: :model do
RSpec.describe ListAccount do
end

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe List, type: :model do
RSpec.describe List do
end

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe LoginActivity, type: :model do
RSpec.describe LoginActivity do
end

View File

@ -2,13 +2,13 @@
require 'rails_helper'
RSpec.describe MediaAttachment, type: :model do
RSpec.describe MediaAttachment do
describe 'local?' do
subject { media_attachment.local? }
let(:media_attachment) { Fabricate(:media_attachment, remote_url: remote_url) }
context 'remote_url is blank' do
context 'when remote_url is blank' do
let(:remote_url) { '' }
it 'returns true' do
@ -16,7 +16,7 @@ RSpec.describe MediaAttachment, type: :model do
end
end
context 'remote_url is present' do
context 'when remote_url is present' do
let(:remote_url) { 'remote_url' }
it 'returns false' do
@ -30,10 +30,10 @@ RSpec.describe MediaAttachment, type: :model do
let(:media_attachment) { Fabricate(:media_attachment, remote_url: remote_url, file: file) }
context 'file is blank' do
context 'when file is blank' do
let(:file) { nil }
context 'remote_url is present' do
context 'when remote_url is present' do
let(:remote_url) { 'remote_url' }
it 'returns true' do
@ -42,10 +42,10 @@ RSpec.describe MediaAttachment, type: :model do
end
end
context 'file is present' do
context 'when file is present' do
let(:file) { attachment_fixture('avatar.gif') }
context 'remote_url is blank' do
context 'when remote_url is blank' do
let(:remote_url) { '' }
it 'returns false' do
@ -53,7 +53,7 @@ RSpec.describe MediaAttachment, type: :model do
end
end
context 'remote_url is present' do
context 'when remote_url is present' do
let(:remote_url) { 'remote_url' }
it 'returns true' do

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe Mention, type: :model do
RSpec.describe Mention do
describe 'validations' do
it 'is invalid without an account' do
mention = Fabricate.build(:mention, account: nil)

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe Mute, type: :model do
RSpec.describe Mute do
end

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe Notification, type: :model do
RSpec.describe Notification do
describe '#target_status' do
let(:notification) { Fabricate(:notification, activity: activity) }
let(:status) { Fabricate(:status) }
@ -10,7 +10,7 @@ RSpec.describe Notification, type: :model do
let(:favourite) { Fabricate(:favourite, status: status) }
let(:mention) { Fabricate(:mention, status: status) }
context 'activity is reblog' do
context 'when Activity is reblog' do
let(:activity) { reblog }
it 'returns status' do
@ -18,7 +18,7 @@ RSpec.describe Notification, type: :model do
end
end
context 'activity is favourite' do
context 'when Activity is favourite' do
let(:type) { :favourite }
let(:activity) { favourite }
@ -27,7 +27,7 @@ RSpec.describe Notification, type: :model do
end
end
context 'activity is mention' do
context 'when Activity is mention' do
let(:activity) { mention }
it 'returns status' do
@ -66,7 +66,7 @@ RSpec.describe Notification, type: :model do
end
end
context 'notifications are empty' do
context 'when notifications are empty' do
let(:notifications) { [] }
it 'returns []' do
@ -74,7 +74,7 @@ RSpec.describe Notification, type: :model do
end
end
context 'notifications are present' do
context 'when notifications are present' do
before do
notifications.each(&:reload)
end

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe PollVote, type: :model do
RSpec.describe PollVote do
describe '#object_type' do
let(:poll_vote) { Fabricate.build(:poll_vote) }

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe PreviewCard, type: :model do
RSpec.describe PreviewCard do
end

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe PreviewCardTrend, type: :model do
RSpec.describe PreviewCardTrend do
end

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe PublicFeed, type: :model do
RSpec.describe PublicFeed do
let(:account) { Fabricate(:account) }
describe '#get' do

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe Relay, type: :model do
RSpec.describe Relay do
end

View File

@ -13,7 +13,7 @@ RSpec.describe RemoteFollow do
describe '.initialize' do
subject { remote_follow.acct }
context 'attrs with acct' do
context 'when attrs with acct' do
let(:attrs) { { acct: 'gargron@quitter.no' } }
it 'returns acct' do
@ -21,7 +21,7 @@ RSpec.describe RemoteFollow do
end
end
context 'attrs without acct' do
context 'when attrs without acct' do
let(:attrs) { {} }
it do
@ -33,7 +33,7 @@ RSpec.describe RemoteFollow do
describe '#valid?' do
subject { remote_follow.valid? }
context 'attrs with acct' do
context 'when attrs with acct' do
let(:attrs) { { acct: 'gargron@quitter.no' } }
it do
@ -41,7 +41,7 @@ RSpec.describe RemoteFollow do
end
end
context 'attrs without acct' do
context 'when attrs without acct' do
let(:attrs) { {} }
it do

View File

@ -89,13 +89,13 @@ describe Report do
let(:report) { Fabricate(:report, action_taken_at: action_taken) }
context 'if action is taken' do
context 'when action is taken' do
let(:action_taken) { Time.now.utc }
it { is_expected.to be false }
end
context 'if action not is taken' do
context 'when action not is taken' do
let(:action_taken) { nil }
it { is_expected.to be true }

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe ScheduledStatus, type: :model do
RSpec.describe ScheduledStatus do
end

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe SessionActivation, type: :model do
RSpec.describe SessionActivation do
describe '#detection' do
let(:session_activation) { Fabricate(:session_activation, user_agent: 'Chrome/62.0.3202.89') }
@ -40,7 +40,7 @@ RSpec.describe SessionActivation, type: :model do
describe '.active?' do
subject { described_class.active?(id) }
context 'id is absent' do
context 'when id is absent' do
let(:id) { nil }
it 'returns nil' do
@ -48,17 +48,17 @@ RSpec.describe SessionActivation, type: :model do
end
end
context 'id is present' do
context 'when id is present' do
let(:id) { '1' }
let!(:session_activation) { Fabricate(:session_activation, session_id: id) }
context 'id exists as session_id' do
context 'when id exists as session_id' do
it 'returns true' do
expect(subject).to be true
end
end
context 'id does not exist as session_id' do
context 'when id does not exist as session_id' do
before do
session_activation.update!(session_id: '2')
end
@ -85,7 +85,7 @@ RSpec.describe SessionActivation, type: :model do
end
describe '.deactivate' do
context 'id is absent' do
context 'when id is absent' do
let(:id) { nil }
it 'returns nil' do
@ -93,7 +93,7 @@ RSpec.describe SessionActivation, type: :model do
end
end
context 'id exists' do
context 'when id exists' do
let(:id) { '1' }
it 'calls where.destroy_all' do

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe Setting, type: :model do
RSpec.describe Setting do
describe '#to_param' do
let(:setting) { Fabricate(:setting, var: var) }
let(:var) { 'var' }
@ -19,7 +19,7 @@ RSpec.describe Setting, type: :model do
let(:key) { 'key' }
context 'rails_initialized? is falsey' do
context 'when rails_initialized? is falsey' do
let(:rails_initialized) { false }
it 'calls RailsSettings::Base#[]' do
@ -28,7 +28,7 @@ RSpec.describe Setting, type: :model do
end
end
context 'rails_initialized? is truthy' do
context 'when rails_initialized? is truthy' do
before do
allow(RailsSettings::Base).to receive(:cache_key).with(key, nil).and_return(cache_key)
end
@ -42,7 +42,7 @@ RSpec.describe Setting, type: :model do
described_class[key]
end
context 'Rails.cache does not exists' do
context 'when Rails.cache does not exists' do
before do
allow(RailsSettings::Settings).to receive(:object).with(key).and_return(object)
allow(described_class).to receive(:default_settings).and_return(default_settings)
@ -60,11 +60,11 @@ RSpec.describe Setting, type: :model do
described_class[key]
end
context 'RailsSettings::Settings.object returns truthy' do
context 'when RailsSettings::Settings.object returns truthy' do
let(:object) { db_val }
let(:db_val) { double(value: 'db_val') }
context 'default_value is a Hash' do
context 'when default_value is a Hash' do
let(:default_value) { { default_value: 'default_value' } }
it 'calls default_value.with_indifferent_access.merge!' do
@ -75,7 +75,7 @@ RSpec.describe Setting, type: :model do
end
end
context 'default_value is not a Hash' do
context 'when default_value is not a Hash' do
let(:default_value) { 'default_value' }
it 'returns db_val.value' do
@ -84,7 +84,7 @@ RSpec.describe Setting, type: :model do
end
end
context 'RailsSettings::Settings.object returns falsey' do
context 'when RailsSettings::Settings.object returns falsey' do
let(:object) { nil }
it 'returns default_settings[key]' do
@ -93,7 +93,7 @@ RSpec.describe Setting, type: :model do
end
end
context 'Rails.cache exists' do
context 'when Rails.cache exists' do
before do
Rails.cache.write(cache_key, cache_value)
end
@ -130,7 +130,7 @@ RSpec.describe Setting, type: :model do
expect(described_class.all_as_records).to be_a Hash
end
context 'records includes Setting with var as the key' do
context 'when records includes Setting with var as the key' do
let(:records) { [original_setting] }
it 'includes the original Setting' do
@ -139,10 +139,10 @@ RSpec.describe Setting, type: :model do
end
end
context 'records includes nothing' do
context 'when records includes nothing' do
let(:records) { [] }
context 'default_value is not a Hash' do
context 'when default_value is not a Hash' do
it 'includes Setting with value of default_value' do
setting = described_class.all_as_records[key]
@ -152,7 +152,7 @@ RSpec.describe Setting, type: :model do
end
end
context 'default_value is a Hash' do
context 'when default_value is a Hash' do
let(:default_value) { { 'foo' => 'fuga' } }
it 'returns {}' do
@ -169,7 +169,7 @@ RSpec.describe Setting, type: :model do
allow(RailsSettings::Default).to receive(:enabled?).and_return(enabled)
end
context 'RailsSettings::Default.enabled? is false' do
context 'when RailsSettings::Default.enabled? is false' do
let(:enabled) { false }
it 'returns {}' do
@ -177,7 +177,7 @@ RSpec.describe Setting, type: :model do
end
end
context 'RailsSettings::Settings.enabled? is true' do
context 'when RailsSettings::Settings.enabled? is true' do
let(:enabled) { true }
it 'returns instance of RailsSettings::Default' do

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe SiteUpload, type: :model do
RSpec.describe SiteUpload do
describe '#cache_key' do
let(:site_upload) { SiteUpload.new(var: 'var') }

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe StatusPin, type: :model do
RSpec.describe StatusPin do
describe 'validations' do
it 'allows pins of own statuses' do
account = Fabricate(:account)

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe Status, type: :model do
RSpec.describe Status do
subject { Fabricate(:status, account: alice) }
let(:alice) { Fabricate(:account, username: 'alice') }
@ -49,22 +49,22 @@ RSpec.describe Status, type: :model do
end
describe '#verb' do
context 'if destroyed?' do
context 'when destroyed?' do
it 'returns :delete' do
subject.destroy!
expect(subject.verb).to be :delete
end
end
context 'unless destroyed?' do
context 'if reblog?' do
context 'when not destroyed?' do
context 'when reblog?' do
it 'returns :share' do
subject.reblog = other
expect(subject.verb).to be :share
end
end
context 'unless reblog?' do
context 'when not reblog?' do
it 'returns :post' do
subject.reblog = nil
expect(subject.verb).to be :post
@ -85,28 +85,28 @@ RSpec.describe Status, type: :model do
end
describe '#hidden?' do
context 'if private_visibility?' do
context 'when private_visibility?' do
it 'returns true' do
subject.visibility = :private
expect(subject.hidden?).to be true
end
end
context 'if direct_visibility?' do
context 'when direct_visibility?' do
it 'returns true' do
subject.visibility = :direct
expect(subject.hidden?).to be true
end
end
context 'if public_visibility?' do
context 'when public_visibility?' do
it 'returns false' do
subject.visibility = :public
expect(subject.hidden?).to be false
end
end
context 'if unlisted_visibility?' do
context 'when unlisted_visibility?' do
it 'returns false' do
subject.visibility = :unlisted
expect(subject.hidden?).to be false

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe StatusStat, type: :model do
RSpec.describe StatusStat do
end

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe StatusTrend, type: :model do
RSpec.describe StatusTrend do
end

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe SystemKey, type: :model do
RSpec.describe SystemKey do
end

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe TagFollow, type: :model do
RSpec.describe TagFollow do
end

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe UnavailableDomain, type: :model do
RSpec.describe UnavailableDomain do
end

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe UserInviteRequest, type: :model do
RSpec.describe UserInviteRequest do
end

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe UserRole, type: :model do
RSpec.describe UserRole do
subject { described_class.create(name: 'Foo', position: 1) }
describe '#can?' do

View File

@ -3,7 +3,7 @@
require 'rails_helper'
require 'devise_two_factor/spec_helpers'
RSpec.describe User, type: :model do
RSpec.describe User do
let(:password) { 'abcd1234' }
let(:account) { Fabricate(:account, username: 'alice') }

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe Web::PushSubscription, type: :model do
RSpec.describe Web::PushSubscription do
subject { described_class.new(data: data) }
let(:account) { Fabricate(:account) }
@ -56,7 +56,7 @@ RSpec.describe Web::PushSubscription, type: :model do
context 'when policy is followed' do
let(:policy) { 'followed' }
context 'and notification is from someone you follow' do
context 'when notification is from someone you follow' do
before do
account.follow!(notification.from_account)
end
@ -66,7 +66,7 @@ RSpec.describe Web::PushSubscription, type: :model do
end
end
context 'and notification is not from someone you follow' do
context 'when notification is not from someone you follow' do
it 'returns false' do
expect(subject.pushable?(notification)).to be false
end
@ -76,7 +76,7 @@ RSpec.describe Web::PushSubscription, type: :model do
context 'when policy is follower' do
let(:policy) { 'follower' }
context 'and notification is from someone who follows you' do
context 'when notification is from someone who follows you' do
before do
notification.from_account.follow!(account)
end
@ -86,7 +86,7 @@ RSpec.describe Web::PushSubscription, type: :model do
end
end
context 'and notification is not from someone who follows you' do
context 'when notification is not from someone who follows you' do
it 'returns false' do
expect(subject.pushable?(notification)).to be false
end

View File

@ -2,5 +2,5 @@
require 'rails_helper'
RSpec.describe Web::Setting, type: :model do
RSpec.describe Web::Setting do
end

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe WebauthnCredential, type: :model do
RSpec.describe WebauthnCredential do
describe 'validations' do
it 'is invalid without an external id' do
webauthn_credential = Fabricate.build(:webauthn_credential, external_id: nil)

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe Webhook, type: :model do
RSpec.describe Webhook do
let(:webhook) { Fabricate(:webhook) }
describe '#rotate_secret!' do