Skip to content

Commit

Permalink
chore: Add tests for address reputation
Browse files Browse the repository at this point in the history
This adds tests for the address reputation object as well as for
the usage of it within all of the address constructs.
  • Loading branch information
arpitsrivastava-cb authored and alex-stone committed Dec 13, 2024
1 parent cf426db commit 0e68bad
Show file tree
Hide file tree
Showing 8 changed files with 169 additions and 4 deletions.
5 changes: 1 addition & 4 deletions lib/coinbase/address_reputation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,7 @@ def reputation_api
end

def initialize(model)
unless model.is_a?(Coinbase::Client::AddressReputation)
raise ArgumentError,
'must be an AddressReputation client object'
end
raise ArgumentError, 'must be an AddressReputation object' unless model.is_a?(Coinbase::Client::AddressReputation)

@model = model
end
Expand Down
39 changes: 39 additions & 0 deletions spec/factories/address_reputation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# frozen_string_literal: true

FactoryBot.define do
factory :address_reputation_model, class: Coinbase::Client::AddressReputation do
score { 50 }
metadata do
{
total_transactions: 1,
unique_days_active: 1,
longest_active_streak: 1,
current_active_streak: 2,
activity_period_days: 3,
bridge_transactions_performed: 4,
lend_borrow_stake_transactions: 5,
ens_contract_interactions: 6,
smart_contract_deployments: 7,
token_swaps_performed: 8
}
end

initialize_with { new(attributes) }
end

factory :address_reputation, class: Coinbase::AddressReputation do
transient do
score { nil }
metadata { nil }

model do
build(
:address_reputation_model,
{ score: score, metadata: metadata }.compact
)
end
end

initialize_with { Coinbase::AddressReputation.new(model) }
end
end
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
require_relative 'support/shared_examples/address_staking'
require_relative 'support/shared_examples/address_transactions'
require_relative 'support/shared_examples/pagination'
require_relative 'support/shared_examples/address_reputation'

# Networks and Asset symbols used in our test factories.
NETWORK_TRAITS = %i[base_mainnet base_sepolia ethereum_holesky ethereum_mainnet].freeze
Expand Down
31 changes: 31 additions & 0 deletions spec/support/shared_examples/address_reputation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true

shared_examples 'an address that supports reputation' do
let(:score) { 50 }
let(:metadata) { { total_transactions: 10, unique_days_active: 42 } }
let(:address_reputation) { build(:address_reputation, score: score, metadata: metadata) }

before do
allow(Coinbase::AddressReputation).to receive(:fetch).and_return(address_reputation)
end

it 'fetches the address reputation from the API' do
expect(address.reputation).to be_a(Coinbase::AddressReputation)
end

it 'returns the reputation score' do
expect(address_reputation.score).to eq(score)
end

it 'returns metadata as a Metadata object' do
expect(address_reputation.metadata).to be_a(Coinbase::AddressReputation::Metadata)
end

it 'has correct metadata values for total transactions' do
expect(address_reputation.metadata.total_transactions).to eq(metadata[:total_transactions])
end

it 'has correct metadata values for unique days active' do
expect(address_reputation.metadata.unique_days_active).to eq(metadata[:unique_days_active])
end
end
1 change: 1 addition & 0 deletions spec/unit/coinbase/address/external_address_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@
it_behaves_like 'an address that supports requesting faucet funds'
it_behaves_like 'an address that supports transaction queries'
it_behaves_like 'an address that supports staking'
it_behaves_like 'an address that supports reputation'
end
1 change: 1 addition & 0 deletions spec/unit/coinbase/address/wallet_address_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
it_behaves_like 'an address that supports balance queries'
it_behaves_like 'an address that supports requesting faucet funds'
it_behaves_like 'an address that supports staking'
it_behaves_like 'an address that supports reputation'

describe '#invoke_contract' do
subject(:contract_invocation) do
Expand Down
94 changes: 94 additions & 0 deletions spec/unit/coinbase/address_reputation_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# frozen_string_literal: true

describe Coinbase::AddressReputation do
subject(:address_reputation) { described_class.new(model) }

let(:address_id) { '0x123456789abcdef' }
let(:network) { 'ethereum-mainnet' }
let(:score) { 50 }
let(:model) { build(:address_reputation_model, score: score) }

describe '.fetch' do
subject(:address_reputation) { described_class.fetch(address_id: address_id, network: network) }

let(:api_instance) { instance_double(Coinbase::Client::ReputationApi) }

before do
allow(Coinbase::Client::ReputationApi).to receive(:new).and_return(api_instance)
allow(api_instance).to receive(:get_address_reputation).and_return(model)

address_reputation
end

it 'fetches address reputation for the given network and address' do
expect(api_instance).to have_received(:get_address_reputation).with(network, address_id)
end

it 'returns an AddressReputation object' do
expect(address_reputation).to be_a(described_class)
end

it 'returns an object initialized with the correct model' do
expect(address_reputation.instance_variable_get(:@model)).to eq(model)
end

it 'raises an error if the API returns an invalid model' do
allow(api_instance).to receive(:get_address_reputation).and_return(nil)

expect do
described_class.fetch(address_id: address_id, network: network)
end.to raise_error(ArgumentError, 'must be an AddressReputation object')
end
end

describe '#score' do
it 'returns the reputation score' do
expect(address_reputation.score).to eq(score)
end
end

describe '#metadata' do
it 'returns a Metadata object' do
expect(address_reputation.metadata).to be_a(described_class::Metadata)
end

it 'initalizes the metadata object properly' do
model.metadata.all? do |key, value|
expect(address_reputation.metadata.send(key)).to eq(value)
end
end
end

describe '#risky?' do
context 'when the score is positive' do
let(:score) { 42 }

it 'returns false' do
expect(address_reputation).not_to be_risky
end
end

context 'when the score is negative' do
let(:score) { -10 }

it 'returns true' do
expect(address_reputation).to be_risky
end
end
end

describe '#to_s' do
it 'includes the score and the metadata details' do
expect(address_reputation.inspect).to include(
score.to_s,
*address_reputation.metadata.to_h.values.map(&:to_s)
)
end
end

describe '#inspect' do
it 'matches the output of #to_s' do
expect(address_reputation.inspect).to eq(address_reputation.to_s)
end
end
end
1 change: 1 addition & 0 deletions spec/unit/coinbase/address_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,5 @@
it_behaves_like 'an address that supports balance queries'
it_behaves_like 'an address that supports requesting faucet funds'
it_behaves_like 'an address that supports transaction queries'
it_behaves_like 'an address that supports reputation'
end

0 comments on commit 0e68bad

Please sign in to comment.