Basic working with ships partly implimented

This commit is contained in:
2026-01-07 23:11:46 -07:00
parent 1ec24fbf12
commit 6e914467ed
49 changed files with 2079 additions and 220 deletions
+295
View File
@@ -0,0 +1,295 @@
# 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')
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' => subject.player_planets,
'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