live_f1-core 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.autotest +23 -0
- data/.gitignore +6 -0
- data/.rspec +1 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +65 -0
- data/Guardfile +11 -0
- data/README.rdoc +62 -0
- data/Rakefile +11 -0
- data/bin/live_f1_example +74 -0
- data/features/fixtures/sessions/2012.03.china.qualifying/7136/keyframes.yaml +32722 -0
- data/features/fixtures/sessions/2012.03.china.qualifying/7136/session.key +1 -0
- data/features/fixtures/sessions/2012.03.china.qualifying/session.bin +0 -0
- data/features/fixtures/sessions/2012.04.bahrain.practice.2/7164/keyframes.yaml +22403 -0
- data/features/fixtures/sessions/2012.04.bahrain.practice.2/7164/session.key +1 -0
- data/features/fixtures/sessions/2012.04.bahrain.practice.2/session.bin +0 -0
- data/features/fixtures/sessions/2012.05.bahrain.race.post/7167/keyframes.yaml +1204 -0
- data/features/fixtures/sessions/2012.05.bahrain.race.post/7167/session.key +1 -0
- data/features/fixtures/sessions/2012.05.bahrain.race.post/session.bin +0 -0
- data/features/live_f1.feature +14 -0
- data/features/step_definitions/live_f1_steps.rb +69 -0
- data/features/support/env.rb +9 -0
- data/lib/live_f1/debug.rb +6 -0
- data/lib/live_f1/enum.rb +9 -0
- data/lib/live_f1/event.rb +23 -0
- data/lib/live_f1/packet/car/best_lap_time.rb +10 -0
- data/lib/live_f1/packet/car/driver.rb +14 -0
- data/lib/live_f1/packet/car/gap.rb +10 -0
- data/lib/live_f1/packet/car/interval.rb +10 -0
- data/lib/live_f1/packet/car/lap_count.rb +10 -0
- data/lib/live_f1/packet/car/lap_time.rb +10 -0
- data/lib/live_f1/packet/car/num_pits.rb +10 -0
- data/lib/live_f1/packet/car/number.rb +14 -0
- data/lib/live_f1/packet/car/period_1.rb +11 -0
- data/lib/live_f1/packet/car/period_2.rb +11 -0
- data/lib/live_f1/packet/car/period_3.rb +11 -0
- data/lib/live_f1/packet/car/pit_count.rb +18 -0
- data/lib/live_f1/packet/car/pit_lap_1.rb +10 -0
- data/lib/live_f1/packet/car/pit_lap_2.rb +10 -0
- data/lib/live_f1/packet/car/pit_lap_3.rb +10 -0
- data/lib/live_f1/packet/car/position.rb +14 -0
- data/lib/live_f1/packet/car/position_history.rb +14 -0
- data/lib/live_f1/packet/car/position_update.rb +13 -0
- data/lib/live_f1/packet/car/sector_1.rb +11 -0
- data/lib/live_f1/packet/car/sector_2.rb +11 -0
- data/lib/live_f1/packet/car/sector_3.rb +11 -0
- data/lib/live_f1/packet/car.rb +13 -0
- data/lib/live_f1/packet/decryptable.rb +22 -0
- data/lib/live_f1/packet/header.rb +127 -0
- data/lib/live_f1/packet/sector_time.rb +28 -0
- data/lib/live_f1/packet/sys/commentary.rb +33 -0
- data/lib/live_f1/packet/sys/copyright.rb +9 -0
- data/lib/live_f1/packet/sys/key_frame.rb +17 -0
- data/lib/live_f1/packet/sys/notice.rb +10 -0
- data/lib/live_f1/packet/sys/reset.rb +9 -0
- data/lib/live_f1/packet/sys/session_start.rb +25 -0
- data/lib/live_f1/packet/sys/speed.rb +29 -0
- data/lib/live_f1/packet/sys/timestamp.rb +23 -0
- data/lib/live_f1/packet/sys/track_status.rb +18 -0
- data/lib/live_f1/packet/sys/weather.rb +33 -0
- data/lib/live_f1/packet/sys.rb +10 -0
- data/lib/live_f1/packet.rb +129 -0
- data/lib/live_f1/source/keyframe.rb +30 -0
- data/lib/live_f1/source/live.rb +163 -0
- data/lib/live_f1/source/log.rb +29 -0
- data/lib/live_f1/source/session.rb +41 -0
- data/lib/live_f1/source.rb +83 -0
- data/lib/live_f1/version.rb +3 -0
- data/lib/live_f1.rb +32 -0
- data/live_f1-core.gemspec +26 -0
- data/spec/live_f1/event_spec.rb +5 -0
- data/spec/live_f1/packet/car/best_lap_time_spec.rb +19 -0
- data/spec/live_f1/packet/car/driver_spec.rb +20 -0
- data/spec/live_f1/packet/car/gap_spec.rb +20 -0
- data/spec/live_f1/packet/car/interval_spec.rb +20 -0
- data/spec/live_f1/packet/car/lap_count_spec.rb +20 -0
- data/spec/live_f1/packet/car/lap_time_spec.rb +20 -0
- data/spec/live_f1/packet/car/number_spec.rb +20 -0
- data/spec/live_f1/packet/car/period_1_spec.rb +21 -0
- data/spec/live_f1/packet/car/period_2_spec.rb +21 -0
- data/spec/live_f1/packet/car/period_3_spec.rb +21 -0
- data/spec/live_f1/packet/car/pit_count_spec.rb +20 -0
- data/spec/live_f1/packet/car/pit_lap_1_spec.rb +20 -0
- data/spec/live_f1/packet/car/pit_lap_2_spec.rb +20 -0
- data/spec/live_f1/packet/car/pit_lap_3_spec.rb +20 -0
- data/spec/live_f1/packet/car/position_history_spec.rb +20 -0
- data/spec/live_f1/packet/car/position_spec.rb +20 -0
- data/spec/live_f1/packet/car/position_update_spec.rb +19 -0
- data/spec/live_f1/packet/car/sector_1_spec.rb +21 -0
- data/spec/live_f1/packet/car/sector_2_spec.rb +21 -0
- data/spec/live_f1/packet/car/sector_3_spec.rb +21 -0
- data/spec/live_f1/packet/header_spec.rb +148 -0
- data/spec/live_f1/packet/sys/commentary_spec.rb +45 -0
- data/spec/live_f1/packet/sys/copyright_spec.rb +19 -0
- data/spec/live_f1/packet/sys/key_frame_spec.rb +39 -0
- data/spec/live_f1/packet/sys/notice_spec.rb +20 -0
- data/spec/live_f1/packet/sys/reset_spec.rb +26 -0
- data/spec/live_f1/packet/sys/session_start_spec.rb +31 -0
- data/spec/live_f1/packet/sys/speed_spec.rb +20 -0
- data/spec/live_f1/packet/sys/timestamp_spec.rb +34 -0
- data/spec/live_f1/packet/sys/track_status_spec.rb +20 -0
- data/spec/live_f1/packet/sys/weather_spec.rb +20 -0
- data/spec/live_f1/packet_spec.rb +112 -0
- data/spec/live_f1/source/keyframe_spec.rb +56 -0
- data/spec/live_f1/source/live_spec.rb +106 -0
- data/spec/live_f1/source/session_spec.rb +39 -0
- data/spec/live_f1/source_spec.rb +140 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/support/packet_type_examples.rb +122 -0
- metadata +337 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'live_f1/packet'
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
extend PacketTypeExamples
|
|
5
|
+
|
|
6
|
+
describe LiveF1::Packet::Sys::KeyFrame do
|
|
7
|
+
it_behaves_like LiveF1::Packet::Type::Short
|
|
8
|
+
|
|
9
|
+
subject { packet }
|
|
10
|
+
|
|
11
|
+
let(:source) { mock(:source) }
|
|
12
|
+
let(:header) { mock(:header) }
|
|
13
|
+
let(:data) { "" }
|
|
14
|
+
let(:packet) do
|
|
15
|
+
packet = described_class.new(source, header)
|
|
16
|
+
packet.send :set_data, data
|
|
17
|
+
packet
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe "#number" do
|
|
21
|
+
# `data` for a KeyFrame packet represents a little-endian integer
|
|
22
|
+
it "reads its keyframe number from the data" do
|
|
23
|
+
# Binary: "00000000/00000011"
|
|
24
|
+
subject.data = [3,0].pack("c*")
|
|
25
|
+
subject.number.should == 3
|
|
26
|
+
|
|
27
|
+
# Binary: "00000001/00000011"
|
|
28
|
+
subject.data = [3,1].pack("c*")
|
|
29
|
+
subject.number.should == 259
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# describe "#inspect" do
|
|
34
|
+
# it "returns a string representation of the keyframe" do
|
|
35
|
+
# subject.stub(:number) { 25 }
|
|
36
|
+
# subject.inspect.should == "Keyframe 25"
|
|
37
|
+
# end
|
|
38
|
+
# end
|
|
39
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'live_f1/packet'
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
extend PacketTypeExamples
|
|
5
|
+
|
|
6
|
+
describe LiveF1::Packet::Sys::Notice do
|
|
7
|
+
it_behaves_like LiveF1::Packet::Type::Long
|
|
8
|
+
it_behaves_like LiveF1::Packet::Decryptable
|
|
9
|
+
|
|
10
|
+
subject { packet }
|
|
11
|
+
|
|
12
|
+
let(:source) { mock(:source) }
|
|
13
|
+
let(:header) { mock(:header) }
|
|
14
|
+
let(:data) { "" }
|
|
15
|
+
let(:packet) do
|
|
16
|
+
packet = described_class.new(source, header)
|
|
17
|
+
packet.send :set_data, data
|
|
18
|
+
packet
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'live_f1/packet'
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
extend PacketTypeExamples
|
|
5
|
+
|
|
6
|
+
describe LiveF1::Packet::Sys::Reset do
|
|
7
|
+
it_behaves_like LiveF1::Packet::Type::Special
|
|
8
|
+
|
|
9
|
+
subject { packet }
|
|
10
|
+
|
|
11
|
+
let(:source) { mock(:source) }
|
|
12
|
+
let(:header) { mock(:header) }
|
|
13
|
+
let(:data) { "" }
|
|
14
|
+
let(:packet) do
|
|
15
|
+
packet = described_class.new(source, header)
|
|
16
|
+
packet.send :set_data, data
|
|
17
|
+
packet
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# describe "#inspect" do
|
|
21
|
+
# it "returns a string representation of the keyframe" do
|
|
22
|
+
# subject.stub(:number) { 25 }
|
|
23
|
+
# subject.inspect.should == "Keyframe 25"
|
|
24
|
+
# end
|
|
25
|
+
# end
|
|
26
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require 'live_f1/packet'
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
extend PacketTypeExamples
|
|
5
|
+
|
|
6
|
+
describe LiveF1::Packet::Sys::SessionStart do
|
|
7
|
+
it_behaves_like LiveF1::Packet::Type::Short
|
|
8
|
+
|
|
9
|
+
subject { packet }
|
|
10
|
+
|
|
11
|
+
let(:source) { mock(:source) }
|
|
12
|
+
let(:header) { mock(:header, :data => "0000010".to_i(2)) }
|
|
13
|
+
let(:data) { "\x005678" }
|
|
14
|
+
let(:packet) do
|
|
15
|
+
described_class.new(source, header).tap do |packet|
|
|
16
|
+
packet.send :set_data, data
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe "#session_number" do
|
|
21
|
+
it "reads a session number from the data" do
|
|
22
|
+
subject.session_number.should == 5678
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe "#event_type" do
|
|
27
|
+
it "returns the event type indicated in the first data byte" do
|
|
28
|
+
subject.event_type.should == 2
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'live_f1/packet'
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
extend PacketTypeExamples
|
|
5
|
+
|
|
6
|
+
describe LiveF1::Packet::Sys::Speed do
|
|
7
|
+
it_behaves_like LiveF1::Packet::Type::Long
|
|
8
|
+
it_behaves_like LiveF1::Packet::Decryptable
|
|
9
|
+
|
|
10
|
+
subject { packet }
|
|
11
|
+
|
|
12
|
+
let(:source) { mock(:source) }
|
|
13
|
+
let(:header) { mock(:header) }
|
|
14
|
+
let(:data) { "" }
|
|
15
|
+
let(:packet) do
|
|
16
|
+
packet = described_class.new(source, header)
|
|
17
|
+
packet.send :set_data, data
|
|
18
|
+
packet
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require 'live_f1/packet'
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
extend PacketTypeExamples
|
|
5
|
+
|
|
6
|
+
describe LiveF1::Packet::Sys::Timestamp do
|
|
7
|
+
it_behaves_like LiveF1::Packet::Type::Timestamp
|
|
8
|
+
it_behaves_like LiveF1::Packet::Decryptable
|
|
9
|
+
|
|
10
|
+
subject { packet }
|
|
11
|
+
|
|
12
|
+
let(:source) { mock(:source) }
|
|
13
|
+
let(:header) { mock(:header) }
|
|
14
|
+
let(:data) { "\x03\x00" }
|
|
15
|
+
let(:packet) do
|
|
16
|
+
packet = described_class.new(source, header)
|
|
17
|
+
packet.send :set_data, data
|
|
18
|
+
packet
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe "#number" do
|
|
22
|
+
# `data` for a KeyFrame packet represents a little-endian integer
|
|
23
|
+
it "read a session number from the data" do
|
|
24
|
+
# Binary: "00000000/00000011"
|
|
25
|
+
subject.send :set_data, [3,0].pack("c*")
|
|
26
|
+
subject.number.should == 3
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# Binary: "00000001/00000011"
|
|
30
|
+
subject.send :set_data, [3,1].pack("c*")
|
|
31
|
+
subject.number.should == 259
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'live_f1/packet'
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
extend PacketTypeExamples
|
|
5
|
+
|
|
6
|
+
describe LiveF1::Packet::Sys::TrackStatus do
|
|
7
|
+
it_behaves_like LiveF1::Packet::Type::Short
|
|
8
|
+
it_behaves_like LiveF1::Packet::Decryptable
|
|
9
|
+
|
|
10
|
+
subject { packet }
|
|
11
|
+
|
|
12
|
+
let(:source) { mock(:source) }
|
|
13
|
+
let(:header) { mock(:header) }
|
|
14
|
+
let(:data) { "" }
|
|
15
|
+
let(:packet) do
|
|
16
|
+
packet = described_class.new(source, header)
|
|
17
|
+
packet.send :set_data, data
|
|
18
|
+
packet
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'live_f1/packet'
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
extend PacketTypeExamples
|
|
5
|
+
|
|
6
|
+
describe LiveF1::Packet::Sys::Weather do
|
|
7
|
+
it_behaves_like LiveF1::Packet::Type::Short
|
|
8
|
+
it_behaves_like LiveF1::Packet::Decryptable
|
|
9
|
+
|
|
10
|
+
subject { packet }
|
|
11
|
+
|
|
12
|
+
let(:source) { mock(:source) }
|
|
13
|
+
let(:header) { mock(:header) }
|
|
14
|
+
let(:data) { "" }
|
|
15
|
+
let(:packet) do
|
|
16
|
+
packet = described_class.new(source, header)
|
|
17
|
+
packet.send :set_data, data
|
|
18
|
+
packet
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
require 'live_f1/packet'
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
module LiveF1
|
|
5
|
+
class Packet
|
|
6
|
+
module Spec
|
|
7
|
+
class Base < Packet; def length; 0; end; end
|
|
8
|
+
class Decryptable < Packet; include Packet::Type::Short; include Packet::Decryptable; end
|
|
9
|
+
class Short < Packet; include Packet::Type::Short; end
|
|
10
|
+
class Long < Packet; include Packet::Type::Long; end
|
|
11
|
+
class Special < Packet; include Packet::Type::Special; end
|
|
12
|
+
class Timestamp < Packet; include Packet::Type::Timestamp; end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def mock_packet stubs = {}
|
|
18
|
+
base_stubs = {
|
|
19
|
+
:data => "",
|
|
20
|
+
:data= => nil,
|
|
21
|
+
:length => 0
|
|
22
|
+
}
|
|
23
|
+
mock("packet", base_stubs.merge(stubs))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
extend PacketTypeExamples
|
|
27
|
+
|
|
28
|
+
describe LiveF1::Packet do
|
|
29
|
+
describe "::from_source" do
|
|
30
|
+
let(:source) { mock("source", :read_bytes => "") }
|
|
31
|
+
let(:header) { mock("header", :packet_klass => LiveF1::Packet::Spec::Base) }
|
|
32
|
+
let(:packet) { mock_packet :length => 7 }
|
|
33
|
+
let(:event_type) { LiveF1::Event::QUALIFYING }
|
|
34
|
+
before do
|
|
35
|
+
LiveF1::Packet::Header.stub(:from_source).with(source, event_type) { header }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "extracts a packet header from the source" do
|
|
39
|
+
LiveF1::Packet::Header.should_receive(:from_source).with(source, event_type) { header }
|
|
40
|
+
|
|
41
|
+
described_class.from_source(source, event_type)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "returns the kind of packet specified in the header" do
|
|
45
|
+
described_class.from_source(source, event_type).should be_a_kind_of(LiveF1::Packet::Spec::Base)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "reads bytes from the source depending on its determined length" do
|
|
49
|
+
described_class.stub(:new) { packet }
|
|
50
|
+
|
|
51
|
+
source.should_receive(:read_bytes).with(7) { " " }
|
|
52
|
+
|
|
53
|
+
described_class.from_source(source, event_type)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "sets the packet data to the data read from the source" do
|
|
57
|
+
described_class.stub(:new) { packet }
|
|
58
|
+
source.stub(:read_bytes).with(7) { "abcdefg" }
|
|
59
|
+
|
|
60
|
+
packet.should_receive(:data=).with("abcdefg")
|
|
61
|
+
|
|
62
|
+
described_class.from_source(source, event_type)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe "(constructor)" do
|
|
67
|
+
let(:source) { mock("source") }
|
|
68
|
+
let(:header) { mock("header") }
|
|
69
|
+
let(:packet) { LiveF1::Packet::Spec::Base.new(source, header) }
|
|
70
|
+
|
|
71
|
+
it "sets the source property" do
|
|
72
|
+
packet.source.should == source
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "sets the header property" do
|
|
76
|
+
packet.header.should == header
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
describe "(instance methods)" do
|
|
81
|
+
subject { packet }
|
|
82
|
+
let(:source) { mock("source") }
|
|
83
|
+
let(:header) { mock("header", :packet_type => 0, :data => 0) }
|
|
84
|
+
let(:packet) { LiveF1::Packet::Spec::Base.new(source, header) }
|
|
85
|
+
|
|
86
|
+
describe "#inspect" do
|
|
87
|
+
it "include the class name" do
|
|
88
|
+
subject.inspect.should include("Spec::Base")
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
describe LiveF1::Packet::Spec::Decryptable do
|
|
95
|
+
it_behaves_like LiveF1::Packet::Decryptable
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
describe LiveF1::Packet::Spec::Long do
|
|
99
|
+
it_behaves_like LiveF1::Packet::Type::Long
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
describe LiveF1::Packet::Spec::Short do
|
|
103
|
+
it_behaves_like LiveF1::Packet::Type::Short
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe LiveF1::Packet::Spec::Special do
|
|
107
|
+
it_behaves_like LiveF1::Packet::Type::Special
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
describe LiveF1::Packet::Spec::Timestamp do
|
|
111
|
+
it_behaves_like LiveF1::Packet::Type::Timestamp
|
|
112
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require 'live_f1/source'
|
|
2
|
+
|
|
3
|
+
describe LiveF1::Source::Keyframe do
|
|
4
|
+
let(:io) { mock(:io) }
|
|
5
|
+
let(:parent) { mock(:source) }
|
|
6
|
+
|
|
7
|
+
describe "(constructor)" do
|
|
8
|
+
let(:source) { described_class.new(io, parent) }
|
|
9
|
+
let(:data) { "" }
|
|
10
|
+
|
|
11
|
+
it "takes an io object as the first parameter" do
|
|
12
|
+
source.io.should == io
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "takes a password as the second parameter" do
|
|
16
|
+
source.parent.should == parent
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe "(instance methods)" do
|
|
21
|
+
let(:source) { described_class.new(io, parent) }
|
|
22
|
+
|
|
23
|
+
describe "#read_bytes" do
|
|
24
|
+
it "reads from the keyframe data" do
|
|
25
|
+
io.should_receive(:read).with(2) { "xx" }
|
|
26
|
+
|
|
27
|
+
source.read_bytes(2)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe "#session" do
|
|
32
|
+
it "uses its parent source's session" do
|
|
33
|
+
session = mock(:session)
|
|
34
|
+
parent.stub(:session) { session }
|
|
35
|
+
source.session.should == session
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
describe "#session=" do
|
|
40
|
+
it "sets its parent source's session" do
|
|
41
|
+
session = mock(:session)
|
|
42
|
+
parent.should_receive(:session=).with(session)
|
|
43
|
+
|
|
44
|
+
source.session = session
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe "#decryption_key" do
|
|
49
|
+
it "uses its parent source's decryption key" do
|
|
50
|
+
parent.should_receive(:decryption_key).with(1234) { "5caff01d" }
|
|
51
|
+
|
|
52
|
+
source.decryption_key(1234).should == "5caff01d"
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'live_f1/source'
|
|
3
|
+
|
|
4
|
+
describe LiveF1::Source::Live do
|
|
5
|
+
let(:username) { "username@example.com" }
|
|
6
|
+
let(:password) { "swordfish" }
|
|
7
|
+
|
|
8
|
+
describe "(constructor)" do
|
|
9
|
+
let(:source) { described_class.new(username, password) }
|
|
10
|
+
|
|
11
|
+
it "takes a username as the first parameter" do
|
|
12
|
+
source.username.should == username
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "takes a password as the second parameter" do
|
|
16
|
+
source.password.should == password
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe "(instance methods)" do
|
|
21
|
+
let(:source) { described_class.new(username, password) }
|
|
22
|
+
|
|
23
|
+
describe "#read_bytes" do
|
|
24
|
+
let(:socket) { mock(:socket) }
|
|
25
|
+
it "reads from the live f1 socket" do
|
|
26
|
+
source.stub(:socket) { socket }
|
|
27
|
+
socket.should_receive(:read).with(2) { "xx" }
|
|
28
|
+
|
|
29
|
+
source.read_bytes(2)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe "#socket" do
|
|
34
|
+
it "opens a TCPSocket to the live timing server" do
|
|
35
|
+
TCPSocket.should_receive(:open).with("80.231.178.249", 4321) { mock("socket") }
|
|
36
|
+
source.send(:socket)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "uses an existing socket if available" do
|
|
40
|
+
TCPSocket.should_receive(:open).once { mock("socket") }
|
|
41
|
+
source.send(:socket)
|
|
42
|
+
source.send(:socket)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
describe "#keyframe" do
|
|
47
|
+
let(:io) { mock(:io, :read => "", :rewind => 0) }
|
|
48
|
+
|
|
49
|
+
context "without a keyframe number" do
|
|
50
|
+
it "returns a Keyframe source initialised with the correct URL and parent source" do
|
|
51
|
+
source.should_receive(:open).with("http://80.231.178.249/keyframe.bin") { io }
|
|
52
|
+
LiveF1::Source::Keyframe.should_receive(:new).with(io, source)
|
|
53
|
+
|
|
54
|
+
source.keyframe
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
context "with a keyframe number" do
|
|
59
|
+
it "returns a Keyframe source initialised with the correct URL and parent source" do
|
|
60
|
+
source.should_receive(:open).with("http://80.231.178.249/keyframe_00012.bin") { io }
|
|
61
|
+
LiveF1::Source::Keyframe.should_receive(:new).with(io, source)
|
|
62
|
+
|
|
63
|
+
source.keyframe(12)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
context "on SocketError" do
|
|
68
|
+
before do
|
|
69
|
+
source.stub(:open).and_raise(SocketError)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "raises ConnectionError" do
|
|
73
|
+
lambda { source.keyframe }.should raise_error(LiveF1::Source::Live::ConnectionError)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
describe "#decryption_key" do
|
|
79
|
+
let(:decryption_url) { "http://80.231.178.249/reg/getkey/1234.asp?auth=ABC123DEF" }
|
|
80
|
+
|
|
81
|
+
before do
|
|
82
|
+
source.stub(:auth) { "ABC123DEF" }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "uses the live source's authorization to request decryption key from the live timing servers" do
|
|
86
|
+
source.should_receive(:open).with(decryption_url) { mock(:io, :read => "5caff01d") }
|
|
87
|
+
source.decryption_key(1234).should == "5caff01d".to_i(16)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "raises a ConnectionError when decryption key service returns 0" do
|
|
91
|
+
source.should_receive(:open).with(decryption_url) { mock(:io, :read => "0") }
|
|
92
|
+
lambda { source.decryption_key(1234) }.should raise_error(LiveF1::Source::Live::ConnectionError, /session key/)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
describe "#auth" do
|
|
97
|
+
before do
|
|
98
|
+
FakeWeb.register_uri :post, "http://80.231.178.249/reg/login", :set_cookie => "USER=abcdef"
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "loads authentication from the live timing servers" do
|
|
102
|
+
source.send(:auth).should == "abcdef"
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'live_f1/source/session'
|
|
2
|
+
|
|
3
|
+
describe LiveF1::Source::Session do
|
|
4
|
+
describe "(constructor)" do
|
|
5
|
+
let(:session) { described_class.new(1, 2, 3) }
|
|
6
|
+
|
|
7
|
+
it "sets the session number, event type and decryption key" do
|
|
8
|
+
session.number.should == 1
|
|
9
|
+
session.event_type.should == 2
|
|
10
|
+
session.decryption_key.should == 3
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "initializes the decryption salt" do
|
|
14
|
+
session.decryption_salt.should == 0x55555555
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe "(instance methods)" do
|
|
19
|
+
let(:session) { described_class.new(1, 2, 3) }
|
|
20
|
+
|
|
21
|
+
describe "#decrypt" do
|
|
22
|
+
let(:decryption_key) { "B247A746".to_i(16) }
|
|
23
|
+
let(:encrypted) { "\xBC\x9A\x1E\x9AH>\xCB\xE4\xFE\xE0v!h\r\xF9" }
|
|
24
|
+
let(:decrypted) { "Please Wait ..." }
|
|
25
|
+
it "decrypts data" do
|
|
26
|
+
session.stub(:decryption_key) { decryption_key }
|
|
27
|
+
session.decrypt(encrypted).should == decrypted
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe "#reset_decryption_salt!" do
|
|
32
|
+
it "resets the decryption salt" do
|
|
33
|
+
session.decryption_salt = 0x01010101
|
|
34
|
+
session.reset_decryption_salt!
|
|
35
|
+
session.decryption_salt.should == 0x55555555
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
require 'live_f1/source'
|
|
2
|
+
|
|
3
|
+
class TestSource < LiveF1::Source
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
module LiveF1
|
|
7
|
+
class Packet
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe LiveF1::Source do
|
|
12
|
+
describe "(instance methods)" do
|
|
13
|
+
let(:source) { TestSource.new }
|
|
14
|
+
let(:session) { mock(:session) }
|
|
15
|
+
|
|
16
|
+
before do
|
|
17
|
+
source.stub(:session) { session }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe "#run" do
|
|
21
|
+
let(:packets) { [mock("packet"),mock("packet"),mock("packet")] }
|
|
22
|
+
|
|
23
|
+
before do
|
|
24
|
+
p = packets ? packets.dup : []
|
|
25
|
+
source.stub(:read_packet) { p.shift }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
context "with keyframes available" do
|
|
29
|
+
let(:keyframe_source) { mock("keyframe source") }
|
|
30
|
+
before do
|
|
31
|
+
source.stub(:keyframe) { keyframe_source }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "runs the keyframe" do
|
|
35
|
+
keyframe_source.should_receive(:run)
|
|
36
|
+
|
|
37
|
+
source.run { }
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "reads packets" do
|
|
42
|
+
source.should_receive(:read_packet) { nil }
|
|
43
|
+
source.run { }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "yields as many packets as are available" do
|
|
47
|
+
@packets = []
|
|
48
|
+
source.run do |p|
|
|
49
|
+
@packets << p
|
|
50
|
+
end
|
|
51
|
+
@packets.should == packets
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe "running" do
|
|
55
|
+
let(:header) { mock("header") }
|
|
56
|
+
let(:decryption_key) { "5caff01d".to_i(16) }
|
|
57
|
+
let(:session_number) { 1234 }
|
|
58
|
+
|
|
59
|
+
before do
|
|
60
|
+
source.stub(:decryption_key).with(session_number) { decryption_key }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
context "when an SessionStart packet is yielded" do
|
|
64
|
+
let(:packets) do
|
|
65
|
+
packet = LiveF1::Packet::Sys::SessionStart.new(source, header)
|
|
66
|
+
packet.stub(:session_number) { session_number }
|
|
67
|
+
packet.stub(:event_type) { 3 }
|
|
68
|
+
[packet]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "creates a source session with the correct data" do
|
|
72
|
+
LiveF1::Source::Session.should_receive(:new).with(1234, 3, decryption_key) { mock(:session) }
|
|
73
|
+
|
|
74
|
+
source.run { }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "sets the source's session to the new session object" do
|
|
78
|
+
LiveF1::Source::Session.stub(:new) { session }
|
|
79
|
+
source.should_receive(:session=).with(session)
|
|
80
|
+
|
|
81
|
+
source.run { }
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
context "when an KeyFrame packet is yielded" do
|
|
86
|
+
let(:packets) do
|
|
87
|
+
packet = LiveF1::Packet::Sys::KeyFrame.new(source, header)
|
|
88
|
+
packet.stub(:number) { 123 }
|
|
89
|
+
[packet]
|
|
90
|
+
end
|
|
91
|
+
let(:session) { mock(:session, :reset_decryption_salt! => true) }
|
|
92
|
+
|
|
93
|
+
before do
|
|
94
|
+
source.stub(:session) { session }
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it "resets the session's decryption data" do
|
|
98
|
+
session.should_receive(:reset_decryption_salt!) { true }
|
|
99
|
+
source.run { }
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe "#read_packet" do
|
|
107
|
+
let(:packet) { mock("packet") }
|
|
108
|
+
let(:session) { mock(:session, :event_type => 3) }
|
|
109
|
+
|
|
110
|
+
before do
|
|
111
|
+
LiveF1::Packet.stub(:from_source).with(source, 3) { packet }
|
|
112
|
+
source.session = session
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it "extracts a packet from itself" do
|
|
116
|
+
LiveF1::Packet.should_receive(:from_source).with(source, 3) { packet }
|
|
117
|
+
|
|
118
|
+
source.read_packet
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "returns the extracted packet" do
|
|
122
|
+
source.read_packet.should == packet
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
describe "#decrypt" do
|
|
127
|
+
let(:input) { "encrypted" }
|
|
128
|
+
let(:output) { "plaintext" }
|
|
129
|
+
it "calls its session's decryptor" do
|
|
130
|
+
session.should_receive(:decrypt).with(input)
|
|
131
|
+
source.decrypt(input)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it "returns the decrypted bytes" do
|
|
135
|
+
session.stub(:decrypt) { output }
|
|
136
|
+
source.decrypt(input).should == output
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
require 'fakeweb'
|
|
2
|
+
|
|
3
|
+
Dir["spec/support/**/*.rb"].each { |f| require File.join(File.expand_path(File.dirname(__FILE__)),"..",f) }
|
|
4
|
+
|
|
5
|
+
RSpec.configure do |config|
|
|
6
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
|
7
|
+
config.run_all_when_everything_filtered = true
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
FakeWeb.allow_net_connect = false
|