live_f1-core 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|