Skip to content

Commit

Permalink
Use automatic spec discovery, run tests in parallel, upgrade package set
Browse files Browse the repository at this point in the history
  • Loading branch information
ad-si committed May 8, 2024
1 parent d55cba3 commit f8a510f
Show file tree
Hide file tree
Showing 11 changed files with 610 additions and 617 deletions.
2 changes: 1 addition & 1 deletion archive/tasklite-app/stack.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
resolver: lts-22.19
resolver: lts-22.20

packages:
- .
Expand Down
2 changes: 1 addition & 1 deletion stack.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# ATTENTION: Also update the version in the Dockerfile
resolver: lts-22.19
resolver: lts-22.20

packages:
- tasklite
Expand Down
6 changes: 3 additions & 3 deletions stack.yaml.lock
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ packages:
url: https://github.com/meteogrid/iso8601-duration/archive/9524d1f02775be1d6c73165c4b4d62a19c8b7698.tar.gz
snapshots:
- completed:
sha256: e5cac927cf7ccbd52aa41476baa68b88c564ee6ddc3bc573dbf4210069287fe7
sha256: 4a0e5e187fbef423f9c60072bfb1dd56f2a01a07a2667eb1469bd79073cfceaf
size: 713340
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/19.yaml
original: lts-22.19
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/20.yaml
original: lts-22.20
2 changes: 2 additions & 0 deletions tasklite-core/tasklite-core.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ test-suite tasklite-test
other-modules:
ImportExportSpec
LibSpec
MigrationsSpec
SpecHook
TestUtils
TypesSpec
UtilsSpec
Expand Down
278 changes: 139 additions & 139 deletions tasklite-core/test/ImportExportSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,15 @@ import Data.Text qualified as T
import Data.ULID (ULID)
import Database.SQLite.Simple (query_)
import Test.Hspec (
SpecWith,
describe,
Spec,
it,
shouldBe,
shouldNotBe,
shouldSatisfy,
shouldStartWith,
)

import Config (Config (..))
import Config (defaultConfig)
import FullTask (FullTask, emptyFullTask)
import FullTask qualified
import ImportExport (insertImportTask)
Expand All @@ -41,141 +40,142 @@ import TestUtils (withMemoryDb)
import Utils (emptyUlid, parseUtc, setDateTime, ulidText2utc, zeroTime)


spec :: Config -> SpecWith ()
spec conf = do
describe "Import & Export" $ do
it "parses any sensible datetime string" $ do
-- TODO: Maybe keep microseconds and nanoseconds
-- , ("YYYY-MM-DDTH:MI:S.msusZ", "2024-03-15T22:20:05.637913Z")
-- , ("YYYY-MM-DDTH:MI:S.msusnsZ", "2024-03-15T22:20:05.637913438Z")

let dateMap :: [(Text, Text)] =
[ ("YYYY-MM-DD", "2024-03-15")
, ("YYYY-MM-DD H:MI", "2024-03-15 22:20")
, ("YYYY-MM-DDTH:MIZ", "2024-03-15T22:20Z")
, ("YYYY-MM-DD H:MI:S", "2024-03-15 22:20:05")
, ("YYYY-MM-DDTH:MI:SZ", "2024-03-15T22:20:05Z")
, ("YYYYMMDDTHMIS", "20240315T222005")
, ("YYYY-MM-DDTH:MI:S.msZ", "2024-03-15T22:20:05.637Z")
, ("YYYY-MM-DDTH:MI:S.msZ", "2024-03-15T22:20:05.637123Z")
, ("YYYY-MM-DDTH:MI:S.msZ", "2024-03-15T22:20:05.637123456Z")
]

P.forM_ dateMap $ \(formatTxt, utcTxt) -> do
case parseUtc utcTxt of
Nothing -> P.die "Invalid UTC string"
Just utcStamp ->
let timeFmt = formatTxt & T.unpack & toFormat
in (utcStamp & timePrint timeFmt)
`shouldBe` T.unpack
( utcTxt
& T.replace "123" ""
& T.replace "456" ""
)
spec :: Spec
spec = do
let conf = defaultConfig

it "parses any sensible datetime string" $ do
-- TODO: Maybe keep microseconds and nanoseconds
-- , ("YYYY-MM-DDTH:MI:S.msusZ", "2024-03-15T22:20:05.637913Z")
-- , ("YYYY-MM-DDTH:MI:S.msusnsZ", "2024-03-15T22:20:05.637913438Z")

