fit_parser 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +105 -0
- data/LICENSE.txt +20 -0
- data/README.md +27 -0
- data/Rakefile +38 -0
- data/lib/fit_parser/file/data.rb +99 -0
- data/lib/fit_parser/file/definition.rb +120 -0
- data/lib/fit_parser/file/definitions.rb +705 -0
- data/lib/fit_parser/file/header.rb +18 -0
- data/lib/fit_parser/file/record.rb +37 -0
- data/lib/fit_parser/file/record_header.rb +27 -0
- data/lib/fit_parser/file/type.rb +41 -0
- data/lib/fit_parser/file/types.rb +954 -0
- data/lib/fit_parser/file.rb +29 -0
- data/lib/fit_parser/version.rb +3 -0
- data/lib/fit_parser.rb +19 -0
- data/spec/file/data_spec.rb +111 -0
- data/spec/file/definition_spec.rb +26 -0
- data/spec/file/definitions_spec.rb +81 -0
- data/spec/file/header_spec.rb +28 -0
- data/spec/file/record_header_spec.rb +20 -0
- data/spec/file/record_spec.rb +56 -0
- data/spec/file/type_spec.rb +99 -0
- data/spec/file/types_spec.rb +100 -0
- data/spec/file_spec.rb +21 -0
- data/spec/fit_spec.rb +10 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/support/examples/file/full_file_with_wrong_crc.fit +0 -0
- data/spec/support/examples/file/header +0 -0
- data/spec/support/examples/file/header_14b.fit +0 -0
- data/spec/support/examples/record/data_record_2.fit +0 -0
- data/spec/support/examples/record/data_record_2bis.fit +0 -0
- data/spec/support/examples/record/definition_record +0 -0
- data/spec/support/examples/record/definition_record_2.fit +0 -0
- data/spec/support/examples/record/message/data_dynamic_fields.fit +0 -0
- data/spec/support/examples/record/message/data_field_array.fit +0 -0
- data/spec/support/examples/record/message/data_file_capabilities_activities.fit +0 -0
- data/spec/support/examples/record/message/data_file_capabilities_settings.fit +0 -0
- data/spec/support/examples/record/message/definition +0 -0
- data/spec/support/examples/record/message/definition_dynamic_fields.fit +0 -0
- data/spec/support/examples/record/message/definition_field_array.fit +0 -0
- data/spec/support/examples/record/message/definition_file_capabilities.fit +0 -0
- data/spec/support/examples/record/normal_header +1 -0
- metadata +230 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
module FitParser
|
2
|
+
class File
|
3
|
+
|
4
|
+
def self.read(io)
|
5
|
+
new.read(io)
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :header, :records, :crc
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@records = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def read(io)
|
15
|
+
@header = Header.read(io)
|
16
|
+
|
17
|
+
Record.clear_definitions!
|
18
|
+
|
19
|
+
while io.pos < @header.end_pos
|
20
|
+
@records << Record.read(io)
|
21
|
+
end
|
22
|
+
|
23
|
+
@crc = io.read(2)
|
24
|
+
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
data/lib/fit_parser.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'bindata'
|
2
|
+
require 'active_support'
|
3
|
+
require 'active_support/core_ext/class'
|
4
|
+
require 'fit_parser/file'
|
5
|
+
require 'fit_parser/file/header'
|
6
|
+
require 'fit_parser/file/record'
|
7
|
+
require 'fit_parser/file/record_header'
|
8
|
+
require 'fit_parser/file/types'
|
9
|
+
require 'fit_parser/file/type'
|
10
|
+
require 'fit_parser/file/definition'
|
11
|
+
require 'fit_parser/file/data'
|
12
|
+
require 'fit_parser/file/definitions'
|
13
|
+
require 'fit_parser/version'
|
14
|
+
|
15
|
+
module FitParser
|
16
|
+
def self.load_file(path)
|
17
|
+
File.read ::File.open(path)
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fit::File::Data do
|
4
|
+
describe ".generate" do
|
5
|
+
context 'standard definition' do
|
6
|
+
let(:definition) do
|
7
|
+
Fit::File::Definition.read example_file('record/message/definition')
|
8
|
+
end
|
9
|
+
|
10
|
+
subject { described_class.generate(definition) }
|
11
|
+
|
12
|
+
its(:ancestors) { should include(BinData::Record) }
|
13
|
+
its("new.record_type") { should eq(:file_id) }
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'definition with multiple time the same field' do
|
17
|
+
before :all do
|
18
|
+
@fields = Fit::File::Definitions.class_variable_get :@@fields
|
19
|
+
@dyn_fields = Fit::File::Definitions.class_variable_get :@@dyn_fields
|
20
|
+
# force a fake definition for scaling of arrays
|
21
|
+
Fit::File::Definitions.add_field 2, 2, "field_array", :type => 6, :scale => 10, :offset => 0
|
22
|
+
end
|
23
|
+
|
24
|
+
after :all do
|
25
|
+
Fit::File::Definitions.class_variable_set :@@fields, @fields
|
26
|
+
Fit::File::Definitions.class_variable_set :@@dyn_fields, @dyn_fields
|
27
|
+
end
|
28
|
+
|
29
|
+
before :each do
|
30
|
+
def_file = example_file('record/message/definition_field_array.fit')
|
31
|
+
data_file = example_file('record/message/data_field_array.fit')
|
32
|
+
definition = described_class.generate(Fit::File::Definition.read def_file)
|
33
|
+
@result = definition.read( data_file )
|
34
|
+
end
|
35
|
+
|
36
|
+
it "reads the entire record" do
|
37
|
+
# read first the record definition
|
38
|
+
expect(@result.raw_field_array).to be == [ 123456789, 987654321 ]
|
39
|
+
expect(@result.raw_field_4).to be == [ 1, 3 ]
|
40
|
+
expect(@result.raw_field_8).to be == 1539
|
41
|
+
expect(@result.raw_active_time_zone).to be == 0
|
42
|
+
end
|
43
|
+
|
44
|
+
it "does not apply the scale equal to 1 for integer" do
|
45
|
+
expect(@result.raw_active_time_zone).to be == 0
|
46
|
+
expect(@result.active_time_zone.to_s).to be_eql '0'
|
47
|
+
end
|
48
|
+
|
49
|
+
it "does not apply the scale equal to 1 for arrays" do
|
50
|
+
expect(@result.raw_field_4).to be == [ 1, 3 ]
|
51
|
+
expect(@result.field_4.to_s).to be_eql '[1, 3]'
|
52
|
+
end
|
53
|
+
|
54
|
+
it "does apply scale on each element of an array" do
|
55
|
+
expect(@result.raw_field_array).to be == [ 123456789, 987654321 ]
|
56
|
+
expect(@result.field_array.to_s).to be_eql '[12345678.9, 98765432.1]'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'definition with dynamic fields' do
|
61
|
+
before :each do
|
62
|
+
def_file = example_file('record/message/definition_dynamic_fields.fit')
|
63
|
+
data_file = example_file('record/message/data_dynamic_fields.fit')
|
64
|
+
definition = described_class.generate(Fit::File::Definition.read def_file)
|
65
|
+
@result = definition.read( data_file )
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'uses dynamic field value' do
|
69
|
+
expect(@result.raw_product).to be == 1499
|
70
|
+
expect(@result.product).to be == 'swim'
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'definition with non basic types' do
|
75
|
+
before :each do
|
76
|
+
def_file = example_file('record/message/definition_dynamic_fields.fit')
|
77
|
+
data_file = example_file('record/message/data_dynamic_fields.fit')
|
78
|
+
definition = described_class.generate(Fit::File::Definition.read def_file)
|
79
|
+
@result = definition.read( data_file )
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'returns the real value' do
|
83
|
+
expect(@result.raw_type).to be == 1
|
84
|
+
expect(@result.type).to be == 'device'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'definition with bit field types' do
|
89
|
+
before :each do
|
90
|
+
def_file = example_file('record/message/definition_file_capabilities.fit')
|
91
|
+
@definition = described_class.generate(Fit::File::Definition.read def_file)
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'when only 1 bit set' do
|
95
|
+
it 'returns the single value' do
|
96
|
+
res = @definition.read( example_file('record/message/data_file_capabilities_activities.fit') )
|
97
|
+
expect(res.raw_flags).to eq(2)
|
98
|
+
expect(res.flags).to eq('read')
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'when several bits set' do
|
103
|
+
it 'returns the compound value' do
|
104
|
+
res = @definition.read( example_file('record/message/data_file_capabilities_settings.fit') )
|
105
|
+
expect(res.raw_flags).to eq(6)
|
106
|
+
expect(res.flags).to eq('read/write')
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fit::File::Definition do
|
4
|
+
context "given a sample definition message" do
|
5
|
+
describe ".read" do
|
6
|
+
subject do
|
7
|
+
described_class.read example_file('record/message/definition')
|
8
|
+
end
|
9
|
+
|
10
|
+
its(:architecture) { should == 0 }
|
11
|
+
its(:global_message_number) { should == 0 }
|
12
|
+
its(:field_count) { should == 6 }
|
13
|
+
it { expect(subject.fields.size).to eq(subject.field_count) }
|
14
|
+
|
15
|
+
its(:record_type) { should == :definition }
|
16
|
+
it 'returns the real type for fields' do
|
17
|
+
expect(subject.fields[0].real_type).to be == :uint32z
|
18
|
+
expect(subject.fields[1].real_type).to be == :date_time
|
19
|
+
expect(subject.fields[2].real_type).to be == :manufacturer
|
20
|
+
expect(subject.fields[3].real_type).to be == :uint16 # product
|
21
|
+
expect(subject.fields[4].real_type).to be == :uint16 # number
|
22
|
+
expect(subject.fields[5].real_type).to be == :file
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# we use undefined numbers for field otherwise we interfere
|
4
|
+
# with already defined fields in definitions.rb and test are
|
5
|
+
# not really independant of the code
|
6
|
+
describe Fit::File::Definitions do
|
7
|
+
describe ".add_field" do
|
8
|
+
before :all do
|
9
|
+
@fields = described_class.class_variable_get :@@fields
|
10
|
+
@dyn_fields = described_class.class_variable_get :@@dyn_fields
|
11
|
+
end
|
12
|
+
|
13
|
+
after :all do
|
14
|
+
Fit::File::Definitions.class_variable_set(:@@fields, @fields)
|
15
|
+
Fit::File::Definitions.class_variable_set(:@@dyn_fields, @dyn_fields)
|
16
|
+
end
|
17
|
+
|
18
|
+
context "without additional options" do
|
19
|
+
before :each do
|
20
|
+
Fit::File::Definitions.class_variable_set(:@@fields, Hash.new { |h,k| h[k]={} })
|
21
|
+
Fit::File::Definitions.class_variable_set(:@@dyn_fields, Hash.new { |h,k| h[k]={} })
|
22
|
+
described_class.add_field(999, 999, 'rspec_test')
|
23
|
+
end
|
24
|
+
|
25
|
+
it "adds field data" do
|
26
|
+
expect(described_class.get_field(999,999)).to be_a(Hash)
|
27
|
+
expect(described_class.get_field(999,999)).to eql({ :name => 'rspec_test'})
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'raised an error for dynamic field data' do
|
31
|
+
expect { described_class.add_field(999, 999, 'rspec_test_dyn') }.to raise_error
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "with additional options" do
|
36
|
+
before :each do
|
37
|
+
Fit::File::Definitions.class_variable_set(:@@fields, Hash.new { |h,k| h[k]={} })
|
38
|
+
Fit::File::Definitions.class_variable_set(:@@dyn_fields, Hash.new { |h,k| h[k]={} })
|
39
|
+
|
40
|
+
described_class.add_field(999, 999, 'rspec_test', :scale => 100, :units => 'm')
|
41
|
+
described_class.add_field(999, 999, 'rspec_test_dyn', :type => 4, :scale => 10, :offset => 10, :ref_field_name => nil, :ref_field_values => nil)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "adds field data" do
|
45
|
+
expect(described_class.get_field(999, 999)).to be_a(Hash)
|
46
|
+
expect(described_class.get_field(999, 999)).to eql({ :name => 'rspec_test', :scale => 100, :units => 'm'})
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'adds dynamic field data' do
|
50
|
+
expect(described_class.get_dynamic_fields(999, 999)).to be_a(Hash)
|
51
|
+
expect(described_class.get_dynamic_fields(999, 999)).to eql({ :rspec_test_dyn => {:type => 4, :scale => 10, :offset => 10, :ref_field_name => nil, :ref_field_values => nil} })
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe ".get_field" do
|
57
|
+
it "returns nil if no field exists" do
|
58
|
+
expect(described_class.get_field(100,100)).to be_nil
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '.get_dynamic_field' do
|
63
|
+
it 'returns nil if no dynamic field exists' do
|
64
|
+
described_class.add_field(100, 100, 'rspec')
|
65
|
+
expect(described_class.get_dynamic_fields(100, 100)).to be_nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe ".add_name" do
|
70
|
+
it "adds a name" do
|
71
|
+
described_class.add_name(20, 'record')
|
72
|
+
expect(described_class.get_name(20)).to eql('record')
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe ".get_name" do
|
77
|
+
it "returns nil if no name exists" do
|
78
|
+
expect(described_class.get_name(100)).to be_nil
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fit::File::Header do
|
4
|
+
context "given a sample FIT header" do
|
5
|
+
subject do
|
6
|
+
described_class.read example_file('file/header')
|
7
|
+
end
|
8
|
+
|
9
|
+
its(:header_size) { should == 12 }
|
10
|
+
its(:protocol_version) { should == 16 }
|
11
|
+
its(:profile_version) { should == 64 }
|
12
|
+
its(:data_size) { should == 36069 }
|
13
|
+
its(:data_type) { should == ".FIT" }
|
14
|
+
end
|
15
|
+
|
16
|
+
context "given a sample header file of 14 bytes length" do
|
17
|
+
subject do
|
18
|
+
described_class.read example_file('file/header_14b.fit')
|
19
|
+
end
|
20
|
+
|
21
|
+
its(:header_size) { should == 14 }
|
22
|
+
its(:protocol_version) { should == 16 }
|
23
|
+
its(:profile_version) { should == 411 }
|
24
|
+
its(:data_size) { should == 325 }
|
25
|
+
its(:data_type) { should == ".FIT" }
|
26
|
+
its(:crc) { should == 17101 }
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fit::File::RecordHeader do
|
4
|
+
context "given a sample normal header" do
|
5
|
+
subject do
|
6
|
+
described_class.read example_file('record/normal_header')
|
7
|
+
end
|
8
|
+
|
9
|
+
its(:header_type) { should == 0 }
|
10
|
+
its(:message_type) { should == 1 }
|
11
|
+
its(:local_message_type) { should == 0 }
|
12
|
+
|
13
|
+
it { is_expected.to be_normal }
|
14
|
+
it { is_expected.not_to be_a_compressed_timestamp }
|
15
|
+
end
|
16
|
+
|
17
|
+
context "given a sample compressed timestamp header" do
|
18
|
+
# TODO
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fit::File::Record do
|
4
|
+
before do
|
5
|
+
described_class.clear_definitions!
|
6
|
+
described_class.read(example_file('record/definition_record_2.fit'))
|
7
|
+
end
|
8
|
+
|
9
|
+
describe ".read" do
|
10
|
+
subject { described_class.read(file) }
|
11
|
+
|
12
|
+
context "given a sample definition record" do
|
13
|
+
let(:file) { example_file('record/definition_record') }
|
14
|
+
|
15
|
+
it { expect(subject.header).to be_a Fit::File::RecordHeader }
|
16
|
+
it { expect(subject.content).to be_a Fit::File::Definition }
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
context "given a sample data record" do
|
21
|
+
let(:file) { nil }
|
22
|
+
end
|
23
|
+
|
24
|
+
context "given a sample data record with a string non null terminated" do
|
25
|
+
|
26
|
+
context 'string length is equal to field size' do
|
27
|
+
|
28
|
+
let(:file) { example_file('record/data_record_2.fit') }
|
29
|
+
|
30
|
+
its(:header) { should be_a(Fit::File::RecordHeader) }
|
31
|
+
it { expect(subject.content.raw_version).to be == 250 }
|
32
|
+
it { expect(subject.content.raw_part_number).to be == '123-A1234-00' }
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'string length is smaller than field size' do
|
36
|
+
|
37
|
+
let(:file) { example_file('record/data_record_2bis.fit') }
|
38
|
+
|
39
|
+
its(:header) { should be_a(Fit::File::RecordHeader) }
|
40
|
+
it { expect(subject.content.raw_version).to be == 251 }
|
41
|
+
it { expect(subject.content.version).to be == 2.51 }
|
42
|
+
it { expect(subject.content.raw_part_number).to be == '123-A1234' }
|
43
|
+
it { expect(subject.content.part_number).to be == '123-A1234' }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe ".clear_definitions" do
|
49
|
+
it "should clear the definitions class variable" do
|
50
|
+
described_class.read example_file('record/definition_record')
|
51
|
+
expect(described_class.definitions).to_not be_empty
|
52
|
+
described_class.clear_definitions!
|
53
|
+
expect(described_class.definitions).to be_empty
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fit::File::Type do
|
4
|
+
before :all do
|
5
|
+
@types = Fit::File::Types.class_variable_get :@@types
|
6
|
+
Fit::File::Types.add_type(:int_type, :sint8)
|
7
|
+
Fit::File::Types.add_type(:int_type_with_val, :uint8, :values => {1 => 'one', 2 => 'two', 3 => 'three'})
|
8
|
+
end
|
9
|
+
|
10
|
+
after :all do
|
11
|
+
Fit::File::Types.class_variable_set(:@@types, @types)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '.get_type' do
|
15
|
+
context 'when valid name' do
|
16
|
+
it 'returns a type' do
|
17
|
+
expect(described_class.get_type(:int_type)).to be_a Fit::File::Type
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'returns always the same instance' do
|
21
|
+
expect(described_class.get_type(:int_type)).to equal described_class.get_type(:int_type)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when invalid name' do
|
26
|
+
it 'returns nil' do
|
27
|
+
expect(described_class.get_type(:unknown_type)).to be_nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#value' do
|
33
|
+
context 'when type has values' do
|
34
|
+
|
35
|
+
let(:type) { described_class.get_type(:int_type_with_val) }
|
36
|
+
|
37
|
+
context 'known value requested' do
|
38
|
+
it 'returns the value' do
|
39
|
+
expect(type.value(2)).to eql 'two'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'unknown value requested' do
|
44
|
+
it 'returns the input value' do
|
45
|
+
expect(type.value(999)).to eql 999
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when invalid value is requested' do
|
50
|
+
it 'returns nil' do
|
51
|
+
expect(type.value(255)).to be_nil
|
52
|
+
expect(type.value(0xFF)).to be_nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when type has date_time value' do
|
58
|
+
let(:type) { described_class.get_type(:date_time) }
|
59
|
+
it 'returns the date' do
|
60
|
+
expect(type.value(790509304)).to eq('2015-01-18 09:55:04 UTC')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'when type has message_index value' do
|
65
|
+
let(:type) { described_class.get_type(:message_index) }
|
66
|
+
|
67
|
+
it 'returns the message_index' do
|
68
|
+
expect(type.value(10)).to eq(10)
|
69
|
+
expect(type.value(32778)).to eq(10)
|
70
|
+
expect(type.value(28682)).to eq(10)
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'when type has file_flags value' do
|
76
|
+
let(:type) { described_class.get_type(:file_flags) }
|
77
|
+
it 'returns the file_flags' do
|
78
|
+
expect(type.value(10)).to eq('read/erase')
|
79
|
+
expect(type.value(0x0A)).to eq('read/erase')
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'when type has bool value' do
|
84
|
+
let(:type) { described_class.get_type(:bool) }
|
85
|
+
it 'returns the boolean value' do
|
86
|
+
expect(type.value(0)).to eq(false)
|
87
|
+
expect(type.value(1)).to eq(true)
|
88
|
+
expect(type.value(255)).to be_nil
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'when type has no value' do
|
93
|
+
it 'returns nil' do
|
94
|
+
type = described_class.get_type(:int_type)
|
95
|
+
expect(type.value(1)).to eql 1
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fit::File::Types do
|
4
|
+
before :all do
|
5
|
+
@types = described_class.class_variable_get :@@types
|
6
|
+
end
|
7
|
+
|
8
|
+
after :all do
|
9
|
+
Fit::File::Types.class_variable_set(:@@types, @types)
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '.add_type' do
|
13
|
+
before :each do
|
14
|
+
Fit::File::Types.class_variable_set(:@@types, Hash.new { |h,k| h[k]={} })
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'for enum type' do
|
18
|
+
it 'add enum data' do
|
19
|
+
val = {:values => { 1 => 'val1', 2=> 'val2', 3 => 'val3'}}
|
20
|
+
described_class.add_type(:test_enum, :enum, val)
|
21
|
+
expect(described_class.get_type_definition(:test_enum)).to eql val.merge({:basic_type => :enum})
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '.get_type_definition' do
|
27
|
+
it 'returns nil when type does not exist' do
|
28
|
+
expect(described_class.get_type_definition(:rspec_unknown)).to be_nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '.date_time_value' do
|
33
|
+
context 'wen value below min' do
|
34
|
+
it 'returns system time in second' do
|
35
|
+
expect(described_class.date_time_value(9999, {268435456 => 'min'}, {:utc => true})).to eql '9999'
|
36
|
+
expect(described_class.date_time_value(9999, {268435456 => 'min'}, {:utc => false})).to eql '9999'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'when value is above min' do
|
41
|
+
context 'with UTC mode' do
|
42
|
+
it 'returns exact date UTC' do
|
43
|
+
expect(described_class.date_time_value(790509304, {268435456 => 'min'}, {:utc => true})).to eql '2015-01-18 09:55:04 UTC'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'with local mode' do
|
48
|
+
it 'returns exact date in locale time zone' do
|
49
|
+
# TODO: manage answer based on current system local
|
50
|
+
expect(described_class.date_time_value(790509304, {268435456 => 'min'}, {:utc => false})).not_to match(/UTC$/)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '.message_index_value' do
|
58
|
+
let(:values) { {32768 => 'selected', 28672 => 'reserved', 4095 => 'mask' } }
|
59
|
+
|
60
|
+
context 'when value is not reserved or selected' do
|
61
|
+
it 'returns the message index' do
|
62
|
+
expect(described_class.message_index_value(10, values)).to eq(10)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when value is reserved' do
|
67
|
+
it 'returns real message index' do
|
68
|
+
expect(described_class.message_index_value(28682, values)).to eq(10)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'when value is selected' do
|
73
|
+
it 'returns real message index' do
|
74
|
+
expect(described_class.message_index_value(32778, values)).to eq(10)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '.bitfield_value' do
|
81
|
+
let(:values) { {0x02 => 'read', 0x04 => 'write', 0x08 => 'erase'} }
|
82
|
+
|
83
|
+
context 'when value is a single bit' do
|
84
|
+
it 'returns the single value' do
|
85
|
+
expect(described_class.bitfield_value(2, values)).to eq('read')
|
86
|
+
expect(described_class.bitfield_value(4, values)).to eq('write')
|
87
|
+
expect(described_class.bitfield_value(8, values)).to eq('erase')
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'when value is several bits' do
|
92
|
+
it 'returns the values separated by a slash' do
|
93
|
+
expect(described_class.bitfield_value(6, values)).to eq('read/write')
|
94
|
+
expect(described_class.bitfield_value(12, values)).to eq('write/erase')
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
data/spec/file_spec.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fit::File do
|
4
|
+
let(:file) { described_class.read( example_file('file/full_file_with_wrong_crc.fit') ) }
|
5
|
+
|
6
|
+
it 'should have a header' do
|
7
|
+
expect(file.header).to be_a Fit::File::Header
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should have records' do
|
11
|
+
expect(file.records).to be_a Array
|
12
|
+
expect(file.records[0]).to be_a Fit::File::Record
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should have a CRC' do
|
16
|
+
# warning this file is not having a consistent CRC compare to
|
17
|
+
# its content. To be used only for test.
|
18
|
+
expect(file.crc).to be_a String
|
19
|
+
expect(BinData::Uint16le.read(file.crc)).to be == 34100
|
20
|
+
end
|
21
|
+
end
|
data/spec/fit_spec.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
SimpleCov.add_filter '/spec/'
|
3
|
+
SimpleCov.start
|
4
|
+
|
5
|
+
SPEC_ROOT = File.dirname(__FILE__)
|
6
|
+
|
7
|
+
$LOAD_PATH.unshift SPEC_ROOT, File.join(SPEC_ROOT, '..', 'lib')
|
8
|
+
|
9
|
+
require 'rspec'
|
10
|
+
require 'rspec/its'
|
11
|
+
require 'fit'
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.raise_errors_for_deprecations!
|
15
|
+
end
|
16
|
+
|
17
|
+
def example_file(filename)
|
18
|
+
File.open File.join(SPEC_ROOT, 'support', 'examples', filename)
|
19
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
@
|