fit_parser 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.
- 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
|
+
@
|