let dateMap :: [(Text, Text)] =
[ ("YYYY-MM-DD", "2024-03-15")
, ("YYYY-MM-DD H:MI", "2024-03-15 22:20")
, ("YYYY-MM-DDTH:MIZ", "2024-03-15T22:20Z")
, ("YYYY-MM-DD H:MI:S", "2024-03-15 22:20:05")
, ("YYYY-MM-DDTH:MI:SZ", "2024-03-15T22:20:05Z")
, ("YYYYMMDDTHMIS", "20240315T222005")
, ("YYYY-MM-DDTH:MI:S.msZ", "2024-03-15T22:20:05.637Z")
, ("YYYY-MM-DDTH:MI:S.msZ", "2024-03-15T22:20:05.637123Z")
, ("YYYY-MM-DDTH:MI:S.msZ", "2024-03-15T22:20:05.637123456Z")
]

P.forM_ dateMap $ \(formatTxt, utcTxt) -> do
case parseUtc utcTxt of
Nothing -> P.die "Invalid UTC string"
Just utcStamp ->
let timeFmt = formatTxt & T.unpack & toFormat
in (utcStamp & timePrint timeFmt)
`shouldBe` T.unpack
( utcTxt
& T.replace "123" ""
& T.replace "456" ""
)

let
utcTxt = "2024-03-15T22:20:05.386777444Z"
printFmt = "YYYY-MM-DDTH:MI:S.ms" & T.unpack & toFormat
-- Truncates microseconds and nanoseconds
expected = "2024-03-15T22:20:05.386"

(utcTxt & parseUtc <&> timePrint printFmt) `shouldBe` Just expected

it "imports a JSON task with notes" $ do
withMemoryDb conf $ \memConn -> do
let jsonTask = "{\"body\":\"Just a test\", \"notes\":[\"A note\"]}"

case eitherDecode jsonTask of
Left error ->
P.die $ "Error decoding JSON: " <> show error
Right importTaskRecord -> do
result <- insertImportTask memConn importTaskRecord

unpack (show result)
`shouldStartWith` "📥 Imported task \"Just a test\" with ulid "

taskToNotes :: [TaskToNote] <-
query_ memConn "SELECT * FROM task_to_note"
case taskToNotes of
[taskToNote] -> do
taskToNote `shouldSatisfy` (\task -> task.ulid /= "")
taskToNote `shouldSatisfy` (\task -> task.task_ulid /= "")
taskToNote `shouldSatisfy` (\task -> task.note == "A note")
_ -> P.die "More than one task_to_note row found"

tasks :: [FullTask] <- query_ memConn "SELECT * FROM tasks_view"

case tasks of
[updatedTask] -> do
updatedTask `shouldSatisfy` (\task -> task.ulid /= "")
updatedTask `shouldSatisfy` (\task -> task.modified_utc /= "")
updatedTask `shouldSatisfy` (\task -> task.user /= "")
updatedTask
{ FullTask.ulid = ""
, FullTask.modified_utc = ""
, FullTask.user = ""
}
`shouldBe` emptyFullTask
{ FullTask.body = "Just a test"
, -- TODO: Fix after notes are returned as a JSON array
FullTask.notes = Just []
, FullTask.priority = Just 1.0
, FullTask.metadata = decode jsonTask
}
_ -> P.die "More than one task found"

it "imports a JSON task with an ISO8601 created_at field" $ do
withMemoryDb conf $ \memConn -> do
let
utcTxt = "2024-03-15T22:20:05.386777444Z"
printFmt = "YYYY-MM-DDTH:MI:S.ms" & T.unpack & toFormat
-- Truncates microseconds and nanoseconds
expected = "2024-03-15T22:20:05.386"

(utcTxt & parseUtc <&> timePrint printFmt) `shouldBe` Just expected

it "imports a JSON task with notes" $ do
withMemoryDb conf $ \memConn -> do
let jsonTask = "{\"body\":\"Just a test\", \"notes\":[\"A note\"]}"

case eitherDecode jsonTask of
Left error ->
P.die $ "Error decoding JSON: " <> show error
Right importTaskRecord -> do
result <- insertImportTask memConn importTaskRecord

unpack (show result)
`shouldStartWith` "📥 Imported task \"Just a test\" with ulid "

taskToNotes :: [TaskToNote] <-
query_ memConn "SELECT * FROM task_to_note"
case taskToNotes of
[taskToNote] -> do
taskToNote `shouldSatisfy` (\task -> task.ulid /= "")
taskToNote `shouldSatisfy` (\task -> task.task_ulid /= "")
taskToNote `shouldSatisfy` (\task -> task.note == "A note")
_ -> P.die "More than one task_to_note row found"

tasks :: [FullTask] <- query_ memConn "SELECT * FROM tasks_view"

