postrunner 0.0.11 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -2
- data/Rakefile +18 -2
- data/lib/postrunner/ActivitiesDB.rb +1 -22
- data/lib/postrunner/Activity.rb +21 -0
- data/lib/postrunner/ActivityLink.rb +1 -1
- data/lib/postrunner/ActivityListView.rb +10 -9
- data/lib/postrunner/ActivitySummary.rb +42 -15
- data/lib/postrunner/ActivityView.rb +10 -8
- data/lib/postrunner/ChartView.rb +238 -80
- data/lib/postrunner/DataSources.rb +1 -14
- data/lib/postrunner/DeviceList.rb +18 -10
- data/lib/postrunner/DirUtils.rb +33 -0
- data/lib/postrunner/EventList.rb +149 -0
- data/lib/postrunner/FFS_Activity.rb +297 -0
- data/lib/postrunner/FFS_Device.rb +129 -0
- data/lib/postrunner/FitFileStore.rb +372 -0
- data/lib/postrunner/HRV_Analyzer.rb +178 -0
- data/lib/postrunner/LinearPredictor.rb +46 -0
- data/lib/postrunner/Main.rb +135 -33
- data/lib/postrunner/Percentiles.rb +45 -0
- data/lib/postrunner/PersonalRecords.rb +203 -114
- data/lib/postrunner/RecordListPageView.rb +6 -6
- data/lib/postrunner/UserProfileView.rb +4 -0
- data/lib/postrunner/version.rb +1 -1
- data/misc/postrunner/trackview.js +99 -0
- data/postrunner.gemspec +5 -5
- data/spec/ActivitySummary_spec.rb +15 -4
- data/spec/FitFileStore_spec.rb +133 -0
- data/spec/FlexiTable_spec.rb +1 -1
- data/spec/PersonalRecords_spec.rb +206 -0
- data/spec/PostRunner_spec.rb +64 -60
- data/spec/View_spec.rb +1 -1
- data/spec/spec_helper.rb +76 -2
- metadata +42 -28
@@ -17,6 +17,7 @@ require 'postrunner/View'
|
|
17
17
|
require 'postrunner/ViewFrame'
|
18
18
|
require 'postrunner/ViewButtons'
|
19
19
|
require 'postrunner/PagingButtons'
|
20
|
+
require 'postrunner/Activity'
|
20
21
|
|
21
22
|
module PostRunner
|
22
23
|
|
@@ -27,16 +28,15 @@ module PostRunner
|
|
27
28
|
include Fit4Ruby::Converters
|
28
29
|
|
29
30
|
# Create a RecordListPageView object.
|
30
|
-
# @param
|
31
|
+
# @param ffs [FitFileStore] Activity database
|
31
32
|
# @param records [PersonalRecords] Database with personal records
|
32
33
|
# @param page_count [Fixnum] Number of total pages
|
33
34
|
# @param page_index [Fixnum] Index of the page
|
34
|
-
def initialize(
|
35
|
-
|
36
|
-
@unit_system = @db.cfg[:unit_system]
|
35
|
+
def initialize(ffs, records, page_count, page_index)
|
36
|
+
#@unit_system = ffs.store['config']['unit_system']
|
37
37
|
@records = records
|
38
38
|
|
39
|
-
views =
|
39
|
+
views = ffs.views
|
40
40
|
views.current_page = "records-0.html"
|
41
41
|
|
42
42
|
pages = PagingButtons.new((0..(page_count - 1)).map do |i|
|
@@ -55,7 +55,7 @@ module PostRunner
|
|
55
55
|
ViewFrame.new("All-time #{@sport_name} Records",
|
56
56
|
frame_width, @records.all_time).to_html(@doc)
|
57
57
|
|
58
|
-
@records.yearly.sort{ |y1, y2| y2[0] <=> y1[0] }.
|
58
|
+
@records.yearly.sort{ |y1, y2| y2[0].to_i <=> y1[0].to_i }.
|
59
59
|
each do |year, record|
|
60
60
|
next if record.empty?
|
61
61
|
ViewFrame.new("#{year} #{@sport_name} Records",
|
@@ -57,6 +57,10 @@ module PostRunner
|
|
57
57
|
if profile.activity_class
|
58
58
|
t.row([ 'Activity Class:', profile.activity_class ])
|
59
59
|
end
|
60
|
+
if profile.metmax
|
61
|
+
t.row([ 'METmax:', "#{profile.metmax} MET" ])
|
62
|
+
t.row([ 'VO2max:', "#{'%.1f' % (profile.metmax * 3.5)} ml/kg/min" ])
|
63
|
+
end
|
60
64
|
t
|
61
65
|
end
|
62
66
|
|
data/lib/postrunner/version.rb
CHANGED
@@ -0,0 +1,99 @@
|
|
1
|
+
/*
|
2
|
+
* TrackView.rb -- PostRunner - Manage the data from your Garmin sport devices.
|
3
|
+
*
|
4
|
+
* Copyright (c) 2014 by Chris Schlaeger <cs@taskjuggler.org>
|
5
|
+
*
|
6
|
+
* This program is free software; you can redistribute it and/or modify
|
7
|
+
* it under the terms of version 2 of the GNU General Public License as
|
8
|
+
* published by the Free Software Foundation.
|
9
|
+
*/
|
10
|
+
|
11
|
+
var pr_trackview_init = function(center_long, center_lat) {
|
12
|
+
lm_w = 40;
|
13
|
+
lm_h = 100;
|
14
|
+
|
15
|
+
pr_transformer = function(coords, i, arr) {
|
16
|
+
arr[i] = ol.proj.transform(coords, 'EPSG:4326', 'EPSG:900913');
|
17
|
+
};
|
18
|
+
|
19
|
+
pr_track_points.forEach(pr_transformer);
|
20
|
+
pr_lap_markers.forEach(pr_transformer);
|
21
|
+
|
22
|
+
var map = new ol.Map({
|
23
|
+
view: new ol.View({
|
24
|
+
center: ol.proj.transform([ center_long, center_lat ],
|
25
|
+
'EPSG:4326', 'EPSG:900913'),
|
26
|
+
zoom: 14,
|
27
|
+
}),
|
28
|
+
layers: [
|
29
|
+
new ol.layer.Tile({
|
30
|
+
source: new ol.source.MapQuest({layer: 'osm'})
|
31
|
+
}),
|
32
|
+
new ol.layer.Vector({
|
33
|
+
source: source_vector = new ol.source.Vector({
|
34
|
+
features: [
|
35
|
+
new ol.Feature({
|
36
|
+
geometry: new ol.geom.LineString(pr_track_points)
|
37
|
+
})
|
38
|
+
]
|
39
|
+
}),
|
40
|
+
style: [
|
41
|
+
new ol.style.Style({
|
42
|
+
stroke: new ol.style.Stroke({
|
43
|
+
color: 'red',
|
44
|
+
width: 5
|
45
|
+
}),
|
46
|
+
fill: new ol.style.Fill({
|
47
|
+
color: 'white'
|
48
|
+
})
|
49
|
+
})
|
50
|
+
]
|
51
|
+
}),
|
52
|
+
new ol.layer.Vector({
|
53
|
+
source: lap_marker_source = new ol.source.Vector(),
|
54
|
+
style: function(feature, resolution) {
|
55
|
+
return [
|
56
|
+
new ol.style.Style({
|
57
|
+
stroke: new ol.style.Stroke({
|
58
|
+
color: 'black',
|
59
|
+
width: 2
|
60
|
+
}),
|
61
|
+
fill: new ol.style.Fill({
|
62
|
+
color: feature.get('color')
|
63
|
+
}),
|
64
|
+
text: new ol.style.Text({
|
65
|
+
font: '' + (lm_w / resolution) + 'px helvetica,sans-serif',
|
66
|
+
text: resolution < (lm_w / 8.0) ? feature.get('name') : '',
|
67
|
+
fill: new ol.style.Fill({
|
68
|
+
color: 'black'
|
69
|
+
})
|
70
|
+
})
|
71
|
+
})
|
72
|
+
];
|
73
|
+
}
|
74
|
+
})
|
75
|
+
],
|
76
|
+
target: "map"
|
77
|
+
});
|
78
|
+
for (var i in pr_lap_markers) {
|
79
|
+
x = pr_lap_markers[i][0];
|
80
|
+
y = pr_lap_markers[i][1];
|
81
|
+
lap_marker_source.addFeature(
|
82
|
+
new ol.Feature({
|
83
|
+
geometry: new ol.geom.Polygon([[[ x - lm_w, y + lm_h ],
|
84
|
+
[ x, y ],
|
85
|
+
[ x + lm_w, y + lm_h ],
|
86
|
+
[ x - lm_w, y + lm_h ]]])
|
87
|
+
})
|
88
|
+
);
|
89
|
+
lap_marker_source.addFeature(
|
90
|
+
new ol.Feature({
|
91
|
+
geometry: new ol.geom.Circle([ x, y + lm_h ], lm_w),
|
92
|
+
name: (i == 0 ? 'S' : i == pr_lap_markers.length - 1 ? 'F' : i),
|
93
|
+
color: (i == 0 ? 'green' :
|
94
|
+
i == pr_lap_markers.length - 1 ? 'red' : 'yellow'),
|
95
|
+
})
|
96
|
+
);
|
97
|
+
};
|
98
|
+
};
|
99
|
+
|
data/postrunner.gemspec
CHANGED
@@ -7,9 +7,9 @@ Gem::Specification.new do |spec|
|
|
7
7
|
spec.name = "postrunner"
|
8
8
|
spec.version = PostRunner::VERSION
|
9
9
|
spec.authors = ["Chris Schlaeger"]
|
10
|
-
spec.email = ["
|
10
|
+
spec.email = ["cs@taskjuggler.org"]
|
11
11
|
spec.summary = %q{Application to manage and analyze Garmin FIT files.}
|
12
|
-
spec.description = %q{This application will allow you to manage and analyze .FIT files such as those generated by Garmin GPS devices. The application was developed and tested with the Garmin Forerunner 620 and Fenix 3. Other devices may work as well. They need to export the data as USB Mass Storage devices.}
|
12
|
+
spec.description = %q{This application will allow you to manage and analyze .FIT files such as those generated by Garmin GPS devices. The application was developed and tested with the Garmin Forerunner 620 and Fenix 3. Other devices may work as well. They need to export the data as USB Mass Storage devices. It is an offline alternative to Garmin Connect.}
|
13
13
|
spec.homepage = 'https://github.com/scrapper/postrunner'
|
14
14
|
spec.license = "GNU GPL version 2"
|
15
15
|
|
@@ -19,12 +19,12 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
spec.required_ruby_version = '>=2.0'
|
21
21
|
|
22
|
-
spec.add_dependency 'fit4ruby', '~> 0.0.
|
23
|
-
spec.add_dependency 'perobs', '~>
|
22
|
+
spec.add_dependency 'fit4ruby', '~> 0.0.9'
|
23
|
+
spec.add_dependency 'perobs', '~> 2.2'
|
24
24
|
spec.add_dependency 'nokogiri', '~> 1.6'
|
25
25
|
|
26
26
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
27
27
|
spec.add_development_dependency 'rake', '~> 0.9.6'
|
28
|
-
spec.add_development_dependency 'rspec', '~>
|
28
|
+
spec.add_development_dependency 'rspec', '~> 3.4.1'
|
29
29
|
spec.add_development_dependency 'yard', '~> 0.8.7'
|
30
30
|
end
|
@@ -18,16 +18,27 @@ end
|
|
18
18
|
|
19
19
|
describe PostRunner::ActivitySummary do
|
20
20
|
|
21
|
+
before(:all) do
|
22
|
+
capture_stdio
|
23
|
+
create_working_dirs
|
24
|
+
create_fit_file_store
|
25
|
+
end
|
26
|
+
|
21
27
|
before(:each) do
|
22
|
-
|
23
|
-
|
24
|
-
|
28
|
+
acfg = { :t => '2014-08-26T19:00', :duration => 30, :serial => 123456790 }
|
29
|
+
fn = create_fit_activity_file(@fit_dir, acfg)
|
30
|
+
fa = @ffs.add_fit_file(fn)
|
31
|
+
@as = PostRunner::ActivitySummary.new(fa, :metric,
|
25
32
|
{ :name => 'test', :type => 'Running',
|
26
33
|
:sub_type => 'Street' })
|
27
34
|
end
|
28
35
|
|
36
|
+
after(:all) do
|
37
|
+
cleanup
|
38
|
+
end
|
39
|
+
|
29
40
|
it 'should create a metric summary' do
|
30
|
-
|
41
|
+
@as.to_s #TODO: Fix aggregation first
|
31
42
|
end
|
32
43
|
|
33
44
|
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
# encoding: UTF-8
|
3
|
+
#
|
4
|
+
# = PostRunner_spec.rb -- PostRunner - Manage the data from your Garmin sport devices.
|
5
|
+
#
|
6
|
+
# Copyright (c) 2014, 2015, 2016 by Chris Schlaeger <cs@taskjuggler.org>
|
7
|
+
#
|
8
|
+
# This program is free software; you can redistribute it and/or modify
|
9
|
+
# it under the terms of version 2 of the GNU General Public License as
|
10
|
+
# published by the Free Software Foundation.
|
11
|
+
#
|
12
|
+
|
13
|
+
require 'spec_helper'
|
14
|
+
|
15
|
+
require 'fit4ruby/FileNameCoder'
|
16
|
+
require 'postrunner/RuntimeConfig'
|
17
|
+
require 'postrunner/FitFileStore'
|
18
|
+
require 'postrunner/PersonalRecords'
|
19
|
+
|
20
|
+
describe PostRunner::FitFileStore do
|
21
|
+
|
22
|
+
before(:all) do
|
23
|
+
capture_stdio
|
24
|
+
create_working_dirs
|
25
|
+
create_fit_file_store
|
26
|
+
|
27
|
+
# Create some test fit files
|
28
|
+
@fit_file_names = []
|
29
|
+
[
|
30
|
+
{ :t => '2015-10-21T21:00', :duration => 10, :serial => 123456790 },
|
31
|
+
{ :t => '2015-10-22T08:10', :duration => 15, :serial => 123456791 },
|
32
|
+
{ :t => '2015-11-01T13:30', :duration => 20, :serial => 123456790 }
|
33
|
+
].each do |config|
|
34
|
+
f = create_fit_activity_file(@fit_dir, config)
|
35
|
+
@fit_file_names << f
|
36
|
+
end
|
37
|
+
@activities = []
|
38
|
+
end
|
39
|
+
|
40
|
+
after(:all) do
|
41
|
+
cleanup
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should be empty at start' do
|
45
|
+
expect(@ffs.devices.length).to eq(0)
|
46
|
+
expect(@ffs.activities.length).to eq(0)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should store a FIT file' do
|
50
|
+
@activities << @ffs.add_fit_file(@fit_file_names[0])
|
51
|
+
expect(@activities[-1]).not_to be_nil
|
52
|
+
|
53
|
+
expect(@ffs.devices.length).to eq(1)
|
54
|
+
expect(@ffs.devices.include?('garmin-fenix3-123456790')).to be true
|
55
|
+
expect(@ffs.activities.length).to eq(1)
|
56
|
+
expect(@ffs.ref_by_activity(@activities[0])).to eq(1)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should not store the same FIT file twice' do
|
60
|
+
expect(@ffs.add_fit_file(@fit_file_names[0])).to be_nil
|
61
|
+
|
62
|
+
expect(@ffs.devices.length).to eq(1)
|
63
|
+
expect(@ffs.devices.include?('garmin-fenix3-123456790')).to be true
|
64
|
+
expect(@ffs.activities.length).to eq(1)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should store another FIT file as 2nd device' do
|
68
|
+
@activities << @ffs.add_fit_file(@fit_file_names[1])
|
69
|
+
expect(@activities[-1]).not_to be_nil
|
70
|
+
|
71
|
+
expect(@ffs.devices.length).to eq(2)
|
72
|
+
expect(@ffs.devices.include?('garmin-fenix3-123456790')).to be true
|
73
|
+
expect(@ffs.devices.include?('garmin-fenix3-123456791')).to be true
|
74
|
+
expect(@ffs.activities.length).to eq(2)
|
75
|
+
expect(@ffs.ref_by_activity(@activities[1])).to eq(1)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should store another activity of a known device' do
|
79
|
+
@activities << @ffs.add_fit_file(@fit_file_names[2])
|
80
|
+
expect(@activities[-1]).not_to be_nil
|
81
|
+
|
82
|
+
expect(@ffs.devices.length).to eq(2)
|
83
|
+
expect(@ffs.devices.include?('garmin-fenix3-123456790')).to be true
|
84
|
+
expect(@ffs.devices.include?('garmin-fenix3-123456791')).to be true
|
85
|
+
expect(@ffs.activities.length).to eq(3)
|
86
|
+
expect(@ffs.ref_by_activity(@activities[2])).to eq(1)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should find activities by index' do
|
90
|
+
expect(@ffs.find('0')).to eq([])
|
91
|
+
expect(@ffs.find('1')).to eq([ @activities[2] ])
|
92
|
+
expect(@ffs.find('2')).to eq([ @activities[1] ])
|
93
|
+
expect(@ffs.find('3')).to eq([ @activities[0] ])
|
94
|
+
expect(@ffs.find('1-2')).to eq([ @activities[2], @activities[1] ])
|
95
|
+
expect(@ffs.find('2-1')).to eq([])
|
96
|
+
expect(@ffs.find('')).to eq([])
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should check all stored fit files' do
|
100
|
+
@ffs.check
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should know the successor of each activity' do
|
104
|
+
expect(@ffs.successor(@activities[2])).to be_nil
|
105
|
+
expect(@ffs.successor(@activities[1])).to eq(@activities[2])
|
106
|
+
expect(@ffs.successor(@activities[0])).to eq(@activities[1])
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'should know the predecessor of each activity' do
|
110
|
+
expect(@ffs.predecessor(@activities[2])).to eq(@activities[1])
|
111
|
+
expect(@ffs.predecessor(@activities[1])).to eq(@activities[0])
|
112
|
+
expect(@ffs.predecessor(@activities[0])).to be_nil
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should delete activities' do
|
116
|
+
@ffs.delete_activity(@activities[1])
|
117
|
+
expect(@ffs.find('1')).to eq([ @activities[2] ])
|
118
|
+
expect(@ffs.find('2')).to eq([ @activities[0] ])
|
119
|
+
expect(@ffs.find('3')).to eq([])
|
120
|
+
|
121
|
+
@ffs.delete_activity(@activities[2])
|
122
|
+
expect(@ffs.find('1')).to eq([ @activities[0] ])
|
123
|
+
expect(@ffs.find('2')).to eq([])
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'should rename an activity' do
|
127
|
+
@ffs.rename_activity(@activities[0], 'new name')
|
128
|
+
expect(@activities[0].name).to eq('new name')
|
129
|
+
expect(@activities[0].fit_file_name).to eq(File.basename(@fit_file_names[0]))
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
data/spec/FlexiTable_spec.rb
CHANGED
@@ -0,0 +1,206 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
# encoding: UTF-8
|
3
|
+
#
|
4
|
+
# = PostRunner_spec.rb -- PostRunner - Manage the data from your Garmin sport devices.
|
5
|
+
#
|
6
|
+
# Copyright (c) 2014, 2015, 2016 by Chris Schlaeger <cs@taskjuggler.org>
|
7
|
+
#
|
8
|
+
# This program is free software; you can redistribute it and/or modify
|
9
|
+
# it under the terms of version 2 of the GNU General Public License as
|
10
|
+
# published by the Free Software Foundation.
|
11
|
+
#
|
12
|
+
|
13
|
+
require 'spec_helper'
|
14
|
+
require 'perobs'
|
15
|
+
|
16
|
+
require 'fit4ruby/FileNameCoder'
|
17
|
+
require 'postrunner/FitFileStore'
|
18
|
+
require 'postrunner/PersonalRecords'
|
19
|
+
|
20
|
+
describe PostRunner::PersonalRecords do
|
21
|
+
|
22
|
+
class Mock_Activity < PEROBS::Object
|
23
|
+
|
24
|
+
po_attr :name, :fit_file_name
|
25
|
+
|
26
|
+
def initialize(store, name = nil)
|
27
|
+
super(store)
|
28
|
+
init_attr(:name, name)
|
29
|
+
init_attr(:fit_file_name, name)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
class Mock_FitFileStore < PEROBS::Object
|
35
|
+
|
36
|
+
po_attr :activities
|
37
|
+
|
38
|
+
def initialize(store)
|
39
|
+
super
|
40
|
+
init_attr(:activities, @store.new(PEROBS::Array))
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_activity(a)
|
44
|
+
@activities << a
|
45
|
+
end
|
46
|
+
|
47
|
+
def ref_by_activity(a)
|
48
|
+
@activities.index(a) + 1
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
before(:all) do
|
54
|
+
@log = StringIO.new
|
55
|
+
Fit4Ruby::Log.open(@log)
|
56
|
+
@work_dir = tmp_dir_name(__FILE__)
|
57
|
+
Dir.mkdir(@work_dir)
|
58
|
+
|
59
|
+
# Create the FitFileStore
|
60
|
+
@store = PEROBS::Store.new(File.join(@work_dir, 'db'))
|
61
|
+
@store['config'] = @store.new(PEROBS::Hash)
|
62
|
+
@store['config']['data_dir'] = @work_dir
|
63
|
+
@ffs = @store['file_store'] = @store.new(Mock_FitFileStore)
|
64
|
+
@records = @store['records'] = @store.new(PostRunner::PersonalRecords)
|
65
|
+
end
|
66
|
+
|
67
|
+
after(:all) do
|
68
|
+
FileUtils.rm_rf(@work_dir)
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should initialize properly' do
|
72
|
+
expect(@records.to_s).to eq('')
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should register a record' do
|
76
|
+
a = @store.new(Mock_Activity, 'Activity 1')
|
77
|
+
@ffs.add_activity(a)
|
78
|
+
t = Time.parse('2014-11-08T09:16:00')
|
79
|
+
expect(@records.register_result(a, 'running', 5000.0, 20 * 60,
|
80
|
+
t)).to be true
|
81
|
+
expect(@records.register_result(a, 'running', 5000.0, nil, t)).to be true
|
82
|
+
expect(@records.activity_records(a).length).to eq(4)
|
83
|
+
expect(tables_to_arrays(@records.to_s)).to eq([
|
84
|
+
[["5 km", "0:20:00", "4:00", "1", "Activity 1", "2014-11-08"],
|
85
|
+
["Longest Distance", "5.000 km", "-", "1", "Activity 1", "2014-11-08"]],
|
86
|
+
[["5 km", "0:20:00", "4:00", "1", "Activity 1", "2014-11-08"],
|
87
|
+
["Longest Distance", "5.000 km", "-", "1", "Activity 1", "2014-11-08"]]
|
88
|
+
])
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should register another record' do
|
92
|
+
a = @store.new(Mock_Activity, 'Activity 2')
|
93
|
+
@ffs.add_activity(a)
|
94
|
+
t = Time.parse('2014-11-09T09:16:00')
|
95
|
+
expect(@records.register_result(a, 'running', 10000.0,
|
96
|
+
42 * 60, t)).to be true
|
97
|
+
expect(@records.register_result(a, 'running', 10000.0,
|
98
|
+
nil, t)).to be true
|
99
|
+
expect(@records.activity_records(a).length).to eq(4)
|
100
|
+
expect(tables_to_arrays(@records.to_s)).to eq([
|
101
|
+
[["5 km", "0:20:00", "4:00", "1", "Activity 1", "2014-11-08"],
|
102
|
+
["10 km", "0:42:00", "4:12", "2", "Activity 2", "2014-11-09"],
|
103
|
+
["Longest Distance", "10.000 km", "-", "2", "Activity 2", "2014-11-09"]],
|
104
|
+
[["5 km", "0:20:00", "4:00", "1", "Activity 1", "2014-11-08"],
|
105
|
+
["10 km", "0:42:00", "4:12", "2", "Activity 2", "2014-11-09"],
|
106
|
+
["Longest Distance", "10.000 km", "-", "2", "Activity 2", "2014-11-09"]],
|
107
|
+
])
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should replace an old record with a new one' do
|
111
|
+
a = @store.new(Mock_Activity, 'Activity 3')
|
112
|
+
@ffs.add_activity(a)
|
113
|
+
t = Time.parse('2014-11-11T09:16:00')
|
114
|
+
expect(@records.register_result(a, 'running', 5000.0,
|
115
|
+
19 * 60, t)).to be true
|
116
|
+
expect(@records.activity_records(a).length).to eq (2)
|
117
|
+
expect(@records.activity_records(@ffs.activities[0]).length).to eq(0)
|
118
|
+
expect(tables_to_arrays(@records.to_s)).to eq([
|
119
|
+
[["5 km", "0:19:00", "3:47", "3", "Activity 3", "2014-11-11"],
|
120
|
+
["10 km", "0:42:00", "4:12", "2", "Activity 2", "2014-11-09"],
|
121
|
+
["Longest Distance", "10.000 km", "-", "2", "Activity 2", "2014-11-09"]],
|
122
|
+
[["5 km", "0:19:00", "3:47", "3", "Activity 3", "2014-11-11"],
|
123
|
+
["10 km", "0:42:00", "4:12", "2", "Activity 2", "2014-11-09"],
|
124
|
+
["Longest Distance", "10.000 km", "-", "2", "Activity 2", "2014-11-09"]],
|
125
|
+
])
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'should add a new table for a new year' do
|
129
|
+
a = @store.new(Mock_Activity, 'Activity 4')
|
130
|
+
@ffs.add_activity(a)
|
131
|
+
t = Time.parse('2015-01-01T06:00:00')
|
132
|
+
expect(@records.register_result(a, 'running', 5000.0,
|
133
|
+
21 * 60, t)).to be true
|
134
|
+
expect(@records.activity_records(a).length).to eq(1)
|
135
|
+
expect(tables_to_arrays(@records.to_s)).to eq([
|
136
|
+
[["5 km", "0:19:00", "3:47", "3", "Activity 3", "2014-11-11"],
|
137
|
+
["10 km", "0:42:00", "4:12", "2", "Activity 2", "2014-11-09"],
|
138
|
+
["Longest Distance", "10.000 km", "-", "2", "Activity 2", "2014-11-09"]],
|
139
|
+
[["5 km", "0:21:00", "4:12", "4", "Activity 4", "2015-01-01"]],
|
140
|
+
[["5 km", "0:19:00", "3:47", "3", "Activity 3", "2014-11-11"],
|
141
|
+
["10 km", "0:42:00", "4:12", "2", "Activity 2", "2014-11-09"],
|
142
|
+
["Longest Distance", "10.000 km", "-", "2", "Activity 2", "2014-11-09"]],
|
143
|
+
])
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'should not add a new record for poor result' do
|
147
|
+
a = @store.new(Mock_Activity, 'Activity 5')
|
148
|
+
@ffs.add_activity(a)
|
149
|
+
t = Time.parse('2015-01-02T10:00:00')
|
150
|
+
expect(@records.register_result(a, 'running', 5000.0, 22 * 60,
|
151
|
+
t)).to be false
|
152
|
+
expect(@records.activity_records(a).length).to eq(0)
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'should not delete a record for non-record activity' do
|
156
|
+
expect(@records.delete_activity(@ffs.activities[0])).to be false
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'should delete a record for a record activity' do
|
160
|
+
expect(@records.delete_activity(@ffs.activities[2])).to be true
|
161
|
+
expect(tables_to_arrays(@records.to_s)).to eq([
|
162
|
+
[["10 km", "0:42:00", "4:12", "2", "Activity 2", "2014-11-09"],
|
163
|
+
["Longest Distance", "10.000 km", "-", "2", "Activity 2", "2014-11-09"]],
|
164
|
+
[["5 km", "0:21:00", "4:12", "4", "Activity 4", "2015-01-01"]],
|
165
|
+
[["10 km", "0:42:00", "4:12", "2", "Activity 2", "2014-11-09"],
|
166
|
+
["Longest Distance", "10.000 km", "-", "2", "Activity 2", "2014-11-09"]],
|
167
|
+
])
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'should add a new distance record' do
|
171
|
+
a = @store.new(Mock_Activity, 'Activity 6')
|
172
|
+
@ffs.add_activity(a)
|
173
|
+
t = Time.parse('2015-01-10T07:00:00')
|
174
|
+
expect(@records.register_result(a, 'running', 15000.0, nil, t)).to be true
|
175
|
+
expect(@records.activity_records(a).length).to eq(2)
|
176
|
+
expect(tables_to_arrays(@records.to_s)).to eq([
|
177
|
+
[ ["10 km", "0:42:00", "4:12", "2", "Activity 2", "2014-11-09"],
|
178
|
+
["Longest Distance", "15.000 km", "-", "6", "Activity 6", "2015-01-10"]],
|
179
|
+
[["5 km", "0:21:00", "4:12", "4", "Activity 4", "2015-01-01"],
|
180
|
+
["Longest Distance", "15.000 km", "-", "6", "Activity 6", "2015-01-10"]],
|
181
|
+
[["10 km", "0:42:00", "4:12", "2", "Activity 2", "2014-11-09"],
|
182
|
+
["Longest Distance", "10.000 km", "-", "2", "Activity 2", "2014-11-09"]],
|
183
|
+
])
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'should not register a record for a bogus sport' do
|
187
|
+
a = @store.new(Mock_Activity, 'Activity 5')
|
188
|
+
@ffs.add_activity(a)
|
189
|
+
t = Time.parse('2015-04-01T11:11:11')
|
190
|
+
expect(@records.register_result(a, 'foobaring', 5000.0, 10 * 60,
|
191
|
+
t)).to be false
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'should not register a record for unknown distance' do
|
195
|
+
a = @store.new(Mock_Activity, 'Activity 6')
|
196
|
+
@ffs.add_activity(a)
|
197
|
+
expect { @records.register_result(a, 'cycling', 42.0, 10 * 60,
|
198
|
+
Time.parse('2015-04-01T11:11:11'))}.to raise_error(Fit4Ruby::Error)
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'should delete all records' do
|
202
|
+
@records.delete_all_records
|
203
|
+
expect(@records.to_s).to eq('')
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|