content: module LibSpec where
  
  import Protolude (
    Bool (True),
    ExitCode (ExitFailure),
    Maybe (..),
    Text,
    isJust,
    pure,
    show,
    ($),
    (&),
    (/=),
    (<),
    (<>),
    (==),
   )
  import Protolude qualified as P
  
  import Control.Arrow ((>>>))
  import Data.Aeson (decode)
  import Data.List.Utils (subIndex)
  import Data.Text (unpack)
  import Data.Text qualified as T
  import Data.Time.ISO8601.Duration qualified as Iso
  import Database.SQLite.Simple (SQLData (SQLNull), query_)
  import Test.Hspec (
    Spec,
    context,
    it,
    shouldBe,
    shouldContain,
    shouldEndWith,
    shouldNotBe,
    shouldNotContain,
    shouldNotSatisfy,
    shouldSatisfy,
    shouldStartWith,
    shouldThrow,
   )
  
  import Config (defaultConfig)
  import Data.Hourglass (TimeFormat (..), timePrint)
  import FullTask (FullTask, emptyFullTask)
  import FullTask qualified
  import ImportExport (EditMode (ApplyPreEdit), editTaskByTask)
  import Lib (
    addNote,
    addTag,
    addTask,
    countTasks,
    deleteNote,
    deleteTag,
    deleteTasks,
    doTasks,
    duplicateTasks,
    headTasks,
    infoTask,
    insertRecord,
    insertTags,
    listNotes,
    logTask,
    newTasks,
    nextTask,
    recurTasks,
    repeatTasks,
    runFilter,
    setDueUtc,
    setReadyUtc,
    unrepeatTasks,
    updateTask,
   )
  import Note (Note)
  import Time.System (dateCurrent)
  import Task (
    Task (
      body,
      closed_utc,
      due_utc,
      group_ulid,
      metadata,
      modified_utc,
      ready_utc,
      repetition_duration,
      state,
      ulid,
      user
    ),
    TaskState (Done),
    emptyTask,
   )
  import TaskToNote (TaskToNote (TaskToNote, ulid))
  import TaskToNote qualified
  import TaskToTag (TaskToTag)
  import TaskToTag qualified
  import TestUtils (withMemoryDb)
  import Utils (parseUtc, zeroTime, zeroUlidTxt)
  
  
  exampleTask :: Task
  exampleTask =
    emptyTask
      { Task.ulid = "01hq68smfe0r9entg3x4rb9441"
      , Task.body = "Buy milk"
      , Task.state = Nothing
      , Task.modified_utc = "2024-02-21 16:43:17"
      , Task.due_utc = Just "2025-07-08 10:22:56"
      , Task.user = "john_vdg1c2hz"
      , Task.metadata = "{\"source\":\"fridge\"}" & decode
      }
  
  
  task1 :: Task
  task1 =
    emptyTask
      { Task.ulid = "01hs68z7mdg4ktpxbv0yfafznq"
      , Task.body = "New task 1"
      , Task.modified_utc = "2024-03-17 13:17:44.461"
      }
  
  
  taskMultiLine :: Task
  taskMultiLine =
    emptyTask
      { Task.ulid = "01hx48cnjhp18mts3c44zk3gen"
      , Task.body =
          "New task\n\
          \with several lines\n\
          \and line breaks"
      }
  
  
  normTask :: Task -> Task
  normTask task =
    task
      { Task.ulid = ""
      , Task.modified_utc = ""
      , Task.due_utc = Nothing
      , Task.user = ""
      }
  
  
  replaceBs :: P.ByteString -> P.ByteString -> P.ByteString -> P.ByteString
  replaceBs needle replacement haystack = do
    haystack
      & P.decodeUtf8
      & T.replace (P.decodeUtf8 needle) (P.decodeUtf8 replacement)
      & P.encodeUtf8
  
  
  spec :: Spec
  spec = do
    let
      now = "2024-05-08 10:04:17" & parseUtc & P.fromMaybe zeroTime
      conf = defaultConfig
  
    it "initially contains no tasks" $ do
      withMemoryDb conf $ \memConn -> do
        tasks <- headTasks conf now memConn Nothing
        unpack (show tasks) `shouldStartWith` "No tasks available"
  
    it "inserts a task" $ do
      withMemoryDb conf $ \memConn -> do
        let task =
              emptyTask
                { Task.ulid = "01hrvhc0h1pncbczxym16642mm"
                , Task.body = "Directly inserted task"
                , Task.state = Just Done
                }
  
        insertRecord "tasks" memConn task
        tasks :: [Task] <- query_ memConn "SELECT * FROM tasks"
        tasks `shouldBe` [task]
  
    it "adds a new task" $ do
      withMemoryDb conf $ \memConn -> do
        result <- addTask conf memConn ["Just a test"]
        unpack (show result)
          `shouldStartWith` "🆕 Added task \"Just a test\" with id"
  
    context "When a task exists" $ do
      it "updates a task" $ do
        withMemoryDb conf $ \memConn -> do
          let initialTask =
                emptyTask
                  { Task.ulid = "01hrvhdddfwsrnp6dd8h7tp8h4"
                  , Task.body = "New task"
                  , Task.state = Just Done
                  }
              newTask = initialTask{body = "Updated task"}
  
          insertRecord "tasks" memConn initialTask
          updateTask memConn newTask
          tasks :: [Task] <- query_ memConn "SELECT * FROM tasks"
  
          case tasks of
            [updatedTask] -> do
              -- Task should have a different `modified_utc` value
              updatedTask `shouldSatisfy` (\task -> task.modified_utc /= "")
              updatedTask{modified_utc = ""} `shouldBe` newTask
            _ ->
              P.die "Found more than one task"
  
      it "lists next task" $ do
        withMemoryDb conf $ \memConn -> do
          insertRecord "tasks" memConn exampleTask
          result <- nextTask conf memConn
          unpack (show result) `shouldContain` "Buy milk"
  
      it "adds a tag" $ do
        withMemoryDb conf $ \memConn -> do
          insertRecord "tasks" memConn exampleTask
          tagResult <- addTag conf memConn "test" [exampleTask.ulid]
          unpack (show tagResult)
            `shouldStartWith` "🏷  Added tag \"test\" to task"
          taskToTags :: [TaskToTag] <-
            query_ memConn "SELECT * FROM task_to_tag"
          case taskToTags of
            [taskToTag] -> do
              taskToTag.ulid `shouldNotBe` ""
              taskToTag.task_ulid `shouldNotBe` ""
              taskToTag.tag `shouldBe` "test"
            _ -> P.die "More than one task_to_tag row found"
  
      it "strips leading + when adding a tag" $ do
        withMemoryDb conf $ \memConn -> do
          insertRecord "tasks" memConn exampleTask
          tagResult <- addTag conf memConn "+test" [exampleTask.ulid]
          unpack (show tagResult)
            `shouldStartWith` "🏷  Added tag \"test\" to task"
          taskToTags :: [TaskToTag] <-
            query_ memConn "SELECT * FROM task_to_tag"
          case taskToTags of
            [taskToTag] -> taskToTag.tag `shouldBe` "test"
            _ -> P.die "More than one task_to_tag row found"
  
      it "deletes a tag" $ do
        withMemoryDb conf $ \memConn -> do
          insertRecord "tasks" memConn exampleTask
          _ <- addTag conf memConn "test" [exampleTask.ulid]
          delResult <- deleteTag conf memConn "test" [exampleTask.ulid]
          unpack (show delResult)
            `shouldStartWith` "💥 Removed tag \"test\" of task"
          taskToTags :: [TaskToTag] <-
            query_ memConn "SELECT * FROM task_to_tag"
          taskToTags `shouldBe` []
  
      it "doesn't delete a tag that does not exist" $ do
        withMemoryDb conf $ \memConn -> do
          insertRecord "tasks" memConn exampleTask
          delResult <- deleteTag conf memConn "test" [exampleTask.ulid]
          unpack (show delResult) `shouldContain` "not set"
  
      it "adds a note" $ do
        withMemoryDb conf $ \memConn -> do
          insertRecord "tasks" memConn exampleTask
          noteResult <- addNote conf memConn "A test note" [exampleTask.ulid]
          unpack (show noteResult)
            `shouldStartWith` "🗒  Added a note to task"
  
      -- it "correctly wraps multiline notes" $ do
      --   See error:
      --   tl info x795vqf
  
      it "sets due UTC" $ do
        withMemoryDb conf $ \memConn -> do
          insertRecord "tasks" memConn exampleTask
          let utcTxt = "2087-03-21 17:43:00"
          case parseUtc utcTxt of
            Nothing -> P.die "Invalid UTC string"
            Just utcStamp -> do
              result <- setDueUtc conf memConn utcStamp [exampleTask.ulid]
              unpack (show result)
                `shouldStartWith` ( "📅 Set due UTC of task \""
                                      <> T.unpack exampleTask.body
                                      <> "\" with id \""
                                      <> T.unpack exampleTask.ulid
                                      <> "\" to \""
                                      <> T.unpack utcTxt
                                      <> "\""
                                  )
  
      it "sets ready UTC" $ do
        withMemoryDb conf $ \memConn -> do
          insertRecord "tasks" memConn exampleTask
          let utcTxt = "2059-07-11 04:55:16"
          case parseUtc utcTxt of
            Nothing -> P.die "Invalid UTC string"
            Just utcStamp -> do
              result <- setReadyUtc conf memConn utcStamp [exampleTask.ulid]
              unpack (show result)
                `shouldStartWith` ( "📅 Set ready UTC of task \""
                                      <> T.unpack exampleTask.body
                                      <> "\" with id \""
                                      <> T.unpack exampleTask.ulid
                                      <> "\" to \""
                                      <> T.unpack utcTxt
                                      <> "\""
                                  )
              tasks :: [Task] <- query_ memConn "SELECT * FROM tasks"
              case tasks of
                [updatedTask] -> do
                  updatedTask `shouldSatisfy` (\task -> isJust task.ready_utc)
                _ -> P.die "Found more than one task"
  
      it "completes it" $ do
        withMemoryDb conf $ \memConn -> do
          insertRecord "tasks" memConn exampleTask
          doResult <- doTasks conf memConn Nothing [exampleTask.ulid]
          unpack (show doResult) `shouldStartWith` "✅ Finished task"
          tasks :: [Task] <- query_ memConn "SELECT * FROM tasks"
          case tasks of
            [updatedTask] -> do
              updatedTask `shouldSatisfy` (\task -> task.state == Just Done)
              updatedTask `shouldSatisfy` (\task -> isJust task.closed_utc)
            _ -> P.die "Found more than one task"
  
      it "deletes it" $ do
        withMemoryDb conf $ \memConn -> do
          insertRecord "tasks" memConn exampleTask
          deleteResult <- deleteTasks conf memConn [exampleTask.ulid]
          unpack (show deleteResult) `shouldStartWith` "❌ Deleted task"
          tasks :: [Task] <- query_ memConn "SELECT * FROM tasks"
          tasks `shouldBe` []
          tags :: [TaskToTag] <- query_ memConn "SELECT * FROM task_to_tag"
          tags `shouldBe` []
          notes :: [Note] <- query_ memConn "SELECT * FROM task_to_note"
          notes `shouldBe` []
  
      it "duplicates a task" $ do
        withMemoryDb conf $ \memConn -> do
          insertRecord "tasks" memConn exampleTask
          duplicationResult <- duplicateTasks conf memConn [exampleTask.ulid]
          unpack (show duplicationResult)
            `shouldStartWith` "👯  Created a duplicate of task \"Buy milk\""
          tasks :: [Task] <- query_ memConn "SELECT * FROM tasks"
          case tasks of
            [taskA, taskB] -> do
              normTask taskA `shouldBe` normTask exampleTask
              normTask taskB `shouldBe` normTask exampleTask
            _ -> P.die "Must have exactly two tasks"
  
      it "deletes obsolete fields on duplication" $ do
        withMemoryDb conf $ \memConn -> do
          insertRecord "tasks" memConn exampleTask
          let
            zeroDur = Iso.DurationWeek (Iso.DurWeek 0)
            oneMonth = "P1M" & Iso.parseDuration & P.fromRight zeroDur
          _ <- repeatTasks conf memConn oneMonth [exampleTask.ulid]
          _ <- duplicateTasks conf memConn [exampleTask.ulid]
          tasks :: [Task] <-
            query_ memConn "SELECT * FROM tasks ORDER BY ulid DESC"
          case tasks of
            [dupe, original] -> do
              original.group_ulid `shouldSatisfy` P.isJust
              original.repetition_duration `shouldSatisfy` P.isJust
              dupe.group_ulid `shouldSatisfy` P.isNothing
              dupe.repetition_duration `shouldSatisfy` P.isNothing
              dupe.user `shouldNotBe` original.user
              normTask dupe `shouldBe` normTask exampleTask
            _ -> P.die "Must have exactly two tasks"
  
    it "adds a task with tags and due date" $ do
      withMemoryDb conf $ \memConn -> do
        _ <- addTask conf memConn ["Just a test +tag due:2082-10-03 +what"]
        (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"
                , FullTask.due_utc = Just "2082-10-03 00:00:00"
                , FullTask.priority = Just 2.0
                , FullTask.tags = Just ["tag", "what"]
                }
          _ -> P.die "Found more than one task"
  
    it "deduplicates tags when adding a task" $ do
      withMemoryDb conf $ \memConn -> do
        _ <- addTask conf memConn ["Buy milk +drink +drink"]
        (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 = "Buy milk"
                , FullTask.priority = Just 2.0
                , FullTask.tags = Just ["drink"]
                }
          _ -> P.die "Found more than one task"
  
    it "logs a task" $ do
      withMemoryDb conf $ \memConn -> do
        result <- logTask conf memConn ["Just a test"]
        unpack (show result)
          `shouldStartWith` "📝 Logged task \"Just a test\" with id"
  
    it "dies on invalid filter expressions" $ do
      withMemoryDb conf $ \memConn -> do
        runFilter conf now memConn [" "] Nothing `shouldThrow` (== ExitFailure 1)
  
    it "counts tasks" $ do
      withMemoryDb defaultConfig $ \memConn -> do
        let
          task2 =
            emptyTask
              { Task.ulid = "01hs690f9hkzk9z7zews9j2k1d"
              , Task.body = "New task 2"
              }
  
        count0 <- countTasks defaultConfig memConn P.mempty
        show count0 `shouldBe` ("0" :: Text)
  
        insertRecord "tasks" memConn task1
        count1 <- countTasks defaultConfig memConn P.mempty
        show count1 `shouldBe` ("1" :: Text)
  
        insertRecord "tasks" memConn task2
        count2 <- countTasks defaultConfig memConn P.mempty
        show count2 `shouldBe` ("2" :: Text)
  
        warnings <- insertTags conf memConn Nothing task2 ["test"]
        P.show warnings `shouldBe` T.empty
        countWithTag <- countTasks defaultConfig memConn (Just ["+test"])
        show countWithTag `shouldBe` ("1" :: Text)
  
        pure ()
  
    it "gets new tasks" $ do
      withMemoryDb defaultConfig $ \memConn -> do
        let
          task2 =
            emptyTask
              { Task.ulid = "01hs6zsf3c0vqx6egfnmbqtmvy"
              , Task.body = "New task 2"
              , Task.closed_utc = Just "2024-04-10T18:54:10Z"
              , Task.state = Just Done
              }
  
        insertRecord "tasks" memConn task1
        insertRecord "tasks" memConn task2
  
        cliOutput <- newTasks defaultConfig now memConn (Just ["state:done"]) Nothing
        show cliOutput `shouldContain` "New task 2"
        show cliOutput `shouldNotContain` "New task 1"
  
    it "shows warning if a tag is duplicated" $ do
      withMemoryDb defaultConfig $ \memConn -> do
        let newTag = "test"
        insertRecord "tasks" memConn task1
        warnings <- insertTags conf memConn Nothing task1 [newTag]
        P.show warnings `shouldBe` T.empty
  
        cliOutput <- addTag defaultConfig memConn newTag [task1.ulid]
        show cliOutput `shouldEndWith` "Tag \"test\" is already assigned"
  
    it "repeats a task and prevents recurring same task" $ do
      withMemoryDb defaultConfig $ \memConn -> do
        insertRecord "tasks" memConn task1
        let oneWeek = Iso.DurationWeek (Iso.DurWeek 1)
        repeatRes <- repeatTasks defaultConfig memConn oneWeek [task1.ulid]
        P.show repeatRes `shouldContain` "Set repeat duration of task"
  
        recurRes <- recurTasks defaultConfig memConn oneWeek [task1.ulid]
        P.show recurRes `shouldContain` "is already in a repetition series"
  
        unrepeatRes <- unrepeatTasks defaultConfig memConn [task1.ulid]
        P.show unrepeatRes `shouldContain` "Removed repetition duration"
  
        recurRes2 <- recurTasks defaultConfig memConn oneWeek [task1.ulid]
        P.show recurRes2 `shouldContain` "Set recurrence duration of task"
  
        repeatRes2 <- repeatTasks defaultConfig memConn oneWeek [task1.ulid]
        P.show repeatRes2 `shouldContain` "is already in a recurrence series"
  
    context "Editing a task" $ do
      it "shows warning if a tag was duplicated" $ do
        withMemoryDb defaultConfig $ \memConn -> do
          let existTag = "existing-tag"
          insertRecord "tasks" memConn task1
          warnings <- insertTags conf memConn Nothing task1 [existTag]
          P.show warnings `shouldBe` T.empty
          cliOutput <-
            editTaskByTask
              conf
              ( ApplyPreEdit $
                  replaceBs
                    "\n...\n"
                    ("\ntags: " <> P.show [existTag, "new-tag"] <> "\n...\n")
              )
              memConn
              task1
          let errMsg = "Tag \"" <> T.unpack existTag <> "\" is already assigned"
          show cliOutput `shouldContain` errMsg
  
      it "lets you change the closed_utc" $ do
        withMemoryDb defaultConfig $ \memConn -> do
          insertRecord "tasks" memConn task1
  
          cliOutput <-
            editTaskByTask
              conf
              ( ApplyPreEdit $
                  replaceBs
                    "state: null"
                    "state: Done"
                    >>> replaceBs
                      "closed_utc: null"
                      "closed_utc: 2024-05-08 10:04"
              )
              memConn
              task1
          show cliOutput `shouldContain` "Edited task"
          tasks :: [Task] <- query_ memConn "SELECT * FROM tasks"
          case tasks of
            [task] -> do
              task.closed_utc `shouldBe` Just "2024-05-08 10:04:00.000"
              task.state `shouldBe` Just Done
              now_ <- dateCurrent
              let today = now_ & timePrint (toFormat ("YYYY-MM-DD" :: [P.Char]))
              T.unpack task.modified_utc `shouldStartWith` today
            _ -> P.die "Found more than one task"
  
      it "lets you add notes" $ do
        withMemoryDb defaultConfig $ \memConn -> do
          insertRecord "tasks" memConn task1
          cliOutput <-
            editTaskByTask
              conf
              ( ApplyPreEdit $
                  replaceBs
                    "\n...\n"
                    ("\nnotes: " <> P.show ["A short note" :: Text] <> "\n...\n")
              )
              memConn
              task1
          show cliOutput `shouldStartWith` "✏️  Edited task \"New task 1\""
  
          taskToNotes :: [TaskToNote] <-
            query_ memConn "SELECT * FROM task_to_note"
          case taskToNotes of
            [taskToNote] -> do
              taskToNote.ulid
                `shouldNotSatisfy` (\ulid -> zeroUlidTxt `T.isPrefixOf` ulid)
              taskToNote.note `shouldBe` "A short note"
            _ -> P.die "Found more than one task_to_tag row"
  
      it "de-duplicates notes" $ do
        withMemoryDb defaultConfig $ \memConn -> do
          insertRecord "tasks" memConn task1
          let note = "A short note"
          insertRecord
            "task_to_note"
            memConn
            TaskToNote
              { TaskToNote.ulid = "01hxsjgzmdx48yzk39v852razr"
              , TaskToNote.task_ulid = task1.ulid
              , TaskToNote.note = note
              }
          taskInfo <- infoTask defaultConfig memConn task1.ulid
          show taskInfo `shouldContain` T.unpack note
          cliOutput <-
            editTaskByTask
              conf
              ( ApplyPreEdit $
                  replaceBs "notes: []" $
                    "notes: " <> P.show [note, note]
              )
              memConn
              task1
          show cliOutput `shouldStartWith` "✏️  Edited task \"New task 1\""
  
          taskToNotes :: [TaskToNote] <-
            query_ memConn "SELECT * FROM task_to_note"
          case taskToNotes of
            [taskToNoteA, taskToNoteB] -> do
              taskToNoteA.ulid
                `shouldNotSatisfy` (\ulid -> zeroUlidTxt `T.isPrefixOf` ulid)
              taskToNoteB.ulid
                `shouldNotSatisfy` (\ulid -> zeroUlidTxt `T.isPrefixOf` ulid)
              taskToNoteA.note `shouldBe` "A short note"
              taskToNoteB.note `shouldBe` "A short note"
            _ -> P.die "Found more than one task_to_tag row"
  
      it "lets you set metadata to null" $ do
        withMemoryDb defaultConfig $ \memConn -> do
          insertRecord "tasks" memConn task1{metadata = Just "{\"a\":\"b\"}"}
          cliOutput <-
            editTaskByTask
              conf
              (ApplyPreEdit $ replaceBs "\n...\n" "\nmetadata: null\n...\n")
              memConn
              task1
          show cliOutput `shouldStartWith` "✏️  Edited task \"New task 1\""
          tasks :: [[SQLData]] <- query_ memConn "SELECT metadata FROM tasks"
          case tasks of
            [[metadata]] -> do
              metadata `shouldBe` SQLNull
            _ -> P.die "Found more than one task"
  
    it "only shows first line of multi-line tasks in task listing" $ do
      withMemoryDb defaultConfig $ \memConn -> do
        insertRecord "tasks" memConn taskMultiLine
  
        tasks <- headTasks conf now memConn Nothing
        show tasks `shouldContain` "New task ▼"
        show tasks `shouldNotContain` "with several lines"
  
    it "keeps line breaks of multi-line tasks in info view" $ do
      withMemoryDb defaultConfig $ \memConn -> do
        insertRecord "tasks" memConn taskMultiLine
  
        cliOutput <- infoTask defaultConfig memConn taskMultiLine.ulid
        show cliOutput
          `shouldContain` "New task\n\
                          \with several lines\n\
                          \and line breaks"
  
    it "lists all notes descending by creation UTC" $ do
      withMemoryDb defaultConfig $ \memConn -> do
        insertRecord "tasks" memConn task1
        let
          taskToNote1 =
            TaskToNote
              { TaskToNote.ulid = "01hx4eyxxvs5b75ynxrztcz87f"
              , TaskToNote.task_ulid = task1.ulid
              , TaskToNote.note = "The first note"
              }
          note1Id = taskToNote1.ulid & T.takeEnd 3 & T.unpack
          taskToNote2 =
            TaskToNote
              { TaskToNote.ulid = "01hx4f3f764sma7n8bahvwjeed"
              , TaskToNote.task_ulid = task1.ulid
              , TaskToNote.note = "The second note"
              }
          note2Id = taskToNote2.ulid & T.takeEnd 3 & T.unpack
  
        insertRecord "task_to_note" memConn taskToNote1
        insertRecord "task_to_note" memConn taskToNote2
  
        cliOutput <- listNotes defaultConfig memConn
  
        show cliOutput `shouldContain` note1Id
        show cliOutput `shouldContain` note2Id
  
        let
          posUlid1 = subIndex note1Id (show cliOutput)
          posUlid2 = subIndex note2Id (show cliOutput)
  
        --  Newer notes should be listed first
        (posUlid2 < posUlid1) `shouldBe` True
  
    it "lets you delete a note" $ do
      withMemoryDb defaultConfig $ \memConn -> do
        insertRecord "tasks" memConn task1
        let noteId = "01hwcqk9nnwjypzw9kr646nqce"
        insertRecord
          "task_to_note"
          memConn
          TaskToNote
            { TaskToNote.ulid = noteId
            , TaskToNote.task_ulid = task1.ulid
            , TaskToNote.note = "The note content"
            }
  
        cliOutput <- deleteNote defaultConfig memConn noteId
  
        (show cliOutput :: Text)
          `shouldBe` "\128165 Deleted note \"01hwcqk9nnwjypzw9kr646nqce\" \
                     \of task \"01hs68z7mdg4ktpxbv0yfafznq\""
  