Files
space_game_server/spec/game/player_spec.rb
T

296 lines
8.8 KiB
Ruby
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Nathan Hinton 24 Dec 2025
# spec/player_spec.rb
require 'rspec'
require 'json'
require 'game/player' # adjust the path if needed
RSpec.describe Player do
let(:player_id) { SecureRandom.uuid }
subject(:player) { Player.new(player_id, 'good') }
# ------------------------------------------------------------------
# Helpers / setup
# ------------------------------------------------------------------
before(:all) do
Dir.mkdir('game_data') unless Dir.exist?('game_data')
end
after(:each) do
# Clean up any save file that might have been created
save_file = File.join('game_data', "#{player_id}.save")
File.delete(save_file) if File.exist?(save_file)
end
# ------------------------------------------------------------------
# initialize
# ------------------------------------------------------------------
describe '#initialize' do
it 'sets the id and empty arrays for planets and ships' do
expect(subject.player_id).to eq(player_id)
expect(subject.player_planets).to be_empty
expect(subject.player_ships).to be_empty
expect(subject.instance_variable_get(:@home_planet)).to be_nil
end
it 'sets the faction correctly' do
subject = Player.new(player_id, 'good')
expect(subject.faction).to eq('good')
subject = Player.new(player_id, 'evil')
expect(subject.faction).to eq('evil')
end
it 'raises errors when the faction does not match' do
expect{subject = Player.new(player_id, 'billy_bob_jo')}.to raise_error(PlayerError, 'Faction must be `good` or `evil`')
end
end
# ------------------------------------------------------------------
# create_new
# ------------------------------------------------------------------
describe '#create_new' do
let(:credits) { 1000 }
let(:metal) { 500 }
let(:crystals) { 200 }
let(:fuel) { 300 }
it 'stores the resources hash correctly' do
subject.create_new(credits, metal, crystals, fuel)
expect(subject.player_resources).to eq(
'credits' => credits,
'metal' => metal,
'crystals' => crystals,
'fuel' => fuel
)
end
end
# ------------------------------------------------------------------
# connect / connected?
# ------------------------------------------------------------------
describe '#connect and #connected?' do
let(:socket) { instance_double('TCPSocket', closed?: false, puts: nil) }
it 'stores the socket' do
subject.connect(socket)
expect(subject.instance_variable_get(:@socket)).to eq(socket)
end
context 'when the socket is nil' do
it 'returns false' do
subject.instance_variable_set(:@socket, nil)
expect(subject.connected?).to be false
end
end
context 'when the socket is closed' do
before do
allow(socket).to receive(:closed?).and_return(true)
subject.connect(socket)
end
it 'returns false' do
expect(subject.connected?).to be false
end
end
context 'when the socket is open' do
before { subject.connect(socket) }
it 'returns true' do
expect(subject.connected?).to be true
end
end
end
# ------------------------------------------------------------------
# claim_planet
# ------------------------------------------------------------------
describe '#claim_planet' do
let(:planet) { double('planet', claimable?: true, owner: nil) }
context 'when the planet is claimable' do
it 'adds the planet to the player and calls claim on the planet' do
expect(planet).to receive(:claim).with(subject)
subject.claim_planet(planet)
expect(subject.player_planets).to include(planet)
end
end
context 'when the planet is not claimable' do
before { allow(planet).to receive(:claimable?).and_return(false) }
it 'does nothing' do
expect(planet).not_to receive(:claim)
subject.claim_planet(planet)
expect(subject.player_planets).not_to include(planet)
end
end
end
# ------------------------------------------------------------------
# make_home_planet
# ------------------------------------------------------------------
describe '#make_home_planet' do
context 'when the player owns the planet' do
let(:planet) { double('planet', owner: subject) }
it 'sets the home planet' do
subject.make_home_planet(planet)
expect(subject.instance_variable_get(:@home_planet)).to eq(planet)
end
end
context 'when the player does NOT own the planet' do
let(:planet) { double('planet', owner: nil) }
it 'returns an error hash' do
result = subject.make_home_planet(planet)
expect(result).to eq(
'type' => 'error',
'payload' => 'Planet must be owned by the player'
)
end
end
end
# ------------------------------------------------------------------
# update
# ------------------------------------------------------------------
describe '#update' do
let(:credits) { 1000 }
let(:metal) { 500 }
let(:crystals) { 200 }
let(:fuel) { 300 }
let(:request_id) { 42 }
before do
subject.create_new(credits, metal, crystals, fuel)
subject.player_planets << double('planet', info_update: 'test_data')
subject.player_ships << double('ship')
end
it 'returns a hash in the expected format' do
expected = {
'type' => 'update',
'domain' => 'player',
'request_id' => request_id,
'payload' => {
'resources' => subject.player_resources,
'planets' => ['test_data'],
'ships' => subject.player_ships
}
}
expect(subject.update(request_id)).to eq(expected)
end
end
# ------------------------------------------------------------------
# send_update
# ------------------------------------------------------------------
describe '#send_update' do
let(:socket) { instance_double('TCPSocket', closed?: false, puts: nil) }
before { subject.connect(socket) }
context 'when connected' do
it 'sends the update JSON' do
expect(socket).to receive(:puts).with(kind_of(String))
subject.send_update
end
end
context 'when not connected' do
before { subject.instance_variable_set(:@socket, nil) }
it 'does nothing' do
expect { subject.send_update }.not_to raise_error
end
end
context 'when socket.puts raises an exception' do
before do
allow(socket).to receive(:puts).and_raise(StandardError)
allow(socket).to receive(:close)
end
it 'closes the socket' do
expect(socket).to receive(:close)
subject.send_update
end
end
end
# ------------------------------------------------------------------
# save_to_file / load_from_save
# ------------------------------------------------------------------
describe 'file persistence' do
let(:credits) { 1000 }
let(:metal) { 500 }
let(:crystals) { 200 }
let(:fuel) { 300 }
before do
subject.create_new(credits, metal, crystals, fuel)
end
it 'writes a marshaled file and can read it back' do
file_id = subject.save_to_file
expect(file_id).to eq(player_id)
loaded_player = Player.load_from_save(player_id)
expect(loaded_player).to be_a(Player)
expect(loaded_player.player_id).to eq(player_id)
expect(loaded_player.player_resources).to eq(
'credits' => credits,
'metal' => metal,
'crystals' => crystals,
'fuel' => fuel
)
end
end
# ------------------------------------------------------------------
# marshal_dump / marshal_load
# ------------------------------------------------------------------
describe '#marshal_dump and #marshal_load' do
let(:credits) { 1000 }
let(:metal) { 500 }
let(:crystals) { 200 }
let(:fuel) { 300 }
before do
subject.create_new(credits, metal, crystals, fuel)
end
it 'returns a hash with the expected keys' do
dump = subject.marshal_dump
expect(dump).to include(
player_id: subject.player_id,
player_resources: subject.player_resources
)
end
it 'restores the player via marshal_load' do
dump = subject.marshal_dump
# Create a brandnew instance and load the dumped data
new_player = Player.new('dummy-id', 'good')
new_player.marshal_load(dump)
expect(new_player.player_id).to eq(subject.player_id)
expect(new_player.player_resources).to eq(subject.player_resources)
end
end
end# Nathan Hinton 24 Dec 2025
# Test file for the player
require 'game/player'
RSpec.describe Player do
describe '#initialize' do
it 'initializes with a player id' do
end
end
end