souplesse

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

UnitTest.hs (4766B)


      1 {-# LANGUAGE QuasiQuotes #-}
      2 
      3 module Main where
      4 
      5 import Control.Exception
      6 import Data.Either
      7 import Data.List as List
      8 import Data.Time qualified
      9 import Debug.Trace (trace, traceShow)
     10 import System.Exit qualified as Exit
     11 import Test.HUnit
     12 import Text.RawString.QQ (r)
     13 import Track qualified
     14 
     15 preamble =
     16   [r|
     17 <?xml version="1.0" encoding="UTF-8"?>
     18 <gpx
     19 version="1.1"
     20 creator="OpenTracks"
     21 xmlns="http://www.topografix.com/GPX/1/1"
     22 xmlns:topografix="http://www.topografix.com/GPX/Private/TopoGrafix/0/1"
     23 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     24 xmlns:opentracks="http://opentracksapp.com/xmlschemas/v1"
     25 xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v2"
     26 xmlns:gpxtrkx="http://www.garmin.com/xmlschemas/TrackStatsExtension/v1"
     27 xmlns:cluetrust="http://www.cluetrust.com/Schemas/"
     28 xmlns:pwr="http://www.garmin.com/xmlschemas/PowerExtension/v1"
     29 xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.topografix.com/GPX/Private/TopoGrafix/0/1 http://www.topografix.com/GPX/Private/TopoGrafix/0/1/topografix.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v2 https://www8.garmin.com/xmlschemas/TrackPointExtensionv2.xsd http://www.garmin.com/xmlschemas/PowerExtension/v1 https://www8.garmin.com/xmlschemas/PowerExtensionv1.xsd http://www.garmin.com/xmlschemas/TrackStatsExtension/v1 http://www.cluetrust.com/Schemas http://www.cluetrust.com/Schemas/gpxdata10.xsd http://opentracksapp.com/xmlschemas/v1 http://opentracksapp.com/xmlschemas/OpenTracks_v1.xsd">
     30 |]
     31 
     32 wrap x = preamble ++ x ++ "</gpx>"
     33 
     34 wrapPoint x =
     35   let trk = "<trk><trkseg>" ++ x ++ "</trkseg></trk>"
     36    in wrap trk
     37 
     38 onepoint =
     39   wrap
     40     [r|
     41 <trk> <trkseg>
     42 <trkpt lat="51" lon="-0.1">
     43    <time>2024-10-23T08:34:59.779+01:00</time>
     44 </trkpt>
     45 </trkseg> </trk>
     46 |]
     47 
     48 onepointWithAttrs =
     49   wrap
     50     [r|
     51 <trk>
     52  <trkseg>
     53   <trkpt lat="51" lon="-0.1">
     54    <ele>25.2</ele>
     55    <time>2024-10-23T08:34:59.779+01:00</time>
     56    <extensions><gpxtpx:TrackPointExtension>
     57     <gpxtpx:speed>2.4</gpxtpx:speed>
     58     <gpxtpx:cad>128</gpxtpx:cad>
     59     <gpxtpx:hr>160</gpxtpx:hr>
     60     <pwr:PowerInWatts>55</pwr:PowerInWatts>
     61     <opentracks:accuracy_horizontal>3.216</opentracks:accuracy_horizontal><opentracks:distance>10.675</opentracks:distance>
     62     <cluetrust:distance>32.025</cluetrust:distance>
     63     </gpxtpx:TrackPointExtension>
     64    </extensions>
     65   </trkpt>
     66  </trkseg>
     67 </trk>
     68 |]
     69 
     70 test1 =
     71   TestCase $
     72     either
     73       (assertFailure . displayException)
     74       ( assertEqual
     75           "empty track has no elements"
     76           0
     77           . Track.length
     78       )
     79       (Track.parse (wrap ""))
     80 
     81 testMalformed =
     82   TestCase $
     83     let trk = Track.parse (wrap "<dgdsfg>>")
     84      in assertBool "catches syntax error" (isLeft trk)
     85 
     86 testMissingAttrs =
     87   let els =
     88         [ [r|
     89 <trkpt lon="2" latsdf="51">
     90    <time>2024-10-23T08:34:59.779+01:00</time>
     91 </trkpt>
     92 |],
     93           [r|
     94 <trkpt lon="dsfgsdfg" lat="51">
     95    <time>2024-10-23T08:34:59.779+01:00</time>
     96 </trkpt>
     97 |],
     98           [r|
     99 <trkpt lon="2" lat="51">
    100    <time>2024-10-23G87sdCfdfgsdfhg</time>
    101 </trkpt>
    102 |]
    103         ]
    104    in TestCase $
    105         assertBool
    106           "failed to catch missing/malformed attribute"
    107           (List.all (isLeft . Track.parse . wrapPoint) els)
    108 
    109 test2 =
    110   TestList
    111     [ TestCase $
    112         either
    113           (assertFailure . displayException)
    114           ( \(p : _) ->
    115               assertEqual
    116                 "matches lat/lon"
    117                 (Track.Pos 51.0 (-0.1) Nothing)
    118                 (Track.pos p)
    119           )
    120           (Track.parse onepoint),
    121       TestCase $
    122         either
    123           (assertFailure . displayException)
    124           ( \(p : _) ->
    125               assertEqual
    126                 "matches lat/lon"
    127                 (Track.Pos 51.0 (-0.1) (Just 25.2))
    128                 (Track.pos p)
    129           )
    130           (Track.parse onepointWithAttrs)
    131     ]
    132 
    133 test3 =
    134   TestCase $
    135     either
    136       (assertFailure . displayException)
    137       ( \(p : _) ->
    138           assertEqual
    139             "handles missing attributes"
    140             (Nothing, Nothing)
    141             (Track.power p, Track.cadence p)
    142       )
    143       (Track.parse onepoint)
    144 
    145 test4 =
    146   TestCase $
    147     either
    148       (assertFailure . displayException)
    149       ( \(p : _) ->
    150           assertEqual
    151             "handles attributes"
    152             (Just 128, Just 55, Data.Time.UTCTime (toEnum 60606) 27299.779, Just 160)
    153             (Track.cadence p, Track.power p, Track.time p, Track.heartRate p)
    154       )
    155       (Track.parse onepointWithAttrs)
    156 
    157 tests :: Test
    158 tests =
    159   TestList
    160     [ test1,
    161       testMalformed,
    162       testMissingAttrs,
    163       test2,
    164       test3,
    165       test4
    166     ]
    167 
    168 main :: IO ()
    169 main = do
    170   result <- runTestTT tests
    171   if (failures result > 0) || (errors result > 0)
    172     then Exit.exitFailure
    173     else Exit.exitSuccess