source: OpenWorkouts-current/ow/tests/test_utilities.py @ ceae158

currentfeature/docs
Last change on this file since ceae158 was ceae158, checked in by borja <borja@…>, 5 years ago

Added missing tests covering the map screenshots feature

  • Property mode set to 100644
File size: 7.5 KB
Line 
1import os
2from datetime import timedelta
3from unittest.mock import patch
4from pyexpat import ExpatError
5from xml.dom.minidom import Element
6
7import pytest
8
9from ow.models.root import OpenWorkouts
10from ow.models.user import User
11from ow.models.workout import Workout
12
13from ow.utilities import (
14    slugify,
15    GPXMinidomParser,
16    semicircles_to_degrees,
17    degrees_to_semicircles,
18    miles_to_kms,
19    kms_to_miles,
20    meters_to_kms,
21    kms_to_meters,
22    mps_to_kmph,
23    kmph_to_mps,
24    save_map_screenshot
25)
26
27from ow.tests.helpers import join
28
29
30class TestUtilities(object):
31
32    @pytest.fixture
33    def john(self):
34        john = User(firstname='John', lastname='Doe',
35                    email='john.doe@example.net')
36        john.password = 's3cr3t'
37        return john
38
39    @pytest.fixture
40    def root(self, john):
41        root = OpenWorkouts()
42        root.add_user(john)
43        john['1'] = Workout(
44            duration=timedelta(minutes=60),
45            distance=30
46        )
47        return root
48
49    def test_slugify(self):
50        res = slugify(u'long story SHORT      ')
51        assert res == u'long-story-short'
52        res = slugify(u'bla \u03ba\u03b1\u03bb\u03ac \u03c0\u03b1\u03c2')
53        assert res == u'bla-kala-pas'
54
55    def test_slugify_special_chars(self):
56        res = slugify(u'(r)-[i]\u00AE')
57        assert res == u'r-i-r'
58
59    def test_semicircles_to_degrees(self):
60        assert semicircles_to_degrees(10) == 10 * (180 / pow(2, 31))
61
62    def test_degrees_to_semicircles(self):
63        assert degrees_to_semicircles(10) == 10 * (pow(2, 31) / 180)
64
65    def test_miles_to_kms(self):
66        assert miles_to_kms(100) == 100 / 0.62137119
67
68    def test_kms_to_miles(self):
69        assert kms_to_miles(100) == 100 * 0.62137119
70
71    def test_meters_to_kms(self):
72        assert meters_to_kms(1000) == 1
73
74    def test_kms_to_meters(self):
75        assert kms_to_meters(1) == 1000
76
77    def test_mps_to_kmph(self):
78        assert mps_to_kmph(5) == 5 * 3.6
79
80    def test_kmph_to_mps(self):
81        assert kmph_to_mps(30) == 30 * 0.277778
82
83    @patch('ow.utilities.os')
84    @patch('ow.utilities.subprocess')
85    def test_save_map_screenshot_no_gpx(self, subprocess, os, root, john):
86        saved = save_map_screenshot(john['1'])
87        assert not saved
88        assert not os.path.abspath.called
89        assert not os.path.dirname.called
90        assert not os.path.join.called
91        assert not os.path.exists.called
92        assert not os.makedirs.called
93        assert not subprocess.run.called
94        # even having a fit tracking file, nothing is done
95        john['1'].tracking_file = 'faked fit file'
96        john['1'].tracking_filetype = 'fit'
97        saved = save_map_screenshot(john['1'])
98        assert not saved
99        assert not os.path.abspath.called
100        assert not os.path.dirname.called
101        assert not os.path.join.called
102        assert not os.path.exists.called
103        assert not os.makedirs.called
104        assert not subprocess.run.called
105
106    @patch('ow.utilities.os')
107    @patch('ow.utilities.subprocess')
108    def test_save_map_screenshot_with_gpx(self, subprocess, os, root, john):
109        os.path.abspath.return_value = 'current_dir'
110        os.path.join.side_effect = join
111        # This mimics what happens when the directory for this user map
112        # screenshots does not exist, which means we don'have to create one
113        # (calling os.makedirs)
114        os.path.exists.return_value = False
115
116        john['1'].tracking_file = 'faked gpx content'
117        john['1'].tracking_filetype = 'gpx'
118        saved = save_map_screenshot(john['1'])
119        assert saved
120        os.path.abspath.assert_called_once
121        assert os.path.dirname.called
122        assert os.path.join.call_count == 3
123        assert os.path.exists.called
124        assert os.makedirs.called
125        subprocess.run.assert_called_once
126
127    @patch('ow.utilities.os')
128    @patch('ow.utilities.subprocess')
129    def test_save_map_screenshot_with_gpx_makedirs(
130            self, subprocess, os, root, john):
131        os.path.abspath.return_value = 'current_dir'
132        os.path.join.side_effect = join
133        # If os.path.exists returns True, makedirs is not called
134        os.path.exists.return_value = True
135
136        john['1'].tracking_file = 'faked gpx content'
137        john['1'].tracking_filetype = 'gpx'
138        saved = save_map_screenshot(john['1'])
139        assert saved
140        os.path.abspath.assert_called_once
141        assert os.path.dirname.called
142        assert os.path.join.call_count == 3
143        assert os.path.exists.called
144        assert not os.makedirs.called
145        subprocess.run.assert_called_once
146
147
148class TestGPXParseMinidom(object):
149
150    def gpx_file(self, filename):
151        """
152        Return the full path to the given filename from the available fixtures
153        """
154        here = os.path.abspath(os.path.dirname(__file__))
155        path = os.path.join(here, 'fixtures', filename)
156        return path
157
158    def test_load_gpx_invalid(self):
159        gpx_file = self.gpx_file('invalid.gpx')
160        parser = GPXMinidomParser(gpx_file)
161        with pytest.raises(ExpatError):
162            parser.load_gpx()
163        assert parser.gpx is None
164
165    gpx_files = [
166        ('empty.gpx', Element),
167        ('20131013.gpx', Element),  # GPX 1.0 file
168        ('20160129-with-extensions.gpx', Element),  # GPX 1.1 file with ext.
169    ]
170
171    @pytest.mark.parametrize(('filename', 'expected'), gpx_files)
172    def test_load_gpx(self, filename, expected):
173        """
174        Loading valid gpx files ends in the gpx attribute of the parser
175        being a xml.dom.minidom.Element object, not matter if the gpx file
176        is empty or a 1.0/1.1 gpx file.
177        """
178        gpx_file = self.gpx_file(filename)
179        parser = GPXMinidomParser(gpx_file)
180        parser.load_gpx()
181        assert isinstance(parser.gpx, expected)
182
183    def test_parse_tracks_empty_gpx(self):
184        gpx_file = self.gpx_file('empty.gpx')
185        parser = GPXMinidomParser(gpx_file)
186        parser.load_gpx()
187        parser.parse_tracks()
188        assert parser.tracks == {}
189
190    def test_parse_tracks_1_0_gpx(self):
191        """
192        Parsing a GPX 1.0 file with no extensions. The points in the track
193        contain keys for the well-known extensions (hr, cad, atemp), but their
194        values are None
195        """
196        gpx_file = self.gpx_file('20131013.gpx')
197        parser = GPXMinidomParser(gpx_file)
198        parser.load_gpx()
199        parser.parse_tracks()
200        keys = list(parser.tracks.keys())
201        assert keys == [u'A ride I will never forget']
202        point = parser.tracks[keys[0]][0]
203        data = ['lat', 'lon', 'ele', 'time']
204        for d in data:
205            assert point[d] is not None
206        extensions = ['hr', 'cad', 'atemp']
207        for e in extensions:
208            assert point[e] is None
209
210    def test_parse_tracks_1_1_gpx(self):
211        """
212        Parsing a GPX 1.1 file with extensions. The points in the track contain
213        keys for the well-known extensions (hr, cad, atemp), with the values
214        taken from the gpx file (although we test only that they are not None)
215        """
216        gpx_file = self.gpx_file('20160129-with-extensions.gpx')
217        parser = GPXMinidomParser(gpx_file)
218        parser.load_gpx()
219        parser.parse_tracks()
220        keys = list(parser.tracks.keys())
221        assert keys == [
222            u'Cota counterclockwise + end bonus']
223        point = parser.tracks[keys[0]][0]
224        data = ['lat', 'lon', 'ele', 'time']
225        for d in data:
226            assert point[d] is not None
227        extensions = ['hr', 'cad', 'atemp']
228        for e in extensions:
229            assert point[e] is not None
Note: See TracBrowser for help on using the repository browser.