case tasks of
[updatedTask] -> do
updatedTask `shouldSatisfy` (\task -> task.ulid /= "")
updatedTask `shouldSatisfy` (\task -> task.modified_utc /= "")
updatedTask `shouldSatisfy` (\task -> task.user /= "")
updatedTask
{ FullTask.ulid = ""
, FullTask.modified_utc = ""
, FullTask.user = ""
}
`shouldBe` emptyFullTask
{ FullTask.body = "Just a test"
, -- TODO: Fix after notes are returned as a JSON array
FullTask.notes = Just []
, FullTask.priority = Just 1.0
, FullTask.metadata = decode jsonTask
}
_ -> P.die "More than one task found"

it "imports a JSON task with an ISO8601 created_at field" $ do
withMemoryDb conf $ \memConn -> do
let
utc = "2024-03-15T10:32:51.386777444Z"
-- ULID only has millisecond precision:
utcFromUlid = "2024-03-15 10:32:51.387"
jsonTask =
"{\"body\":\"Just a test\",\"created_at\":\"{{utc}}\"}"
& T.replace "{{utc}}" utc

case eitherDecodeStrictText jsonTask of
Left error ->
P.die $ "Error decoding JSON: " <> show error
Right importTaskRecord -> do
_ <- insertImportTask memConn importTaskRecord
tasks :: [FullTask] <- query_ memConn "SELECT * FROM tasks_view"
case tasks of
[insertedTask] ->
ulidText2utc insertedTask.ulid `shouldBe` Just utcFromUlid
_ -> P.die "More than one task found"

it "imports JSON task with notes and sets the created_utc for notes" $ do
withMemoryDb conf $ \memConn -> do
let
utc = "2024-03-15 10:32:51"
jsonTask =
"{\"body\":\"Just a test\",\
\\"created_at\":\"{{utc}}\",\
\\"notes\": [\"Just a note\"]}"
& T.replace "{{utc}}" utc

expectedTaskToNote =
TaskToNote
{ ulid =
emptyUlid
& P.flip setDateTime (utc & parseUtc & fromMaybe zeroTime)
& show @ULID
& T.toLower
, task_ulid = "01hs0tqw1r0007h0mj78s1jntz"
, note = "Just a note"
}

case eitherDecodeStrictText jsonTask of
Left error ->
P.die $ "Error decoding JSON: " <> show error
Right importTaskRecord -> do
_ <- insertImportTask memConn importTaskRecord
taskToNoteList :: [TaskToNote] <-
query_ memConn "SELECT * FROM task_to_note"
case taskToNoteList of
[taskToNote] -> do
taskToNote.ulid `shouldNotBe` expectedTaskToNote.ulid
(taskToNote.ulid & T.take 10)
`shouldBe` (expectedTaskToNote.ulid & T.take 10)
_ -> P.die "Found more than one note"
utc = "2024-03-15T10:32:51.386777444Z"
-- ULID only has millisecond precision:
utcFromUlid = "2024-03-15 10:32:51.387"
jsonTask =
"{\"body\":\"Just a test\",\"created_at\":\"{{utc}}\"}"
& T.replace "{{utc}}" utc

case eitherDecodeStrictText jsonTask of
Left error ->
P.die $ "Error decoding JSON: " <> show error
Right importTaskRecord -> do
_ <- insertImportTask memConn importTaskRecord
tasks :: [FullTask] <- query_ memConn "SELECT * FROM tasks_view"
case tasks of
[insertedTask] ->
ulidText2utc insertedTask.ulid `shouldBe` Just utcFromUlid
_ -> P.die "More than one task found"

it "imports JSON task with notes and sets the created_utc for notes" $ do
withMemoryDb conf $ \memConn -> do
let
utc = "2024-03-15 10:32:51"
jsonTask =
"{\"body\":\"Just a test\",\
\\"created_at\":\"{{utc}}\",\
\\"notes\": [\"Just a note\"]}"
& T.replace "{{utc}}" utc

expectedTaskToNote =
TaskToNote
{ ulid =
emptyUlid
& P.flip setDateTime (utc & parseUtc & fromMaybe zeroTime)
& show @ULID
& T.toLower
, task_ulid = "01hs0tqw1r0007h0mj78s1jntz"
, note = "Just a note"
}

case eitherDecodeStrictText jsonTask of
Left error ->
P.die $ "Error decoding JSON: " <> show error
Right importTaskRecord -> do
_ <- insertImportTask memConn importTaskRecord
taskToNoteList :: [TaskToNote] <-
query_ memConn "SELECT * FROM task_to_note"
case taskToNoteList of
[taskToNote] -> do
taskToNote.ulid `shouldNotBe` expectedTaskToNote.ulid
(taskToNote.ulid & T.take 10)
`shouldBe` (expectedTaskToNote.ulid & T.take 10)
_ -> P.die "Found more than one note"
Loading

0 comments on commit f8a510f

Please sign in to comment.