emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/subed b3a4ae08ab 10/22: Add missing tests for merging and


From: ELPA Syncer
Subject: [nongnu] elpa/subed b3a4ae08ab 10/22: Add missing tests for merging and subtitle ID at msecs
Date: Tue, 1 Feb 2022 14:06:05 -0500 (EST)

branch: elpa/subed
commit b3a4ae08ab1288c52274d4544cd0abb8f296a8d0
Author: Sacha Chua <sacha@sachachua.com>
Commit: Sacha Chua <sacha@sachachua.com>

    Add missing tests for merging and subtitle ID at msecs
    
    * subed/subed-common.el (merge-with-next): Define generic function.
    (merge-with-previous): Define generic function.
    * tests/test-subed-srt.el: Wrap in a SRT case for easy
    disabling. Also, test merging with next.
    * tests/test-subed-vtt.el ("Merging with next subtitle"): New case.
    ("Getting the subtitle ID"): New case.
    ("Getting the subtitle ID at playback time"): New case.
---
 subed/subed-common.el   |    7 +-
 tests/test-subed-srt.el | 2897 ++++++++++++++++++++++++-----------------------
 tests/test-subed-vtt.el |   65 +-
 3 files changed, 1528 insertions(+), 1441 deletions(-)

diff --git a/subed/subed-common.el b/subed/subed-common.el
index bf0ae27f33..43b9c3f86e 100644
--- a/subed/subed-common.el
+++ b/subed/subed-common.el
@@ -1095,7 +1095,12 @@ position of the point."
 
 ;;; Merging
 
-(defun subed-merge-with-previous ()
+(subed-define-generic-function merge-with-next ()
+  "Merge the current subtitle with the next subtitle.
+Update the end timestamp accordingly."
+  (interactive))
+
+(subed-define-generic-function merge-with-previous ()
   "Merge the current subtitle with the previous subtitle.
 Update the end timestamp accordingly."
   (interactive)
diff --git a/tests/test-subed-srt.el b/tests/test-subed-srt.el
index d6d44aed68..13514f0a1a 100644
--- a/tests/test-subed-srt.el
+++ b/tests/test-subed-srt.el
@@ -22,1486 +22,1505 @@ Baz.
     (subed-srt-mode)
     (progn ,@body)))
 
-(describe "Getting"
-  (describe "the subtitle ID"
-    (it "returns the subtitle ID if it can be found."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-text 2)
-        (expect (subed-subtitle-id) :to-equal 2)))
-    (it "returns nil if no subtitle ID can be found."
-      (with-temp-srt-buffer
-        (expect (subed-subtitle-id) :to-equal nil)))
-    )
-  (describe "the subtitle ID at playback time"
-    (it "returns subtitle ID if time is equal to start time."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (cl-loop for target-id from 1 to 3 do
-                 (let ((msecs (subed-subtitle-msecs-start target-id)))
-                   (cl-loop for outset-id from 1 to 3 do
-                            (progn
-                              (subed-jump-to-subtitle-id outset-id)
-                              (expect (subed-subtitle-id-at-msecs msecs) 
:to-equal target-id)))))))
-    (it "returns subtitle ID if time is equal to stop time."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (cl-loop for target-id from 1 to 3 do
-                 (let ((msecs (subed-subtitle-msecs-stop target-id)))
-                   (cl-loop for outset-id from 1 to 3 do
-                            (progn
-                              (subed-jump-to-subtitle-id outset-id)
-                              (expect (subed-subtitle-id-at-msecs msecs) 
:to-equal target-id)))))))
-    (it "returns subtitle ID if time is between start and stop time."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (cl-loop for target-id from 1 to 3 do
-                 (let ((msecs (+ 1 (subed-subtitle-msecs-start target-id))))
-                   (cl-loop for outset-id from 1 to 3 do
-                            (progn
-                              (subed-jump-to-subtitle-id outset-id)
-                              (expect (subed-subtitle-id-at-msecs msecs) 
:to-equal target-id)))))))
-    (it "returns nil if time is before the first subtitle's start time."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (let ((msecs (- (save-excursion
-                          (goto-char (point-min))
-                          (subed-subtitle-msecs-start)) 1)))
-          (cl-loop for outset-id from 1 to 3 do
-                   (progn
-                     (subed-jump-to-subtitle-id outset-id)
-                     (expect (subed-subtitle-id-at-msecs msecs) :to-equal 
nil))))))
-    (it "returns nil if time is after the last subtitle's start time."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (let ((msecs (+ (save-excursion
-                          (goto-char (point-max))
-                          (subed-subtitle-msecs-stop)) 1)))
-          (cl-loop for outset-id from 1 to 3 do
-                   (progn
-                     (subed-jump-to-subtitle-id outset-id)
-                     (expect (subed-subtitle-id-at-msecs msecs) :to-equal 
nil))))))
-    (it "returns nil if time is between subtitles."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (cl-loop for target-id from 1 to 2 do
-                 (let ((msecs (+ (subed-subtitle-msecs-stop target-id) 1)))
-                   (cl-loop for outset-id from 1 to 3 do
-                            (progn
-                              (subed-jump-to-subtitle-id outset-id)
-                              (expect (subed-subtitle-id-at-msecs msecs) 
:to-equal nil))))
-                 (let ((msecs (- (subed-subtitle-msecs-start (+ target-id 1)) 
1)))
-                   (cl-loop for outset-id from 1 to 3 do
-                            (progn
-                              (subed-jump-to-subtitle-id outset-id)
-                              (expect (subed-subtitle-id-at-msecs msecs) 
:to-equal nil)))))))
-    (it "doesn't fail if start time is invalid."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-id 2)
-        (let ((msecs (- (subed-subtitle-msecs-start) 1)))
-          (subed-jump-to-subtitle-time-start)
-          (forward-char 8) (delete-char 1)
-          (expect (subed-subtitle-id-at-msecs msecs) :to-equal 2))))
-    )
-  (describe "the subtitle start/stop time"
-    (it "returns the time in milliseconds."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-text 2)
-        (expect (subed-subtitle-msecs-start) :to-equal (+ (* 2 60000) (* 2 
1000) 234))
-        (expect (subed-subtitle-msecs-stop) :to-equal (+ (* 2 60000) (* 10 
1000) 345))))
-    (it "handles lack of digits in milliseconds gracefully."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-id 3)
-        (expect (save-excursion (subed-jump-to-subtitle-time-start)
-                                (thing-at-point 'line)) :to-equal "00:03:03,45 
--> 00:03:15,5\n")
-        (expect (subed-subtitle-msecs-start) :to-equal (+ (* 3 60 1000) (*  3 
1000) 450))
-        (expect (subed-subtitle-msecs-stop)  :to-equal (+ (* 3 60 1000) (* 15 
1000) 500))))
-    (it "returns nil if time can't be found."
-      (with-temp-srt-buffer
-        (expect (subed-subtitle-msecs-start) :to-be nil)
-        (expect (subed-subtitle-msecs-stop) :to-be nil)))
-    )
-  (describe "the subtitle text"
-    (describe "when text is empty"
-      (it "and at the beginning with a trailing newline."
-        (with-temp-srt-buffer
-          (insert mock-srt-data)
-          (subed-jump-to-subtitle-text 1)
-          (kill-line)
-          (expect (subed-subtitle-text) :to-equal "")))
-      (it "and at the beginning without a trailing newline."
-        (with-temp-srt-buffer
-          (insert mock-srt-data)
-          (subed-jump-to-subtitle-text 1)
-          (kill-whole-line)
-          (expect (subed-subtitle-text) :to-equal "")))
-      (it "and in the middle."
-        (with-temp-srt-buffer
-          (insert mock-srt-data)
-          (subed-jump-to-subtitle-text 2)
-          (kill-line)
-          (expect (subed-subtitle-text) :to-equal "")))
-      (it "and at the end with a trailing newline."
-        (with-temp-srt-buffer
-          (insert mock-srt-data)
-          (subed-jump-to-subtitle-text 3)
-          (kill-line)
-          (expect (subed-subtitle-text) :to-equal "")))
-      (it "and at the end without a trailing newline."
-        (with-temp-srt-buffer
-          (insert mock-srt-data)
-          (subed-jump-to-subtitle-text 3)
-          (kill-whole-line)
-          (expect (subed-subtitle-text) :to-equal "")))
-      )
-    (describe "when text is not empty"
-      (it "and has no linebreaks."
-        (with-temp-srt-buffer
-          (insert mock-srt-data)
-          (subed-jump-to-subtitle-text 2)
-          (expect (subed-subtitle-text) :to-equal "Bar.")))
-      (it "and has linebreaks."
-        (with-temp-srt-buffer
-          (insert mock-srt-data)
-          (subed-jump-to-subtitle-text 2)
-          (insert "Bar.\n")
-          (expect (subed-subtitle-text) :to-equal "Bar.\nBar.")))
+(describe "SRT"
+  (describe "Getting"
+    (describe "the subtitle ID"
+      (it "returns the subtitle ID if it can be found."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 2)
+         (expect (subed-subtitle-id) :to-equal 2)))
+      (it "returns nil if no subtitle ID can be found."
+        (with-temp-srt-buffer
+         (expect (subed-subtitle-id) :to-equal nil)))
       )
-    )
-  (describe "the point within the subtitle"
-    (it "returns the relative point if we can find an ID."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-id 2)
-        (expect (subed-subtitle-relative-point) :to-equal 0)
-        (forward-line)
-        (expect (subed-subtitle-relative-point) :to-equal 2)
-        (forward-line)
-        (expect (subed-subtitle-relative-point) :to-equal 32)
-        (forward-char)
-        (expect (subed-subtitle-relative-point) :to-equal 33)
-        (forward-line)
-        (expect (subed-subtitle-relative-point) :to-equal 37)
-        (forward-line)
-        (expect (subed-subtitle-relative-point) :to-equal 0)))
-    (it "returns nil if we can't find an ID."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-id 1)
-        (insert "foo")
-        (expect (subed-subtitle-relative-point) :to-equal nil)))
-    )
-  )
-
-(describe "Jumping"
-  (describe "to current subtitle ID"
-    (it "returns ID's point when point is already on the ID."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (expect (thing-at-point 'word) :to-equal "1")
-        (expect (subed-jump-to-subtitle-id) :to-equal 1)
-        (expect (thing-at-point 'word) :to-equal "1")))
-    (it "returns ID's point when point is on the duration."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (search-backward ",234")
-        (expect (thing-at-point 'word) :to-equal "02")
-        (expect (subed-jump-to-subtitle-id) :to-equal 39)
-        (expect (thing-at-point 'word) :to-equal "2")))
-    (it "returns ID's point when point is on the text."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (search-backward "Baz.")
-        (expect (thing-at-point 'word) :to-equal "Baz")
-        (expect (subed-jump-to-subtitle-id) :to-equal 77)
-        (expect (thing-at-point 'word) :to-equal "3")))
-    (it "returns ID's point when point is between subtitles."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (search-forward "Bar.\n")
-        (expect (thing-at-point 'line) :to-equal "\n")
-        (expect (subed-jump-to-subtitle-id) :to-equal 39)
-        (expect (thing-at-point 'word) :to-equal "2")))
-    (it "returns nil if buffer is empty."
-      (with-temp-srt-buffer
-        (expect (buffer-string) :to-equal "")
-        (expect (subed-jump-to-subtitle-id) :to-equal nil)))
-    (it "returns ID's point when buffer starts with blank lines."
-      (with-temp-srt-buffer
-        (insert (concat " \n \t \n" mock-srt-data))
-        (search-backward "Foo.")
-        (expect (thing-at-point 'line) :to-equal "Foo.\n")
-        (expect (subed-jump-to-subtitle-id) :to-equal 7)
-        (expect (thing-at-point 'word) :to-equal "1")))
-    (it "returns ID's point when subtitles are separated with blank lines."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (search-forward "Foo.\n")
-        (insert " \n \t \n")
-        (expect (subed-jump-to-subtitle-id) :to-equal 1)
-        (expect (thing-at-point 'word) :to-equal "1")))
-    )
-  (describe "to specific subtitle ID"
-    (it "returns ID's point if wanted ID exists."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-max))
-        (expect (subed-jump-to-subtitle-id 2) :to-equal 39)
-        (expect (thing-at-point 'word) :to-equal "2")
-        (expect (subed-jump-to-subtitle-id 1) :to-equal 1)
-        (expect (thing-at-point 'word) :to-equal "1")
-        (expect (subed-jump-to-subtitle-id 3) :to-equal 77)
-        (expect (thing-at-point 'word) :to-equal "3")))
-    (it "returns nil and does not move if wanted ID does not exists."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (search-forward "Foo")
-        (let ((stored-point (point)))
-          (expect (subed-jump-to-subtitle-id 4) :to-equal nil)
-          (expect stored-point :to-equal (point)))))
-    )
-  (describe "to subtitle ID at specific time"
-    (it "returns ID's point if point changed."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-max))
-        (spy-on 'subed-subtitle-id-at-msecs :and-return-value (point-min))
-        (expect (subed-jump-to-subtitle-id-at-msecs 123450) :to-equal 
(point-min))
-        (expect (point) :to-equal (point-min))
-        (expect 'subed-subtitle-id-at-msecs :to-have-been-called-with 123450)
-        (expect 'subed-subtitle-id-at-msecs :to-have-been-called-times 1)))
-    (it "returns nil if point didn't change."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char 75)
-        (spy-on 'subed-subtitle-id-at-msecs :and-return-value 75)
-        (expect (subed-jump-to-subtitle-id-at-msecs 123450) :to-equal nil)
-        (expect (point) :to-equal 75)
-        (expect 'subed-subtitle-id-at-msecs :to-have-been-called-with 123450)
-        (expect 'subed-subtitle-id-at-msecs :to-have-been-called-times 1)))
-    )
-  (describe "to subtitle start time"
-    (it "returns start time's point if movement was successful."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (expect (subed-jump-to-subtitle-time-start) :to-equal 3)
-        (expect (looking-at subed--regexp-timestamp) :to-be t)
-        (expect (match-string 0) :to-equal "00:01:01,000")
-        (re-search-forward "\n\n")
-        (expect (subed-jump-to-subtitle-time-start) :to-equal 41)
-        (expect (looking-at subed--regexp-timestamp) :to-be t)
-        (expect (match-string 0) :to-equal "00:02:02,234")
-        (re-search-forward "\n\n")
-        (expect (subed-jump-to-subtitle-time-start) :to-equal 79)
-        (expect (looking-at subed--regexp-timestamp) :to-be t)
-        (expect (match-string 0) :to-equal "00:03:03,45")))
-    (it "returns nil if movement failed."
-      (with-temp-srt-buffer
-        (expect (subed-jump-to-subtitle-time-start) :to-equal nil)))
-    )
-  (describe "to subtitle stop time"
-    (it "returns stop time's point if movement was successful."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (expect (subed-jump-to-subtitle-time-stop) :to-equal 20)
-        (expect (looking-at subed--regexp-timestamp) :to-be t)
-        (expect (match-string 0) :to-equal "00:01:05,123")
-        (re-search-forward "\n\n")
-        (expect (subed-jump-to-subtitle-time-stop) :to-equal 58)
-        (expect (looking-at subed--regexp-timestamp) :to-be t)
-        (expect (match-string 0) :to-equal "00:02:10,345")
-        (re-search-forward "\n\n")
-        (expect (subed-jump-to-subtitle-time-stop) :to-equal 95)
-        (expect (looking-at subed--regexp-timestamp) :to-be t)
-        (expect (match-string 0) :to-equal "00:03:15,5")))
-    (it "returns nil if movement failed."
-      (with-temp-srt-buffer
-        (expect (subed-jump-to-subtitle-time-stop) :to-equal nil)))
-    )
-  (describe "to subtitle text"
-    (it "returns subtitle text's point if movement was successful."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (expect (subed-jump-to-subtitle-text) :to-equal 33)
-        (expect (point) :to-equal (save-excursion (goto-char (point-max)) 
(search-backward "Foo.")))
-        (re-search-forward "\n\n")
-        (expect (subed-jump-to-subtitle-text) :to-equal 71)
-        (expect (point) :to-equal (save-excursion (goto-char (point-max)) 
(search-backward "Bar.")))
-        (re-search-forward "\n\n")
-        (expect (subed-jump-to-subtitle-text) :to-equal 106)
-        (expect (point) :to-equal (save-excursion (goto-char (point-max)) 
(search-backward "Baz.")))))
-    (it "returns nil if movement failed."
-      (with-temp-srt-buffer
-        (expect (subed-jump-to-subtitle-time-stop) :to-equal nil)))
-    )
-  (describe "to end of subtitle text"
-    (it "returns point if subtitle end can be found."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (expect (subed-jump-to-subtitle-end) :to-be 37)
-        (expect (looking-back "^Foo.$") :to-be t)
-        (forward-char 2)
-        (expect (subed-jump-to-subtitle-end) :to-be 75)
-        (expect (looking-back "^Bar.$") :to-be t)
-        (forward-char 2)
-        (expect (subed-jump-to-subtitle-end) :to-be 110)
-        (expect (looking-back "^Baz.$") :to-be t)
-        (goto-char (point-max))
-        (backward-char 2)
-        (expect (subed-jump-to-subtitle-end) :to-be 110)
-        (expect (looking-back "^Baz.$") :to-be t)))
-    (it "returns nil if subtitle end cannot be found."
-      (with-temp-srt-buffer
-        (expect (subed-jump-to-subtitle-end) :to-be nil)))
-    (it "returns nil if point did not move."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-text 1)
-        (kill-line)
-        (expect (subed-jump-to-subtitle-end) :to-be nil)))
-    (it "works if text is empty with trailing newline."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-text 1)
-        (kill-line)
-        (backward-char)
-        (expect (subed-jump-to-subtitle-end) :to-be 33)
-        (expect (looking-at "^$") :to-be t)
-        (subed-jump-to-subtitle-text 2)
-        (kill-line)
-        (backward-char)
-        (expect (subed-jump-to-subtitle-end) :to-be 67)
-        (expect (looking-at "^$") :to-be t)
-        (subed-jump-to-subtitle-text 3)
-        (kill-line)
-        (backward-char)
-        (expect (subed-jump-to-subtitle-end) :to-be 98)
-        (expect (looking-at "^$") :to-be t)))
-    (it "works if text is empty without trailing newline."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-text 1)
-        (kill-whole-line)
-        (expect (subed-jump-to-subtitle-end) :to-be nil)
-        (expect (looking-at "^$") :to-be t)
-        (goto-char (point-min))
-        (expect (subed-jump-to-subtitle-end) :to-be 33)
-        (expect (looking-at "^$") :to-be t)
-        (subed-jump-to-subtitle-text 2)
-        (kill-whole-line)
-        (expect (subed-jump-to-subtitle-end) :to-be nil)
-        (expect (looking-at "^$") :to-be t)
-        (backward-char)
-        (expect (subed-jump-to-subtitle-end) :to-be 66)
-        (expect (looking-at "^$") :to-be t)
-        (subed-jump-to-subtitle-text 3)
-        (kill-whole-line)
-        (expect (subed-jump-to-subtitle-end) :to-be nil)
-        (expect (looking-at "^$") :to-be t)
-        (backward-char)
-        (expect (subed-jump-to-subtitle-end) :to-be 96)
-        (expect (looking-at "^$") :to-be t)))
-    )
-  (describe "to next subtitle ID"
-    (it "returns point when there is a next subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-id 1)
-        (expect (thing-at-point 'word) :to-equal "1")
-        (expect (subed-forward-subtitle-id) :to-be 39)
-        (expect (thing-at-point 'word) :to-equal "2")
-        (subed-jump-to-subtitle-time-start 2)
-        (expect (thing-at-point 'word) :to-equal "00")
-        (expect (subed-forward-subtitle-id) :to-be 77)
-        (expect (thing-at-point 'word) :to-equal "3")))
-    (it "returns nil and doesn't move when there is no next subtitle."
-      (with-temp-srt-buffer
-        (expect (thing-at-point 'word) :to-equal nil)
-        (expect (subed-forward-subtitle-id) :to-be nil))
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-text 1)
-        (expect (thing-at-point 'word) :to-equal "Foo")
-        (expect (subed-forward-subtitle-id) :to-be 39)
-        (expect (thing-at-point 'word) :to-equal "2")
-        (subed-jump-to-subtitle-time-stop 2)
-        (expect (thing-at-point 'word) :to-equal "00")
-        (expect (subed-forward-subtitle-id) :to-be 77)
-        (expect (thing-at-point 'word) :to-equal "3"))
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-text 3)
-        (expect (thing-at-point 'word) :to-equal "Baz")
-        (expect (subed-forward-subtitle-id) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "Baz"))
-      (with-temp-srt-buffer
-        (insert (concat mock-srt-data "\n\n"))
-        (subed-jump-to-subtitle-time-stop 3)
-        (expect (thing-at-point 'word) :to-equal "00")
-        (expect (subed-forward-subtitle-id) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "00")))
-    )
-  (describe "to previous subtitle ID"
-    (it "returns point when there is a previous subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-text 2)
-        (expect (thing-at-point 'word) :to-equal "Bar")
-        (expect (subed-backward-subtitle-id) :to-be 1)
-        (expect (thing-at-point 'word) :to-equal "1")
-        (subed-jump-to-subtitle-time-stop 3)
-        (expect (thing-at-point 'word) :to-equal "00")
-        (expect (subed-backward-subtitle-id) :to-be 39)
-        (expect (thing-at-point 'word) :to-equal "2")))
-    (it "returns nil and doesn't move when there is no previous subtitle."
-      (with-temp-srt-buffer
-        (expect (subed-backward-subtitle-id) :to-be nil))
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-id 1)
-        (expect (thing-at-point 'word) :to-equal "1")
-        (expect (subed-backward-subtitle-id) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "1"))
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-text 1)
-        (expect (thing-at-point 'word) :to-equal "Foo")
-        (expect (subed-backward-subtitle-id) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "Foo"))
-      (with-temp-srt-buffer
-        (insert (concat "\n\n\n" mock-srt-data))
-        (subed-jump-to-subtitle-time-stop 1)
-        (expect (thing-at-point 'word) :to-equal "00")
-        (expect (subed-backward-subtitle-id) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "00")))
-    )
-  (describe "to next subtitle text"
-    (it "returns point when there is a next subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-id 1)
-        (expect (thing-at-point 'word) :to-equal "1")
-        (expect (subed-forward-subtitle-text) :to-be 71)
-        (expect (thing-at-point 'word) :to-equal "Bar")))
-    (it "returns nil and doesn't move when there is no next subtitle."
-      (with-temp-srt-buffer
-        (goto-char (point-max))
-        (insert (concat mock-srt-data "\n\n"))
-        (subed-jump-to-subtitle-id 3)
-        (expect (thing-at-point 'word) :to-equal "3")
-        (expect (subed-forward-subtitle-text) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "3")))
-    )
-  (describe "to previous subtitle text"
-    (it "returns point when there is a previous subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-id 3)
-        (expect (thing-at-point 'word) :to-equal "3")
-        (expect (subed-backward-subtitle-text) :to-be 71)
-        (expect (thing-at-point 'word) :to-equal "Bar")))
-    (it "returns nil and doesn't move when there is no previous subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (expect (thing-at-point 'word) :to-equal "1")
-        (expect (subed-backward-subtitle-text) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "1")))
-    )
-  (describe "to next subtitle end"
-    (it "returns point when there is a next subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-text 2)
-        (expect (thing-at-point 'word) :to-equal "Bar")
-        (expect (subed-forward-subtitle-end) :to-be 110)
-        (expect (thing-at-point 'word) :to-equal nil)))
-    (it "returns nil and doesn't move when there is no next subtitle."
-      (with-temp-srt-buffer
-        (insert (concat mock-srt-data "\n\n"))
-        (subed-jump-to-subtitle-text 3)
-        (end-of-line)
-        (expect (thing-at-point 'word) :to-equal nil)
-        (expect (subed-forward-subtitle-end) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal nil)))
-    )
-  (describe "to previous subtitle end"
-    (it "returns point when there is a previous subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-id 3)
-        (expect (thing-at-point 'word) :to-equal "3")
-        (expect (subed-backward-subtitle-text) :to-be 71)
-        (expect (thing-at-point 'word) :to-equal "Bar")))
-    (it "returns nil and doesn't move when there is no previous subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (expect (thing-at-point 'word) :to-equal "1")
-        (expect (subed-backward-subtitle-text) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "1")))
-    )
-  (describe "to next subtitle start time"
-    (it "returns point when there is a next subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-text 1)
-        (expect (thing-at-point 'word) :to-equal "Foo")
-        (expect (subed-forward-subtitle-time-start) :to-be 41)
-        (expect (thing-at-point 'word) :to-equal "00")))
-    (it "returns nil and doesn't move when there is no next subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-id 3)
-        (expect (thing-at-point 'word) :to-equal "3")
-        (expect (subed-forward-subtitle-time-start) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "3")))
-    )
-  (describe "to previous subtitle start time"
-    (it "returns point when there is a previous subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-id 2)
-        (expect (thing-at-point 'word) :to-equal "2")
-        (expect (subed-backward-subtitle-time-start) :to-be 3)
-        (expect (thing-at-point 'word) :to-equal "00")))
-    (it "returns nil and doesn't move when there is no previous subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-id 1)
-        (expect (thing-at-point 'word) :to-equal "1")
-        (expect (subed-backward-subtitle-time-start) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "1")))
-    )
-  (describe "to next subtitle stop time"
-    (it "returns point when there is a next subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-text 1)
-        (expect (thing-at-point 'word) :to-equal "Foo")
-        (expect (subed-forward-subtitle-time-stop) :to-be 58)
-        (expect (thing-at-point 'word) :to-equal "00")))
-    (it "returns nil and doesn't move when there is no next subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-id 3)
-        (expect (thing-at-point 'word) :to-equal "3")
-        (expect (subed-forward-subtitle-time-stop) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "3")))
-    )
-  (describe "to previous subtitle stop time"
-    (it "returns point when there is a previous subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-id 3)
-        (expect (thing-at-point 'word) :to-equal "3")
-        (expect (subed-backward-subtitle-time-stop) :to-be 58)
-        (expect (thing-at-point 'word) :to-equal "00")))
-    (it "returns nil and doesn't move when there is no previous subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-id 1)
-        (expect (thing-at-point 'word) :to-equal "1")
-        (expect (subed-backward-subtitle-time-stop) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "1")))
-    )
-  )
-
-(describe "Setting start/stop time"
-  (it "of current subtitle."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-jump-to-subtitle-end 2)
-      (subed-set-subtitle-time-start (+ (* 1 60 60 1000) (* 2 60 1000) (* 3 
1000) 400))
-      (expect (buffer-string) :to-equal (concat "1\n"
-                                                "00:01:01,000 --> 
00:01:05,123\n"
-                                                "Foo.\n\n"
-                                                "2\n"
-                                                "01:02:03,400 --> 
00:02:10,345\n"
-                                                "Bar.\n\n"
-                                                "3\n"
-                                                "00:03:03,45 --> 00:03:15,5\n"
-                                                "Baz.\n"))
-      (subed-set-subtitle-time-stop (+ (* 5 60 60 1000) (* 6 60 1000) (* 7 
1000) 800))
-      (expect (buffer-string) :to-equal (concat "1\n"
-                                                "00:01:01,000 --> 
00:01:05,123\n"
-                                                "Foo.\n\n"
-                                                "2\n"
-                                                "01:02:03,400 --> 
05:06:07,800\n"
-                                                "Bar.\n\n"
-                                                "3\n"
-                                                "00:03:03,45 --> 00:03:15,5\n"
-                                                "Baz.\n"))))
-  (it "of specific subtitle."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-jump-to-subtitle-time-stop 3)
-      (subed-set-subtitle-time-start (+ (* 2 60 60 1000) (* 4 60 1000) (* 6 
1000) 800) 1)
-      (expect (buffer-string) :to-equal (concat "1\n"
-                                                "02:04:06,800 --> 
00:01:05,123\n"
-                                                "Foo.\n\n"
-                                                "2\n"
-                                                "00:02:02,234 --> 
00:02:10,345\n"
-                                                "Bar.\n\n"
-                                                "3\n"
-                                                "00:03:03,45 --> 00:03:15,5\n"
-                                                "Baz.\n"))
-      (subed-jump-to-subtitle-text 1)
-      (subed-set-subtitle-time-stop (+ (* 3 60 60 1000) (* 5 60 1000) (* 7 
1000) 900) 3)
-      (expect (buffer-string) :to-equal (concat "1\n"
-                                                "02:04:06,800 --> 
00:01:05,123\n"
-                                                "Foo.\n\n"
-                                                "2\n"
-                                                "00:02:02,234 --> 
00:02:10,345\n"
-                                                "Bar.\n\n"
-                                                "3\n"
-                                                "00:03:03,45 --> 
03:05:07,900\n"
-                                                "Baz.\n"))))
-  (it "when milliseconds lack digits."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-jump-to-subtitle-id 3)
-      (subed-set-subtitle-time-start (+ (* 1 60 60 1000) (* 2 60 1000) (* 3 
1000) 4) 3)
-      (expect (save-excursion (subed-jump-to-subtitle-time-start)
-                              (thing-at-point 'line)) :to-equal "01:02:03,004 
--> 00:03:15,5\n")
-      (subed-set-subtitle-time-stop (+ (* 2 60 60 1000) (* 3 60 1000) (* 4 
1000) 60) 3)
-      (expect (save-excursion (subed-jump-to-subtitle-time-start)
-                              (thing-at-point 'line)) :to-equal "01:02:03,004 
--> 02:03:04,060\n")))
-  )
-
-(describe "Inserting a subtitle"
-  (describe "in an empty buffer"
-    (describe "before"
-      (it "passing nothing."
-        (with-temp-srt-buffer
-          (expect (subed-prepend-subtitle) :to-equal 33)
-          (expect (buffer-string) :to-equal (concat "0\n"
-                                                    "00:00:00,000 --> 
00:00:01,000\n\n"))
-          (expect (point) :to-equal 33)))
-      (it "passing ID."
-        (with-temp-srt-buffer
-          (expect (subed-prepend-subtitle 2) :to-equal 33)
-          (expect (buffer-string) :to-equal (concat "2\n"
-                                                    "00:00:00,000 --> 
00:00:01,000\n\n"))
-          (expect (point) :to-equal 33)))
-      (it "passing ID and start time."
-        (with-temp-srt-buffer
-          (expect (subed-prepend-subtitle 3 60000) :to-equal 33)
-          (expect (buffer-string) :to-equal (concat "3\n"
-                                                    "00:01:00,000 --> 
00:01:01,000\n\n"))
-          (expect (point) :to-equal 33)))
-      (it "passing ID, start time and stop time."
-        (with-temp-srt-buffer
-          (expect (subed-prepend-subtitle 4 60000 65000) :to-equal 33)
-          (expect (buffer-string) :to-equal (concat "4\n"
-                                                    "00:01:00,000 --> 
00:01:05,000\n\n"))
-          (expect (point) :to-equal 33)))
-      (it "passing ID, start time, stop time and text."
-        (with-temp-srt-buffer
-          (expect (subed-prepend-subtitle 5 60000 65000 "Foo, bar\nbaz.") 
:to-equal 33)
-          (expect (buffer-string) :to-equal (concat "5\n"
-                                                    "00:01:00,000 --> 
00:01:05,000\n"
-                                                    "Foo, bar\nbaz.\n"))
-          (expect (point) :to-equal 33)))
+    (describe "the subtitle ID at playback time"
+      (it "returns subtitle ID if time is equal to start time."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (cl-loop for target-id from 1 to 3 do
+                  (let ((msecs (subed-subtitle-msecs-start target-id)))
+                    (cl-loop for outset-id from 1 to 3 do
+                             (progn
+                               (subed-jump-to-subtitle-id outset-id)
+                               (expect (subed-subtitle-id-at-msecs msecs) 
:to-equal target-id)))))))
+      (it "returns subtitle ID if time is equal to stop time."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (cl-loop for target-id from 1 to 3 do
+                  (let ((msecs (subed-subtitle-msecs-stop target-id)))
+                    (cl-loop for outset-id from 1 to 3 do
+                             (progn
+                               (subed-jump-to-subtitle-id outset-id)
+                               (expect (subed-subtitle-id-at-msecs msecs) 
:to-equal target-id)))))))
+      (it "returns subtitle ID if time is between start and stop time."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (cl-loop for target-id from 1 to 3 do
+                  (let ((msecs (+ 1 (subed-subtitle-msecs-start target-id))))
+                    (cl-loop for outset-id from 1 to 3 do
+                             (progn
+                               (subed-jump-to-subtitle-id outset-id)
+                               (expect (subed-subtitle-id-at-msecs msecs) 
:to-equal target-id)))))))
+      (it "returns nil if time is before the first subtitle's start time."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (let ((msecs (- (save-excursion
+                           (goto-char (point-min))
+                           (subed-subtitle-msecs-start)) 1)))
+           (cl-loop for outset-id from 1 to 3 do
+                    (progn
+                      (subed-jump-to-subtitle-id outset-id)
+                      (expect (subed-subtitle-id-at-msecs msecs) :to-equal 
nil))))))
+      (it "returns nil if time is after the last subtitle's start time."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (let ((msecs (+ (save-excursion
+                           (goto-char (point-max))
+                           (subed-subtitle-msecs-stop)) 1)))
+           (cl-loop for outset-id from 1 to 3 do
+                    (progn
+                      (subed-jump-to-subtitle-id outset-id)
+                      (expect (subed-subtitle-id-at-msecs msecs) :to-equal 
nil))))))
+      (it "returns nil if time is between subtitles."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (cl-loop for target-id from 1 to 2 do
+                  (let ((msecs (+ (subed-subtitle-msecs-stop target-id) 1)))
+                    (cl-loop for outset-id from 1 to 3 do
+                             (progn
+                               (subed-jump-to-subtitle-id outset-id)
+                               (expect (subed-subtitle-id-at-msecs msecs) 
:to-equal nil))))
+                  (let ((msecs (- (subed-subtitle-msecs-start (+ target-id 1)) 
1)))
+                    (cl-loop for outset-id from 1 to 3 do
+                             (progn
+                               (subed-jump-to-subtitle-id outset-id)
+                               (expect (subed-subtitle-id-at-msecs msecs) 
:to-equal nil)))))))
+      (it "doesn't fail if start time is invalid."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 2)
+         (let ((msecs (- (subed-subtitle-msecs-start) 1)))
+           (subed-jump-to-subtitle-time-start)
+           (forward-char 8) (delete-char 1)
+           (expect (subed-subtitle-id-at-msecs msecs) :to-equal 2))))
       )
-    (describe "after"
-      (it "passing nothing."
-        (with-temp-srt-buffer
-          (expect (subed-append-subtitle) :to-equal 33)
-          (expect (buffer-string) :to-equal (concat "0\n"
-                                                    "00:00:00,000 --> 
00:00:01,000\n\n"))
-          (expect (point) :to-equal 33)))
-      (it "passing ID."
-        (with-temp-srt-buffer
-          (expect (subed-append-subtitle 2) :to-equal 33)
-          (expect (buffer-string) :to-equal (concat "2\n"
-                                                    "00:00:00,000 --> 
00:00:01,000\n\n"))
-          (expect (point) :to-equal 33)))
-      (it "passing ID and start time."
-        (with-temp-srt-buffer
-          (expect (subed-append-subtitle 3 60000) :to-equal 33)
-          (expect (buffer-string) :to-equal (concat "3\n"
-                                                    "00:01:00,000 --> 
00:01:01,000\n\n"))
-          (expect (point) :to-equal 33)))
-      (it "passing ID, start time and stop time."
-        (with-temp-srt-buffer
-          (expect (subed-append-subtitle 4 60000 65000) :to-equal 33)
-          (expect (buffer-string) :to-equal (concat "4\n"
-                                                    "00:01:00,000 --> 
00:01:05,000\n\n"))
-          (expect (point) :to-equal 33)))
-      (it "passing ID, start time, stop time and text."
-        (with-temp-srt-buffer
-          (expect (subed-append-subtitle 5 60000 65000 "Foo, bar\nbaz.") 
:to-equal 33)
-          (expect (buffer-string) :to-equal (concat "5\n"
-                                                    "00:01:00,000 --> 
00:01:05,000\n"
-                                                    "Foo, bar\nbaz.\n"))
-          (expect (point) :to-equal 33)))
+    (describe "the subtitle start/stop time"
+      (it "returns the time in milliseconds."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 2)
+         (expect (subed-subtitle-msecs-start) :to-equal (+ (* 2 60000) (* 2 
1000) 234))
+         (expect (subed-subtitle-msecs-stop) :to-equal (+ (* 2 60000) (* 10 
1000) 345))))
+      (it "handles lack of digits in milliseconds gracefully."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 3)
+         (expect (save-excursion (subed-jump-to-subtitle-time-start)
+                                 (thing-at-point 'line)) :to-equal 
"00:03:03,45 --> 00:03:15,5\n")
+         (expect (subed-subtitle-msecs-start) :to-equal (+ (* 3 60 1000) (*  3 
1000) 450))
+         (expect (subed-subtitle-msecs-stop)  :to-equal (+ (* 3 60 1000) (* 15 
1000) 500))))
+      (it "returns nil if time can't be found."
+        (with-temp-srt-buffer
+         (expect (subed-subtitle-msecs-start) :to-be nil)
+         (expect (subed-subtitle-msecs-stop) :to-be nil)))
       )
-    )
-  (describe "in a non-empty buffer"
-    (describe "before the current subtitle"
-      (describe "with point on the first subtitle"
-        (it "passing nothing."
+    (describe "the subtitle text"
+      (describe "when text is empty"
+        (it "and at the beginning with a trailing newline."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n"))
-            (subed-jump-to-subtitle-time-stop)
-            (expect (subed-prepend-subtitle) :to-equal 33)
-            (expect (buffer-string) :to-equal (concat "0\n"
-                                                      "00:00:00,000 --> 
00:00:01,000\n"
-                                                      "\n\n"
-                                                      "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n"))
-            (expect (point) :to-equal 33)))
-        (it "passing ID."
+           (insert mock-srt-data)
+           (subed-jump-to-subtitle-text 1)
+           (kill-line)
+           (expect (subed-subtitle-text) :to-equal "")))
+        (it "and at the beginning without a trailing newline."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n"))
-            (subed-jump-to-subtitle-time-stop)
-            (expect (subed-prepend-subtitle 7) :to-equal 33)
-            (expect (buffer-string) :to-equal (concat "7\n"
-                                                      "00:00:00,000 --> 
00:00:01,000\n"
-                                                      "\n\n"
-                                                      "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n"))
-            (expect (point) :to-equal 33)))
-        (it "passing ID and start time."
+           (insert mock-srt-data)
+           (subed-jump-to-subtitle-text 1)
+           (kill-whole-line)
+           (expect (subed-subtitle-text) :to-equal "")))
+        (it "and in the middle."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n"))
-            (subed-jump-to-subtitle-time-stop)
-            (expect (subed-prepend-subtitle 6 1500) :to-equal 33)
-            (expect (buffer-string) :to-equal (concat "6\n"
-                                                      "00:00:01,500 --> 
00:00:02,500\n"
-                                                      "\n\n"
-                                                      "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n"))
-            (expect (point) :to-equal 33)))
-        (it "passing ID, start time and stop time."
+           (insert mock-srt-data)
+           (subed-jump-to-subtitle-text 2)
+           (kill-line)
+           (expect (subed-subtitle-text) :to-equal "")))
+        (it "and at the end with a trailing newline."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n"))
-            (subed-jump-to-subtitle-time-stop)
-            (expect (subed-prepend-subtitle 5 1500 2000) :to-equal 33)
-            (expect (buffer-string) :to-equal (concat "5\n"
-                                                      "00:00:01,500 --> 
00:00:02,000\n"
-                                                      "\n\n"
-                                                      "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n"))
-            (expect (point) :to-equal 33)))
-        (it "passing ID, start time, stop time and text."
+           (insert mock-srt-data)
+           (subed-jump-to-subtitle-text 3)
+           (kill-line)
+           (expect (subed-subtitle-text) :to-equal "")))
+        (it "and at the end without a trailing newline."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n"))
-            (subed-jump-to-subtitle-time-stop)
-            (expect (subed-prepend-subtitle 4 1500 3000 "Bar.") :to-equal 33)
-            (expect (buffer-string) :to-equal (concat "4\n"
-                                                      "00:00:01,500 --> 
00:00:03,000\n"
-                                                      "Bar.\n\n"
-                                                      "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n"))
-            (expect (point) :to-equal 33)))
+           (insert mock-srt-data)
+           (subed-jump-to-subtitle-text 3)
+           (kill-whole-line)
+           (expect (subed-subtitle-text) :to-equal "")))
         )
-      (describe "with point on a non-first subtitle"
-        (it "passing nothing."
+      (describe "when text is not empty"
+        (it "and has no linebreaks."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n\n"
-                            "2\n"
-                            "00:00:10,000 --> 00:00:12,000\n"
-                            "Bar.\n"))
-            (subed-jump-to-subtitle-text 2)
-            (expect (subed-prepend-subtitle) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n\n"
-                                                      "0\n"
-                                                      "00:00:00,000 --> 
00:00:01,000\n"
-                                                      "\n\n"
-                                                      "2\n"
-                                                      "00:00:10,000 --> 
00:00:12,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
-        (it "passing ID."
-          (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n\n"
-                            "2\n"
-                            "00:00:10,000 --> 00:00:12,000\n"
-                            "Bar.\n"))
-            (subed-jump-to-subtitle-text 2)
-            (expect (subed-prepend-subtitle 9) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n\n"
-                                                      "9\n"
-                                                      "00:00:00,000 --> 
00:00:01,000\n"
-                                                      "\n\n"
-                                                      "2\n"
-                                                      "00:00:10,000 --> 
00:00:12,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
-        (it "passing ID and start time."
+           (insert mock-srt-data)
+           (subed-jump-to-subtitle-text 2)
+           (expect (subed-subtitle-text) :to-equal "Bar.")))
+        (it "and has linebreaks."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n\n"
-                            "2\n"
-                            "00:00:10,000 --> 00:00:12,000\n"
-                            "Bar.\n"))
-            (subed-jump-to-subtitle-text 2)
-            (expect (subed-prepend-subtitle 9 7000) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n\n"
-                                                      "9\n"
-                                                      "00:00:07,000 --> 
00:00:08,000\n"
-                                                      "\n\n"
-                                                      "2\n"
-                                                      "00:00:10,000 --> 
00:00:12,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
-        (it "passing ID, start time and stop time."
-          (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n\n"
-                            "2\n"
-                            "00:00:10,000 --> 00:00:12,000\n"
-                            "Bar.\n"))
-            (subed-jump-to-subtitle-text 2)
-            (expect (subed-prepend-subtitle 9 7000 7123) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n\n"
-                                                      "9\n"
-                                                      "00:00:07,000 --> 
00:00:07,123\n"
-                                                      "\n\n"
-                                                      "2\n"
-                                                      "00:00:10,000 --> 
00:00:12,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
-        (it "passing ID, start time, stop time and text."
-          (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n\n"
-                            "2\n"
-                            "00:00:10,000 --> 00:00:12,000\n"
-                            "Bar.\n"))
-            (subed-jump-to-subtitle-text 2)
-            (expect (subed-prepend-subtitle 9 7000 7123 "Baz.") :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n\n"
-                                                      "9\n"
-                                                      "00:00:07,000 --> 
00:00:07,123\n"
-                                                      "Baz.\n\n"
-                                                      "2\n"
-                                                      "00:00:10,000 --> 
00:00:12,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
+           (insert mock-srt-data)
+           (subed-jump-to-subtitle-text 2)
+           (insert "Bar.\n")
+           (expect (subed-subtitle-text) :to-equal "Bar.\nBar.")))
         )
       )
-    (describe "after the current subtitle"
-      (describe "with point on the last subtitle"
+    (describe "the point within the subtitle"
+      (it "returns the relative point if we can find an ID."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 2)
+         (expect (subed-subtitle-relative-point) :to-equal 0)
+         (forward-line)
+         (expect (subed-subtitle-relative-point) :to-equal 2)
+         (forward-line)
+         (expect (subed-subtitle-relative-point) :to-equal 32)
+         (forward-char)
+         (expect (subed-subtitle-relative-point) :to-equal 33)
+         (forward-line)
+         (expect (subed-subtitle-relative-point) :to-equal 37)
+         (forward-line)
+         (expect (subed-subtitle-relative-point) :to-equal 0)))
+      (it "returns nil if we can't find an ID."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 1)
+         (insert "foo")
+         (expect (subed-subtitle-relative-point) :to-equal nil)))
+      )
+    )
+
+  (describe "Jumping"
+    (describe "to current subtitle ID"
+      (it "returns ID's point when point is already on the ID."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (expect (thing-at-point 'word) :to-equal "1")
+         (expect (subed-jump-to-subtitle-id) :to-equal 1)
+         (expect (thing-at-point 'word) :to-equal "1")))
+      (it "returns ID's point when point is on the duration."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (search-backward ",234")
+         (expect (thing-at-point 'word) :to-equal "02")
+         (expect (subed-jump-to-subtitle-id) :to-equal 39)
+         (expect (thing-at-point 'word) :to-equal "2")))
+      (it "returns ID's point when point is on the text."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (search-backward "Baz.")
+         (expect (thing-at-point 'word) :to-equal "Baz")
+         (expect (subed-jump-to-subtitle-id) :to-equal 77)
+         (expect (thing-at-point 'word) :to-equal "3")))
+      (it "returns ID's point when point is between subtitles."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (search-forward "Bar.\n")
+         (expect (thing-at-point 'line) :to-equal "\n")
+         (expect (subed-jump-to-subtitle-id) :to-equal 39)
+         (expect (thing-at-point 'word) :to-equal "2")))
+      (it "returns nil if buffer is empty."
+        (with-temp-srt-buffer
+         (expect (buffer-string) :to-equal "")
+         (expect (subed-jump-to-subtitle-id) :to-equal nil)))
+      (it "returns ID's point when buffer starts with blank lines."
+        (with-temp-srt-buffer
+         (insert (concat " \n \t \n" mock-srt-data))
+         (search-backward "Foo.")
+         (expect (thing-at-point 'line) :to-equal "Foo.\n")
+         (expect (subed-jump-to-subtitle-id) :to-equal 7)
+         (expect (thing-at-point 'word) :to-equal "1")))
+      (it "returns ID's point when subtitles are separated with blank lines."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (search-forward "Foo.\n")
+         (insert " \n \t \n")
+         (expect (subed-jump-to-subtitle-id) :to-equal 1)
+         (expect (thing-at-point 'word) :to-equal "1")))
+      )
+    (describe "to specific subtitle ID"
+      (it "returns ID's point if wanted ID exists."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-max))
+         (expect (subed-jump-to-subtitle-id 2) :to-equal 39)
+         (expect (thing-at-point 'word) :to-equal "2")
+         (expect (subed-jump-to-subtitle-id 1) :to-equal 1)
+         (expect (thing-at-point 'word) :to-equal "1")
+         (expect (subed-jump-to-subtitle-id 3) :to-equal 77)
+         (expect (thing-at-point 'word) :to-equal "3")))
+      (it "returns nil and does not move if wanted ID does not exists."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (search-forward "Foo")
+         (let ((stored-point (point)))
+           (expect (subed-jump-to-subtitle-id 4) :to-equal nil)
+           (expect stored-point :to-equal (point)))))
+      )
+    (describe "to subtitle ID at specific time"
+      (it "returns ID's point if point changed."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-max))
+         (spy-on 'subed-subtitle-id-at-msecs :and-return-value (point-min))
+         (expect (subed-jump-to-subtitle-id-at-msecs 123450) :to-equal 
(point-min))
+         (expect (point) :to-equal (point-min))
+         (expect 'subed-subtitle-id-at-msecs :to-have-been-called-with 123450)
+         (expect 'subed-subtitle-id-at-msecs :to-have-been-called-times 1)))
+      (it "returns nil if point didn't change."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char 75)
+         (spy-on 'subed-subtitle-id-at-msecs :and-return-value 75)
+         (expect (subed-jump-to-subtitle-id-at-msecs 123450) :to-equal nil)
+         (expect (point) :to-equal 75)
+         (expect 'subed-subtitle-id-at-msecs :to-have-been-called-with 123450)
+         (expect 'subed-subtitle-id-at-msecs :to-have-been-called-times 1)))
+      )
+    (describe "to subtitle start time"
+      (it "returns start time's point if movement was successful."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (expect (subed-jump-to-subtitle-time-start) :to-equal 3)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
+         (expect (match-string 0) :to-equal "00:01:01,000")
+         (re-search-forward "\n\n")
+         (expect (subed-jump-to-subtitle-time-start) :to-equal 41)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
+         (expect (match-string 0) :to-equal "00:02:02,234")
+         (re-search-forward "\n\n")
+         (expect (subed-jump-to-subtitle-time-start) :to-equal 79)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
+         (expect (match-string 0) :to-equal "00:03:03,45")))
+      (it "returns nil if movement failed."
+        (with-temp-srt-buffer
+         (expect (subed-jump-to-subtitle-time-start) :to-equal nil)))
+      )
+    (describe "to subtitle stop time"
+      (it "returns stop time's point if movement was successful."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (expect (subed-jump-to-subtitle-time-stop) :to-equal 20)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
+         (expect (match-string 0) :to-equal "00:01:05,123")
+         (re-search-forward "\n\n")
+         (expect (subed-jump-to-subtitle-time-stop) :to-equal 58)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
+         (expect (match-string 0) :to-equal "00:02:10,345")
+         (re-search-forward "\n\n")
+         (expect (subed-jump-to-subtitle-time-stop) :to-equal 95)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
+         (expect (match-string 0) :to-equal "00:03:15,5")))
+      (it "returns nil if movement failed."
+        (with-temp-srt-buffer
+         (expect (subed-jump-to-subtitle-time-stop) :to-equal nil)))
+      )
+    (describe "to subtitle text"
+      (it "returns subtitle text's point if movement was successful."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (expect (subed-jump-to-subtitle-text) :to-equal 33)
+         (expect (point) :to-equal (save-excursion (goto-char (point-max)) 
(search-backward "Foo.")))
+         (re-search-forward "\n\n")
+         (expect (subed-jump-to-subtitle-text) :to-equal 71)
+         (expect (point) :to-equal (save-excursion (goto-char (point-max)) 
(search-backward "Bar.")))
+         (re-search-forward "\n\n")
+         (expect (subed-jump-to-subtitle-text) :to-equal 106)
+         (expect (point) :to-equal (save-excursion (goto-char (point-max)) 
(search-backward "Baz.")))))
+      (it "returns nil if movement failed."
+        (with-temp-srt-buffer
+         (expect (subed-jump-to-subtitle-time-stop) :to-equal nil)))
+      )
+    (describe "to end of subtitle text"
+      (it "returns point if subtitle end can be found."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (expect (subed-jump-to-subtitle-end) :to-be 37)
+         (expect (looking-back "^Foo.$") :to-be t)
+         (forward-char 2)
+         (expect (subed-jump-to-subtitle-end) :to-be 75)
+         (expect (looking-back "^Bar.$") :to-be t)
+         (forward-char 2)
+         (expect (subed-jump-to-subtitle-end) :to-be 110)
+         (expect (looking-back "^Baz.$") :to-be t)
+         (goto-char (point-max))
+         (backward-char 2)
+         (expect (subed-jump-to-subtitle-end) :to-be 110)
+         (expect (looking-back "^Baz.$") :to-be t)))
+      (it "returns nil if subtitle end cannot be found."
+        (with-temp-srt-buffer
+         (expect (subed-jump-to-subtitle-end) :to-be nil)))
+      (it "returns nil if point did not move."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 1)
+         (kill-line)
+         (expect (subed-jump-to-subtitle-end) :to-be nil)))
+      (it "works if text is empty with trailing newline."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 1)
+         (kill-line)
+         (backward-char)
+         (expect (subed-jump-to-subtitle-end) :to-be 33)
+         (expect (looking-at "^$") :to-be t)
+         (subed-jump-to-subtitle-text 2)
+         (kill-line)
+         (backward-char)
+         (expect (subed-jump-to-subtitle-end) :to-be 67)
+         (expect (looking-at "^$") :to-be t)
+         (subed-jump-to-subtitle-text 3)
+         (kill-line)
+         (backward-char)
+         (expect (subed-jump-to-subtitle-end) :to-be 98)
+         (expect (looking-at "^$") :to-be t)))
+      (it "works if text is empty without trailing newline."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 1)
+         (kill-whole-line)
+         (expect (subed-jump-to-subtitle-end) :to-be nil)
+         (expect (looking-at "^$") :to-be t)
+         (goto-char (point-min))
+         (expect (subed-jump-to-subtitle-end) :to-be 33)
+         (expect (looking-at "^$") :to-be t)
+         (subed-jump-to-subtitle-text 2)
+         (kill-whole-line)
+         (expect (subed-jump-to-subtitle-end) :to-be nil)
+         (expect (looking-at "^$") :to-be t)
+         (backward-char)
+         (expect (subed-jump-to-subtitle-end) :to-be 66)
+         (expect (looking-at "^$") :to-be t)
+         (subed-jump-to-subtitle-text 3)
+         (kill-whole-line)
+         (expect (subed-jump-to-subtitle-end) :to-be nil)
+         (expect (looking-at "^$") :to-be t)
+         (backward-char)
+         (expect (subed-jump-to-subtitle-end) :to-be 96)
+         (expect (looking-at "^$") :to-be t)))
+      )
+    (describe "to next subtitle ID"
+      (it "returns point when there is a next subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 1)
+         (expect (thing-at-point 'word) :to-equal "1")
+         (expect (subed-forward-subtitle-id) :to-be 39)
+         (expect (thing-at-point 'word) :to-equal "2")
+         (subed-jump-to-subtitle-time-start 2)
+         (expect (thing-at-point 'word) :to-equal "00")
+         (expect (subed-forward-subtitle-id) :to-be 77)
+         (expect (thing-at-point 'word) :to-equal "3")))
+      (it "returns nil and doesn't move when there is no next subtitle."
+        (with-temp-srt-buffer
+         (expect (thing-at-point 'word) :to-equal nil)
+         (expect (subed-forward-subtitle-id) :to-be nil))
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 1)
+         (expect (thing-at-point 'word) :to-equal "Foo")
+         (expect (subed-forward-subtitle-id) :to-be 39)
+         (expect (thing-at-point 'word) :to-equal "2")
+         (subed-jump-to-subtitle-time-stop 2)
+         (expect (thing-at-point 'word) :to-equal "00")
+         (expect (subed-forward-subtitle-id) :to-be 77)
+         (expect (thing-at-point 'word) :to-equal "3"))
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 3)
+         (expect (thing-at-point 'word) :to-equal "Baz")
+         (expect (subed-forward-subtitle-id) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "Baz"))
+        (with-temp-srt-buffer
+         (insert (concat mock-srt-data "\n\n"))
+         (subed-jump-to-subtitle-time-stop 3)
+         (expect (thing-at-point 'word) :to-equal "00")
+         (expect (subed-forward-subtitle-id) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "00")))
+      )
+    (describe "to previous subtitle ID"
+      (it "returns point when there is a previous subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 2)
+         (expect (thing-at-point 'word) :to-equal "Bar")
+         (expect (subed-backward-subtitle-id) :to-be 1)
+         (expect (thing-at-point 'word) :to-equal "1")
+         (subed-jump-to-subtitle-time-stop 3)
+         (expect (thing-at-point 'word) :to-equal "00")
+         (expect (subed-backward-subtitle-id) :to-be 39)
+         (expect (thing-at-point 'word) :to-equal "2")))
+      (it "returns nil and doesn't move when there is no previous subtitle."
+        (with-temp-srt-buffer
+         (expect (subed-backward-subtitle-id) :to-be nil))
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 1)
+         (expect (thing-at-point 'word) :to-equal "1")
+         (expect (subed-backward-subtitle-id) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "1"))
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 1)
+         (expect (thing-at-point 'word) :to-equal "Foo")
+         (expect (subed-backward-subtitle-id) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "Foo"))
+        (with-temp-srt-buffer
+         (insert (concat "\n\n\n" mock-srt-data))
+         (subed-jump-to-subtitle-time-stop 1)
+         (expect (thing-at-point 'word) :to-equal "00")
+         (expect (subed-backward-subtitle-id) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "00")))
+      )
+    (describe "to next subtitle text"
+      (it "returns point when there is a next subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 1)
+         (expect (thing-at-point 'word) :to-equal "1")
+         (expect (subed-forward-subtitle-text) :to-be 71)
+         (expect (thing-at-point 'word) :to-equal "Bar")))
+      (it "returns nil and doesn't move when there is no next subtitle."
+        (with-temp-srt-buffer
+         (goto-char (point-max))
+         (insert (concat mock-srt-data "\n\n"))
+         (subed-jump-to-subtitle-id 3)
+         (expect (thing-at-point 'word) :to-equal "3")
+         (expect (subed-forward-subtitle-text) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "3")))
+      )
+    (describe "to previous subtitle text"
+      (it "returns point when there is a previous subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 3)
+         (expect (thing-at-point 'word) :to-equal "3")
+         (expect (subed-backward-subtitle-text) :to-be 71)
+         (expect (thing-at-point 'word) :to-equal "Bar")))
+      (it "returns nil and doesn't move when there is no previous subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (expect (thing-at-point 'word) :to-equal "1")
+         (expect (subed-backward-subtitle-text) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "1")))
+      )
+    (describe "to next subtitle end"
+      (it "returns point when there is a next subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 2)
+         (expect (thing-at-point 'word) :to-equal "Bar")
+         (expect (subed-forward-subtitle-end) :to-be 110)
+         (expect (thing-at-point 'word) :to-equal nil)))
+      (it "returns nil and doesn't move when there is no next subtitle."
+        (with-temp-srt-buffer
+         (insert (concat mock-srt-data "\n\n"))
+         (subed-jump-to-subtitle-text 3)
+         (end-of-line)
+         (expect (thing-at-point 'word) :to-equal nil)
+         (expect (subed-forward-subtitle-end) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal nil)))
+      )
+    (describe "to previous subtitle end"
+      (it "returns point when there is a previous subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 3)
+         (expect (thing-at-point 'word) :to-equal "3")
+         (expect (subed-backward-subtitle-text) :to-be 71)
+         (expect (thing-at-point 'word) :to-equal "Bar")))
+      (it "returns nil and doesn't move when there is no previous subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (expect (thing-at-point 'word) :to-equal "1")
+         (expect (subed-backward-subtitle-text) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "1")))
+      )
+    (describe "to next subtitle start time"
+      (it "returns point when there is a next subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 1)
+         (expect (thing-at-point 'word) :to-equal "Foo")
+         (expect (subed-forward-subtitle-time-start) :to-be 41)
+         (expect (thing-at-point 'word) :to-equal "00")))
+      (it "returns nil and doesn't move when there is no next subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 3)
+         (expect (thing-at-point 'word) :to-equal "3")
+         (expect (subed-forward-subtitle-time-start) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "3")))
+      )
+    (describe "to previous subtitle start time"
+      (it "returns point when there is a previous subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 2)
+         (expect (thing-at-point 'word) :to-equal "2")
+         (expect (subed-backward-subtitle-time-start) :to-be 3)
+         (expect (thing-at-point 'word) :to-equal "00")))
+      (it "returns nil and doesn't move when there is no previous subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 1)
+         (expect (thing-at-point 'word) :to-equal "1")
+         (expect (subed-backward-subtitle-time-start) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "1")))
+      )
+    (describe "to next subtitle stop time"
+      (it "returns point when there is a next subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 1)
+         (expect (thing-at-point 'word) :to-equal "Foo")
+         (expect (subed-forward-subtitle-time-stop) :to-be 58)
+         (expect (thing-at-point 'word) :to-equal "00")))
+      (it "returns nil and doesn't move when there is no next subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 3)
+         (expect (thing-at-point 'word) :to-equal "3")
+         (expect (subed-forward-subtitle-time-stop) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "3")))
+      )
+    (describe "to previous subtitle stop time"
+      (it "returns point when there is a previous subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 3)
+         (expect (thing-at-point 'word) :to-equal "3")
+         (expect (subed-backward-subtitle-time-stop) :to-be 58)
+         (expect (thing-at-point 'word) :to-equal "00")))
+      (it "returns nil and doesn't move when there is no previous subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 1)
+         (expect (thing-at-point 'word) :to-equal "1")
+         (expect (subed-backward-subtitle-time-stop) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "1")))
+      )
+    )
+
+  (describe "Setting start/stop time"
+    (it "of current subtitle."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-end 2)
+       (subed-set-subtitle-time-start (+ (* 1 60 60 1000) (* 2 60 1000) (* 3 
1000) 400))
+       (expect (buffer-string) :to-equal (concat "1\n"
+                                                 "00:01:01,000 --> 
00:01:05,123\n"
+                                                 "Foo.\n\n"
+                                                 "2\n"
+                                                 "01:02:03,400 --> 
00:02:10,345\n"
+                                                 "Bar.\n\n"
+                                                 "3\n"
+                                                 "00:03:03,45 --> 00:03:15,5\n"
+                                                 "Baz.\n"))
+       (subed-set-subtitle-time-stop (+ (* 5 60 60 1000) (* 6 60 1000) (* 7 
1000) 800))
+       (expect (buffer-string) :to-equal (concat "1\n"
+                                                 "00:01:01,000 --> 
00:01:05,123\n"
+                                                 "Foo.\n\n"
+                                                 "2\n"
+                                                 "01:02:03,400 --> 
05:06:07,800\n"
+                                                 "Bar.\n\n"
+                                                 "3\n"
+                                                 "00:03:03,45 --> 00:03:15,5\n"
+                                                 "Baz.\n"))))
+    (it "of specific subtitle."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-time-stop 3)
+       (subed-set-subtitle-time-start (+ (* 2 60 60 1000) (* 4 60 1000) (* 6 
1000) 800) 1)
+       (expect (buffer-string) :to-equal (concat "1\n"
+                                                 "02:04:06,800 --> 
00:01:05,123\n"
+                                                 "Foo.\n\n"
+                                                 "2\n"
+                                                 "00:02:02,234 --> 
00:02:10,345\n"
+                                                 "Bar.\n\n"
+                                                 "3\n"
+                                                 "00:03:03,45 --> 00:03:15,5\n"
+                                                 "Baz.\n"))
+       (subed-jump-to-subtitle-text 1)
+       (subed-set-subtitle-time-stop (+ (* 3 60 60 1000) (* 5 60 1000) (* 7 
1000) 900) 3)
+       (expect (buffer-string) :to-equal (concat "1\n"
+                                                 "02:04:06,800 --> 
00:01:05,123\n"
+                                                 "Foo.\n\n"
+                                                 "2\n"
+                                                 "00:02:02,234 --> 
00:02:10,345\n"
+                                                 "Bar.\n\n"
+                                                 "3\n"
+                                                 "00:03:03,45 --> 
03:05:07,900\n"
+                                                 "Baz.\n"))))
+    (it "when milliseconds lack digits."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-id 3)
+       (subed-set-subtitle-time-start (+ (* 1 60 60 1000) (* 2 60 1000) (* 3 
1000) 4) 3)
+       (expect (save-excursion (subed-jump-to-subtitle-time-start)
+                               (thing-at-point 'line)) :to-equal "01:02:03,004 
--> 00:03:15,5\n")
+       (subed-set-subtitle-time-stop (+ (* 2 60 60 1000) (* 3 60 1000) (* 4 
1000) 60) 3)
+       (expect (save-excursion (subed-jump-to-subtitle-time-start)
+                               (thing-at-point 'line)) :to-equal "01:02:03,004 
--> 02:03:04,060\n")))
+    )
+
+  (describe "Inserting a subtitle"
+    (describe "in an empty buffer"
+      (describe "before"
         (it "passing nothing."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n"))
-            (subed-jump-to-subtitle-text)
-            (expect (subed-append-subtitle) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n\n"
-                                                      "0\n"
-                                                      "00:00:00,000 --> 
00:00:01,000\n"
-                                                      "\n"))
-            (expect (point) :to-equal 71)))
+           (expect (subed-prepend-subtitle) :to-equal 33)
+           (expect (buffer-string) :to-equal (concat "0\n"
+                                                     "00:00:00,000 --> 
00:00:01,000\n\n"))
+           (expect (point) :to-equal 33)))
         (it "passing ID."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n"))
-            (subed-jump-to-subtitle-text)
-            (expect (subed-append-subtitle 5) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n\n"
-                                                      "5\n"
-                                                      "00:00:00,000 --> 
00:00:01,000\n"
-                                                      "\n"))
-            (expect (point) :to-equal 71)))
+           (expect (subed-prepend-subtitle 2) :to-equal 33)
+           (expect (buffer-string) :to-equal (concat "2\n"
+                                                     "00:00:00,000 --> 
00:00:01,000\n\n"))
+           (expect (point) :to-equal 33)))
         (it "passing ID and start time."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n"))
-            (subed-jump-to-subtitle-text)
-            (expect (subed-append-subtitle 5 12345) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n\n"
-                                                      "5\n"
-                                                      "00:00:12,345 --> 
00:00:13,345\n"
-                                                      "\n"))
-            (expect (point) :to-equal 71)))
+           (expect (subed-prepend-subtitle 3 60000) :to-equal 33)
+           (expect (buffer-string) :to-equal (concat "3\n"
+                                                     "00:01:00,000 --> 
00:01:01,000\n\n"))
+           (expect (point) :to-equal 33)))
         (it "passing ID, start time and stop time."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n"))
-            (subed-jump-to-subtitle-text)
-            (expect (subed-append-subtitle 5 12345 15000) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n\n"
-                                                      "5\n"
-                                                      "00:00:12,345 --> 
00:00:15,000\n"
-                                                      "\n"))
-            (expect (point) :to-equal 71)))
+           (expect (subed-prepend-subtitle 4 60000 65000) :to-equal 33)
+           (expect (buffer-string) :to-equal (concat "4\n"
+                                                     "00:01:00,000 --> 
00:01:05,000\n\n"))
+           (expect (point) :to-equal 33)))
         (it "passing ID, start time, stop time and text."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n"))
-            (subed-jump-to-subtitle-text)
-            (expect (subed-append-subtitle 5 12345 15000 "Bar.") :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n\n"
-                                                      "5\n"
-                                                      "00:00:12,345 --> 
00:00:15,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
+           (expect (subed-prepend-subtitle 5 60000 65000 "Foo, bar\nbaz.") 
:to-equal 33)
+           (expect (buffer-string) :to-equal (concat "5\n"
+                                                     "00:01:00,000 --> 
00:01:05,000\n"
+                                                     "Foo, bar\nbaz.\n"))
+           (expect (point) :to-equal 33)))
         )
-      (describe "with point on a non-last subtitle"
+      (describe "after"
         (it "passing nothing."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:01,000 --> 00:00:02,000\n"
-                            "Foo.\n\n"
-                            "2\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Bar.\n"))
-            (subed-jump-to-subtitle-time-start 1)
-            (expect (subed-append-subtitle) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:01,000 --> 
00:00:02,000\n"
-                                                      "Foo.\n\n"
-                                                      "0\n"
-                                                      "00:00:00,000 --> 
00:00:01,000\n"
-                                                      "\n\n"
-                                                      "2\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
+           (expect (subed-append-subtitle) :to-equal 33)
+           (expect (buffer-string) :to-equal (concat "0\n"
+                                                     "00:00:00,000 --> 
00:00:01,000\n\n"))
+           (expect (point) :to-equal 33)))
         (it "passing ID."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:01,000 --> 00:00:02,000\n"
-                            "Foo.\n\n"
-                            "2\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Bar.\n"))
-            (subed-jump-to-subtitle-time-start 1)
-            (expect (subed-append-subtitle 7) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:01,000 --> 
00:00:02,000\n"
-                                                      "Foo.\n\n"
-                                                      "7\n"
-                                                      "00:00:00,000 --> 
00:00:01,000\n"
-                                                      "\n\n"
-                                                      "2\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
+           (expect (subed-append-subtitle 2) :to-equal 33)
+           (expect (buffer-string) :to-equal (concat "2\n"
+                                                     "00:00:00,000 --> 
00:00:01,000\n\n"))
+           (expect (point) :to-equal 33)))
         (it "passing ID and start time."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:01,000 --> 00:00:02,000\n"
-                            "Foo.\n\n"
-                            "2\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Bar.\n"))
-            (subed-jump-to-subtitle-time-start 1)
-            (expect (subed-append-subtitle 7 2500) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:01,000 --> 
00:00:02,000\n"
-                                                      "Foo.\n\n"
-                                                      "7\n"
-                                                      "00:00:02,500 --> 
00:00:03,500\n"
-                                                      "\n\n"
-                                                      "2\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
+           (expect (subed-append-subtitle 3 60000) :to-equal 33)
+           (expect (buffer-string) :to-equal (concat "3\n"
+                                                     "00:01:00,000 --> 
00:01:01,000\n\n"))
+           (expect (point) :to-equal 33)))
         (it "passing ID, start time and stop time."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:01,000 --> 00:00:02,000\n"
-                            "Foo.\n\n"
-                            "2\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Bar.\n"))
-            (subed-jump-to-subtitle-time-start 1)
-            (expect (subed-append-subtitle 7 2500 4000) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:01,000 --> 
00:00:02,000\n"
-                                                      "Foo.\n\n"
-                                                      "7\n"
-                                                      "00:00:02,500 --> 
00:00:04,000\n"
-                                                      "\n\n"
-                                                      "2\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
+           (expect (subed-append-subtitle 4 60000 65000) :to-equal 33)
+           (expect (buffer-string) :to-equal (concat "4\n"
+                                                     "00:01:00,000 --> 
00:01:05,000\n\n"))
+           (expect (point) :to-equal 33)))
         (it "passing ID, start time, stop time and text."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:01,000 --> 00:00:02,000\n"
-                            "Foo.\n\n"
-                            "2\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Bar.\n"))
-            (subed-jump-to-subtitle-time-start 1)
-            (expect (subed-append-subtitle 7 2500 4000 "Baz.") :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:01,000 --> 
00:00:02,000\n"
-                                                      "Foo.\n\n"
-                                                      "7\n"
-                                                      "00:00:02,500 --> 
00:00:04,000\n"
-                                                      "Baz.\n\n"
-                                                      "2\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
+           (expect (subed-append-subtitle 5 60000 65000 "Foo, bar\nbaz.") 
:to-equal 33)
+           (expect (buffer-string) :to-equal (concat "5\n"
+                                                     "00:01:00,000 --> 
00:01:05,000\n"
+                                                     "Foo, bar\nbaz.\n"))
+           (expect (point) :to-equal 33)))
         )
       )
-    (it "when point is on empty text."
-      (with-temp-srt-buffer
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "\n"))
-        (subed-jump-to-subtitle-text)
-        (expect (subed-append-subtitle) :to-equal 67)
-        (expect (buffer-string) :to-equal (concat "1\n"
-                                                  "00:00:01,000 --> 
00:00:02,000\n"
-                                                  "\n\n"
-                                                  "0\n"
-                                                  "00:00:00,000 --> 
00:00:01,000\n"
-                                                  "\n"))
-        (expect (point) :to-equal 67)))
+    (describe "in a non-empty buffer"
+      (describe "before the current subtitle"
+        (describe "with point on the first subtitle"
+          (it "passing nothing."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n"))
+             (subed-jump-to-subtitle-time-stop)
+             (expect (subed-prepend-subtitle) :to-equal 33)
+             (expect (buffer-string) :to-equal (concat "0\n"
+                                                       "00:00:00,000 --> 
00:00:01,000\n"
+                                                       "\n\n"
+                                                       "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n"))
+             (expect (point) :to-equal 33)))
+          (it "passing ID."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n"))
+             (subed-jump-to-subtitle-time-stop)
+             (expect (subed-prepend-subtitle 7) :to-equal 33)
+             (expect (buffer-string) :to-equal (concat "7\n"
+                                                       "00:00:00,000 --> 
00:00:01,000\n"
+                                                       "\n\n"
+                                                       "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n"))
+             (expect (point) :to-equal 33)))
+          (it "passing ID and start time."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n"))
+             (subed-jump-to-subtitle-time-stop)
+             (expect (subed-prepend-subtitle 6 1500) :to-equal 33)
+             (expect (buffer-string) :to-equal (concat "6\n"
+                                                       "00:00:01,500 --> 
00:00:02,500\n"
+                                                       "\n\n"
+                                                       "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n"))
+             (expect (point) :to-equal 33)))
+          (it "passing ID, start time and stop time."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n"))
+             (subed-jump-to-subtitle-time-stop)
+             (expect (subed-prepend-subtitle 5 1500 2000) :to-equal 33)
+             (expect (buffer-string) :to-equal (concat "5\n"
+                                                       "00:00:01,500 --> 
00:00:02,000\n"
+                                                       "\n\n"
+                                                       "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n"))
+             (expect (point) :to-equal 33)))
+          (it "passing ID, start time, stop time and text."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n"))
+             (subed-jump-to-subtitle-time-stop)
+             (expect (subed-prepend-subtitle 4 1500 3000 "Bar.") :to-equal 33)
+             (expect (buffer-string) :to-equal (concat "4\n"
+                                                       "00:00:01,500 --> 
00:00:03,000\n"
+                                                       "Bar.\n\n"
+                                                       "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n"))
+             (expect (point) :to-equal 33)))
+          )
+        (describe "with point on a non-first subtitle"
+          (it "passing nothing."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n\n"
+                             "2\n"
+                             "00:00:10,000 --> 00:00:12,000\n"
+                             "Bar.\n"))
+             (subed-jump-to-subtitle-text 2)
+             (expect (subed-prepend-subtitle) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n\n"
+                                                       "0\n"
+                                                       "00:00:00,000 --> 
00:00:01,000\n"
+                                                       "\n\n"
+                                                       "2\n"
+                                                       "00:00:10,000 --> 
00:00:12,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n\n"
+                             "2\n"
+                             "00:00:10,000 --> 00:00:12,000\n"
+                             "Bar.\n"))
+             (subed-jump-to-subtitle-text 2)
+             (expect (subed-prepend-subtitle 9) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n\n"
+                                                       "9\n"
+                                                       "00:00:00,000 --> 
00:00:01,000\n"
+                                                       "\n\n"
+                                                       "2\n"
+                                                       "00:00:10,000 --> 
00:00:12,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID and start time."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n\n"
+                             "2\n"
+                             "00:00:10,000 --> 00:00:12,000\n"
+                             "Bar.\n"))
+             (subed-jump-to-subtitle-text 2)
+             (expect (subed-prepend-subtitle 9 7000) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n\n"
+                                                       "9\n"
+                                                       "00:00:07,000 --> 
00:00:08,000\n"
+                                                       "\n\n"
+                                                       "2\n"
+                                                       "00:00:10,000 --> 
00:00:12,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID, start time and stop time."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n\n"
+                             "2\n"
+                             "00:00:10,000 --> 00:00:12,000\n"
+                             "Bar.\n"))
+             (subed-jump-to-subtitle-text 2)
+             (expect (subed-prepend-subtitle 9 7000 7123) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n\n"
+                                                       "9\n"
+                                                       "00:00:07,000 --> 
00:00:07,123\n"
+                                                       "\n\n"
+                                                       "2\n"
+                                                       "00:00:10,000 --> 
00:00:12,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID, start time, stop time and text."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n\n"
+                             "2\n"
+                             "00:00:10,000 --> 00:00:12,000\n"
+                             "Bar.\n"))
+             (subed-jump-to-subtitle-text 2)
+             (expect (subed-prepend-subtitle 9 7000 7123 "Baz.") :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n\n"
+                                                       "9\n"
+                                                       "00:00:07,000 --> 
00:00:07,123\n"
+                                                       "Baz.\n\n"
+                                                       "2\n"
+                                                       "00:00:10,000 --> 
00:00:12,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          )
+        )
+      (describe "after the current subtitle"
+        (describe "with point on the last subtitle"
+          (it "passing nothing."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n"))
+             (subed-jump-to-subtitle-text)
+             (expect (subed-append-subtitle) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n\n"
+                                                       "0\n"
+                                                       "00:00:00,000 --> 
00:00:01,000\n"
+                                                       "\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n"))
+             (subed-jump-to-subtitle-text)
+             (expect (subed-append-subtitle 5) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n\n"
+                                                       "5\n"
+                                                       "00:00:00,000 --> 
00:00:01,000\n"
+                                                       "\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID and start time."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n"))
+             (subed-jump-to-subtitle-text)
+             (expect (subed-append-subtitle 5 12345) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n\n"
+                                                       "5\n"
+                                                       "00:00:12,345 --> 
00:00:13,345\n"
+                                                       "\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID, start time and stop time."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n"))
+             (subed-jump-to-subtitle-text)
+             (expect (subed-append-subtitle 5 12345 15000) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n\n"
+                                                       "5\n"
+                                                       "00:00:12,345 --> 
00:00:15,000\n"
+                                                       "\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID, start time, stop time and text."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n"))
+             (subed-jump-to-subtitle-text)
+             (expect (subed-append-subtitle 5 12345 15000 "Bar.") :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n\n"
+                                                       "5\n"
+                                                       "00:00:12,345 --> 
00:00:15,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          )
+        (describe "with point on a non-last subtitle"
+          (it "passing nothing."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:01,000 --> 00:00:02,000\n"
+                             "Foo.\n\n"
+                             "2\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Bar.\n"))
+             (subed-jump-to-subtitle-time-start 1)
+             (expect (subed-append-subtitle) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:01,000 --> 
00:00:02,000\n"
+                                                       "Foo.\n\n"
+                                                       "0\n"
+                                                       "00:00:00,000 --> 
00:00:01,000\n"
+                                                       "\n\n"
+                                                       "2\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:01,000 --> 00:00:02,000\n"
+                             "Foo.\n\n"
+                             "2\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Bar.\n"))
+             (subed-jump-to-subtitle-time-start 1)
+             (expect (subed-append-subtitle 7) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:01,000 --> 
00:00:02,000\n"
+                                                       "Foo.\n\n"
+                                                       "7\n"
+                                                       "00:00:00,000 --> 
00:00:01,000\n"
+                                                       "\n\n"
+                                                       "2\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID and start time."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:01,000 --> 00:00:02,000\n"
+                             "Foo.\n\n"
+                             "2\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Bar.\n"))
+             (subed-jump-to-subtitle-time-start 1)
+             (expect (subed-append-subtitle 7 2500) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:01,000 --> 
00:00:02,000\n"
+                                                       "Foo.\n\n"
+                                                       "7\n"
+                                                       "00:00:02,500 --> 
00:00:03,500\n"
+                                                       "\n\n"
+                                                       "2\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID, start time and stop time."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:01,000 --> 00:00:02,000\n"
+                             "Foo.\n\n"
+                             "2\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Bar.\n"))
+             (subed-jump-to-subtitle-time-start 1)
+             (expect (subed-append-subtitle 7 2500 4000) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:01,000 --> 
00:00:02,000\n"
+                                                       "Foo.\n\n"
+                                                       "7\n"
+                                                       "00:00:02,500 --> 
00:00:04,000\n"
+                                                       "\n\n"
+                                                       "2\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID, start time, stop time and text."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:01,000 --> 00:00:02,000\n"
+                             "Foo.\n\n"
+                             "2\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Bar.\n"))
+             (subed-jump-to-subtitle-time-start 1)
+             (expect (subed-append-subtitle 7 2500 4000 "Baz.") :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:01,000 --> 
00:00:02,000\n"
+                                                       "Foo.\n\n"
+                                                       "7\n"
+                                                       "00:00:02,500 --> 
00:00:04,000\n"
+                                                       "Baz.\n\n"
+                                                       "2\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          )
+        )
+      (it "when point is on empty text."
+        (with-temp-srt-buffer
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "\n"))
+         (subed-jump-to-subtitle-text)
+         (expect (subed-append-subtitle) :to-equal 67)
+         (expect (buffer-string) :to-equal (concat "1\n"
+                                                   "00:00:01,000 --> 
00:00:02,000\n"
+                                                   "\n\n"
+                                                   "0\n"
+                                                   "00:00:00,000 --> 
00:00:01,000\n"
+                                                   "\n"))
+         (expect (point) :to-equal 67)))
+      )
     )
-  )
 
-(describe "Killing a subtitle"
-  (it "removes the first subtitle."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-jump-to-subtitle-text 1)
-      (subed-kill-subtitle)
-      (expect (buffer-string) :to-equal (concat "2\n"
-                                                "00:02:02,234 --> 
00:02:10,345\n"
-                                                "Bar.\n\n"
-                                                "3\n"
-                                                "00:03:03,45 --> 00:03:15,5\n"
-                                                "Baz.\n"))))
-  (it "removes it in between."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-jump-to-subtitle-text 2)
-      (subed-kill-subtitle)
-      (expect (buffer-string) :to-equal (concat "1\n"
-                                                "00:01:01,000 --> 
00:01:05,123\n"
-                                                "Foo.\n\n"
-                                                "3\n"
-                                                "00:03:03,45 --> 00:03:15,5\n"
-                                                "Baz.\n"))))
-  (it "removes the last subtitle."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-jump-to-subtitle-text 3)
-      (subed-kill-subtitle)
-      (expect (buffer-string) :to-equal (concat "1\n"
-                                                "00:01:01,000 --> 
00:01:05,123\n"
-                                                "Foo.\n\n"
-                                                "2\n"
-                                                "00:02:02,234 --> 
00:02:10,345\n"
-                                                "Bar.\n"))))
-  (describe "removes the previous subtitle when point is right above the ID"
-    (it "of the last subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-id 3)
-        (backward-char)
-        (expect (looking-at "^\n3\n") :to-be t)
-        (subed-kill-subtitle)
-        (expect (buffer-string) :to-equal (concat "1\n"
-                                                  "00:01:01,000 --> 
00:01:05,123\n"
-                                                  "Foo.\n\n"
-                                                  "3\n"
-                                                  "00:03:03,45 --> 
00:03:15,5\n"
-                                                  "Baz.\n"))))
-    (it "of a non-last subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-id 2)
-        (backward-char)
-        (expect (looking-at "^\n2\n") :to-be t)
-        (subed-kill-subtitle)
-        (expect (buffer-string) :to-equal (concat "2\n"
-                                                  "00:02:02,234 --> 
00:02:10,345\n"
-                                                  "Bar.\n\n"
-                                                  "3\n"
-                                                  "00:03:03,45 --> 
00:03:15,5\n"
-                                                  "Baz.\n"))))
+  (describe "Killing a subtitle"
+    (it "removes the first subtitle."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-text 1)
+       (subed-kill-subtitle)
+       (expect (buffer-string) :to-equal (concat "2\n"
+                                                 "00:02:02,234 --> 
00:02:10,345\n"
+                                                 "Bar.\n\n"
+                                                 "3\n"
+                                                 "00:03:03,45 --> 00:03:15,5\n"
+                                                 "Baz.\n"))))
+    (it "removes it in between."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-text 2)
+       (subed-kill-subtitle)
+       (expect (buffer-string) :to-equal (concat "1\n"
+                                                 "00:01:01,000 --> 
00:01:05,123\n"
+                                                 "Foo.\n\n"
+                                                 "3\n"
+                                                 "00:03:03,45 --> 00:03:15,5\n"
+                                                 "Baz.\n"))))
+    (it "removes the last subtitle."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-text 3)
+       (subed-kill-subtitle)
+       (expect (buffer-string) :to-equal (concat "1\n"
+                                                 "00:01:01,000 --> 
00:01:05,123\n"
+                                                 "Foo.\n\n"
+                                                 "2\n"
+                                                 "00:02:02,234 --> 
00:02:10,345\n"
+                                                 "Bar.\n"))))
+    (describe "removes the previous subtitle when point is right above the ID"
+      (it "of the last subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 3)
+         (backward-char)
+         (expect (looking-at "^\n3\n") :to-be t)
+         (subed-kill-subtitle)
+         (expect (buffer-string) :to-equal (concat "1\n"
+                                                   "00:01:01,000 --> 
00:01:05,123\n"
+                                                   "Foo.\n\n"
+                                                   "3\n"
+                                                   "00:03:03,45 --> 
00:03:15,5\n"
+                                                   "Baz.\n"))))
+      (it "of a non-last subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 2)
+         (backward-char)
+         (expect (looking-at "^\n2\n") :to-be t)
+         (subed-kill-subtitle)
+         (expect (buffer-string) :to-equal (concat "2\n"
+                                                   "00:02:02,234 --> 
00:02:10,345\n"
+                                                   "Bar.\n\n"
+                                                   "3\n"
+                                                   "00:03:03,45 --> 
00:03:15,5\n"
+                                                   "Baz.\n"))))
+      )
     )
-  )
 
-(describe "Validating"
-  (it "works in empty buffer."
-    (with-temp-srt-buffer
-     (subed-validate)))
-  (it "works in buffer that contains only newlines."
-    (with-temp-srt-buffer
-      (cl-loop for _ from 1 to 10 do
-               (insert "\n")
-               (subed-validate))))
-  (it "works in buffer that contains only spaces."
-    (with-temp-srt-buffer
-      (cl-loop for _ from 1 to 10 do
-               (insert " ")
-               (subed-validate))))
-  (it "works in buffer that contains only spaces and newlines."
-    (with-temp-srt-buffer
-      (cl-loop for _ from 1 to 10 do
-               (if (eq (random 2) 0)
-                   (insert " ")
-                 (insert "\n"))
-               (subed-validate))))
-  (it "reports invalid IDs."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-jump-to-subtitle-id 1)
-      (insert "x")
-      (expect (subed-validate) :to-throw
-              'error '("Found invalid subtitle ID: \"x1\""))
-      (expect (point) :to-equal 1)))
-  (it "reports invalid start time."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-jump-to-subtitle-time-start 1)
-      (forward-char 5)
-      (delete-char 1)
-      (expect (subed-validate) :to-throw
-              'error '("Found invalid start time: \"00:0101,000 --> 
00:01:05,123\""))
-      (expect (point) :to-equal 3)))
-  (it "reports invalid stop time."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-jump-to-subtitle-time-stop 1)
-      (forward-char 10)
-      (insert "3")
-      (expect (subed-validate) :to-throw
-              'error '("Found invalid stop time: \"00:01:01,000 --> 
00:01:05,1323\""))
-      (expect (point) :to-equal 20)))
-  (it "reports invalid time separator."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-jump-to-subtitle-time-stop 1)
-      (delete-char -1)
-      (expect (subed-validate) :to-throw
-              'error '("Found invalid separator between start and stop time: 
\"00:01:01,000 -->00:01:05,123\""))
-      (expect (point) :to-equal 15)))
-  (it "reports invalid start time in later entries."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-jump-to-subtitle-time-start 3)
-      (forward-char 3)
-      (insert "##")
-      (expect (subed-validate) :to-throw
-              'error '("Found invalid start time: \"00:##03:03,45 --> 
00:03:15,5\""))
-      (expect (point) :to-equal 79)))
-  (it "does not report error when last subtitle text is empty."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-jump-to-subtitle-text 3)
-      (kill-whole-line)
-      (forward-char -2)
-      (subed-validate)
-      (expect (point) :to-equal 104)))
-  (it "preserves point if there is no error."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-jump-to-subtitle-text 2)
-      (forward-char 2)
-      (subed-validate)
-      (expect (point) :to-equal 73)))
-  (it "runs before saving."
-    (with-temp-srt-buffer
-     (insert mock-srt-data)
-     (subed-jump-to-subtitle-time-start 3)
-     (forward-char 3)
-     (insert "##")
-     (expect (subed-prepare-to-save) :to-throw
-             'error '("Found invalid start time: \"00:##03:03,45 --> 
00:03:15,5\""))
-     (expect (point) :to-equal 79))))
+  (describe "Validating"
+    (it "works in empty buffer."
+      (with-temp-srt-buffer
+       (subed-validate)))
+    (it "works in buffer that contains only newlines."
+      (with-temp-srt-buffer
+       (cl-loop for _ from 1 to 10 do
+                (insert "\n")
+                (subed-validate))))
+    (it "works in buffer that contains only spaces."
+      (with-temp-srt-buffer
+       (cl-loop for _ from 1 to 10 do
+                (insert " ")
+                (subed-validate))))
+    (it "works in buffer that contains only spaces and newlines."
+      (with-temp-srt-buffer
+       (cl-loop for _ from 1 to 10 do
+                (if (eq (random 2) 0)
+                    (insert " ")
+                  (insert "\n"))
+                (subed-validate))))
+    (it "reports invalid IDs."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-id 1)
+       (insert "x")
+       (expect (subed-validate) :to-throw
+               'error '("Found invalid subtitle ID: \"x1\""))
+       (expect (point) :to-equal 1)))
+    (it "reports invalid start time."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-time-start 1)
+       (forward-char 5)
+       (delete-char 1)
+       (expect (subed-validate) :to-throw
+               'error '("Found invalid start time: \"00:0101,000 --> 
00:01:05,123\""))
+       (expect (point) :to-equal 3)))
+    (it "reports invalid stop time."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-time-stop 1)
+       (forward-char 10)
+       (insert "3")
+       (expect (subed-validate) :to-throw
+               'error '("Found invalid stop time: \"00:01:01,000 --> 
00:01:05,1323\""))
+       (expect (point) :to-equal 20)))
+    (it "reports invalid time separator."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-time-stop 1)
+       (delete-char -1)
+       (expect (subed-validate) :to-throw
+               'error '("Found invalid separator between start and stop time: 
\"00:01:01,000 -->00:01:05,123\""))
+       (expect (point) :to-equal 15)))
+    (it "reports invalid start time in later entries."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-time-start 3)
+       (forward-char 3)
+       (insert "##")
+       (expect (subed-validate) :to-throw
+               'error '("Found invalid start time: \"00:##03:03,45 --> 
00:03:15,5\""))
+       (expect (point) :to-equal 79)))
+    (it "does not report error when last subtitle text is empty."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-text 3)
+       (kill-whole-line)
+       (forward-char -2)
+       (subed-validate)
+       (expect (point) :to-equal 104)))
+    (it "preserves point if there is no error."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-text 2)
+       (forward-char 2)
+       (subed-validate)
+       (expect (point) :to-equal 73)))
+    (it "runs before saving."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-time-start 3)
+       (forward-char 3)
+       (insert "##")
+       (expect (subed-prepare-to-save) :to-throw
+               'error '("Found invalid start time: \"00:##03:03,45 --> 
00:03:15,5\""))
+       (expect (point) :to-equal 79))))
 
-(describe "Sanitizing"
-  (it "removes trailing tabs and spaces from all lines."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-min))
-      (while (re-search-forward "\n" nil t)
-        (replace-match " \n"))
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-sanitize)
-      (expect (buffer-string) :to-equal mock-srt-data))
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-min))
-      (while (re-search-forward "\n" nil t)
-        (replace-match "\t\n"))
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-sanitize)
-      (expect (buffer-string) :to-equal mock-srt-data)))
-  (it "removes leading tabs and spaces from all lines."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-min))
-      (while (re-search-forward "\n" nil t)
-        (replace-match "\n "))
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-sanitize)
-      (expect (buffer-string) :to-equal mock-srt-data))
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-min))
-      (while (re-search-forward "\n" nil t)
-        (replace-match "\n\t"))
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-sanitize)
-      (expect (buffer-string) :to-equal mock-srt-data)))
-  (it "removes excessive empty lines between subtitles."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-min))
-      (while (re-search-forward "\n\n" nil t)
-        (replace-match "\n \n  \t  \t\t  \n\n  \t\n"))
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-sanitize)
-      (expect (buffer-string) :to-equal mock-srt-data)))
-  (it "ensures double newline between subtitles if text of previous subtitle 
is empty."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-jump-to-subtitle-text 1)
-      (kill-whole-line)
-      (expect (buffer-string) :to-equal (concat "1\n"
-                                                "00:01:01,000 --> 
00:01:05,123\n"
-                                                "\n"
-                                                "2\n"
-                                                "00:02:02,234 --> 
00:02:10,345\n"
-                                                "Bar.\n\n"
-                                                "3\n"
-                                                "00:03:03,45 --> 00:03:15,5\n"
-                                                "Baz.\n"))
-      (subed-sanitize)
-      (expect (buffer-string) :to-equal (concat "1\n"
-                                                "00:01:01,000 --> 
00:01:05,123\n"
-                                                "\n\n"
-                                                "2\n"
-                                                "00:02:02,234 --> 
00:02:10,345\n"
-                                                "Bar.\n\n"
-                                                "3\n"
-                                                "00:03:03,45 --> 00:03:15,5\n"
-                                                "Baz.\n"))))
-  (it "removes empty lines from beginning of buffer."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-min))
-      (insert " \n\t\n")
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-sanitize)
-      (expect (buffer-string) :to-equal mock-srt-data)))
-  (it "removes empty lines from end of buffer."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-max))
-      (insert " \n\t\n\n")
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-sanitize)
-      (expect (buffer-string) :to-equal mock-srt-data)))
-  (it "ensures a single newline after the last subtitle."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-max))
-      (while (eq (char-before (point-max)) ?\n)
-        (delete-backward-char 1))
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-sanitize)
-      (expect (buffer-string) :to-equal mock-srt-data)))
-  (it "ensures single newline after last subtitle if text is empty."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-jump-to-subtitle-text 3)
-      (kill-whole-line)
-      (expect (buffer-string) :to-equal (concat "1\n"
-                                                "00:01:01,000 --> 
00:01:05,123\n"
-                                                "Foo.\n\n"
-                                                "2\n"
-                                                "00:02:02,234 --> 
00:02:10,345\n"
-                                                "Bar.\n\n"
-                                                "3\n"
-                                                "00:03:03,45 --> 00:03:15,5\n"
-                                                ""))
-      (subed-sanitize)
-      (expect (buffer-string) :to-equal (concat "1\n"
-                                                "00:01:01,000 --> 
00:01:05,123\n"
-                                                "Foo.\n\n"
-                                                "2\n"
-                                                "00:02:02,234 --> 
00:02:10,345\n"
-                                                "Bar.\n\n"
-                                                "3\n"
-                                                "00:03:03,45 --> 00:03:15,5\n"
-                                                "\n"))))
-  (it "ensures single space before and after time separators."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-min))
-      (re-search-forward " --> ")
-      (replace-match "  --> ")
-      (re-search-forward " --> ")
-      (replace-match " -->  ")
-      (re-search-forward " --> ")
-      (replace-match "-->")
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-sanitize)
-      (expect (buffer-string) :to-equal mock-srt-data)))
-  (it "does not insert newline in empty buffer."
-    (with-temp-srt-buffer
-      (expect (buffer-string) :to-equal "")
-      (subed-sanitize)
-      (expect (buffer-string) :to-equal "")))
-  (it "runs before saving."
-    (with-temp-srt-buffer
-     (insert mock-srt-data)
-     (goto-char (point-min))
-     (re-search-forward " --> ")
-     (replace-match "  --> ")
-     (re-search-forward " --> ")
-     (replace-match " -->  ")
-     (re-search-forward " --> ")
-     (replace-match "-->")
-     (expect (buffer-string) :not :to-equal mock-srt-data)
-     (subed-prepare-to-save)
-     (expect (buffer-string) :to-equal mock-srt-data))))
+  (describe "Sanitizing"
+    (it "removes trailing tabs and spaces from all lines."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (while (re-search-forward "\n" nil t)
+         (replace-match " \n"))
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal mock-srt-data))
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (while (re-search-forward "\n" nil t)
+         (replace-match "\t\n"))
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal mock-srt-data)))
+    (it "removes leading tabs and spaces from all lines."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (while (re-search-forward "\n" nil t)
+         (replace-match "\n "))
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal mock-srt-data))
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (while (re-search-forward "\n" nil t)
+         (replace-match "\n\t"))
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal mock-srt-data)))
+    (it "removes excessive empty lines between subtitles."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (while (re-search-forward "\n\n" nil t)
+         (replace-match "\n \n  \t  \t\t  \n\n  \t\n"))
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal mock-srt-data)))
+    (it "ensures double newline between subtitles if text of previous subtitle 
is empty."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-text 1)
+       (kill-whole-line)
+       (expect (buffer-string) :to-equal (concat "1\n"
+                                                 "00:01:01,000 --> 
00:01:05,123\n"
+                                                 "\n"
+                                                 "2\n"
+                                                 "00:02:02,234 --> 
00:02:10,345\n"
+                                                 "Bar.\n\n"
+                                                 "3\n"
+                                                 "00:03:03,45 --> 00:03:15,5\n"
+                                                 "Baz.\n"))
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal (concat "1\n"
+                                                 "00:01:01,000 --> 
00:01:05,123\n"
+                                                 "\n\n"
+                                                 "2\n"
+                                                 "00:02:02,234 --> 
00:02:10,345\n"
+                                                 "Bar.\n\n"
+                                                 "3\n"
+                                                 "00:03:03,45 --> 00:03:15,5\n"
+                                                 "Baz.\n"))))
+    (it "removes empty lines from beginning of buffer."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (insert " \n\t\n")
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal mock-srt-data)))
+    (it "removes empty lines from end of buffer."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-max))
+       (insert " \n\t\n\n")
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal mock-srt-data)))
+    (it "ensures a single newline after the last subtitle."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-max))
+       (while (eq (char-before (point-max)) ?\n)
+         (delete-backward-char 1))
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal mock-srt-data)))
+    (it "ensures single newline after last subtitle if text is empty."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-text 3)
+       (kill-whole-line)
+       (expect (buffer-string) :to-equal (concat "1\n"
+                                                 "00:01:01,000 --> 
00:01:05,123\n"
+                                                 "Foo.\n\n"
+                                                 "2\n"
+                                                 "00:02:02,234 --> 
00:02:10,345\n"
+                                                 "Bar.\n\n"
+                                                 "3\n"
+                                                 "00:03:03,45 --> 00:03:15,5\n"
+                                                 ""))
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal (concat "1\n"
+                                                 "00:01:01,000 --> 
00:01:05,123\n"
+                                                 "Foo.\n\n"
+                                                 "2\n"
+                                                 "00:02:02,234 --> 
00:02:10,345\n"
+                                                 "Bar.\n\n"
+                                                 "3\n"
+                                                 "00:03:03,45 --> 00:03:15,5\n"
+                                                 "\n"))))
+    (it "ensures single space before and after time separators."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (re-search-forward " --> ")
+       (replace-match "  --> ")
+       (re-search-forward " --> ")
+       (replace-match " -->  ")
+       (re-search-forward " --> ")
+       (replace-match "-->")
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal mock-srt-data)))
+    (it "does not insert newline in empty buffer."
+      (with-temp-srt-buffer
+       (expect (buffer-string) :to-equal "")
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal "")))
+    (it "runs before saving."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (re-search-forward " --> ")
+       (replace-match "  --> ")
+       (re-search-forward " --> ")
+       (replace-match " -->  ")
+       (re-search-forward " --> ")
+       (replace-match "-->")
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-prepare-to-save)
+       (expect (buffer-string) :to-equal mock-srt-data))))
 
-(describe "Renumbering"
-  (it "ensures consecutive subtitle IDs."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-min))
-      (while (looking-at "^[0-9]$")
-        (replace-match "123"))
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-srt--regenerate-ids)
-      (expect (buffer-string) :to-equal mock-srt-data)))
-  (it "runs before saving."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-min))
-      (while (looking-at "^[0-9]$")
-        (replace-match "123"))
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-prepare-to-save)
-      (expect (buffer-string) :to-equal mock-srt-data)))
-  (it "does not modify the kill-ring."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (kill-new "asdf")
-      (goto-char (point-min))
-      (while (looking-at "^[0-9]$")
-        (insert "555"))
-      (subed-srt--regenerate-ids)
-      (expect (car kill-ring) :to-equal "asdf")))
-  (it "does not modify empty buffer."
-    (with-temp-srt-buffer
-      (subed-srt--regenerate-ids)
-      (expect (buffer-string) :to-equal "")))
-  )
+  (describe "Renumbering"
+    (it "ensures consecutive subtitle IDs."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (while (looking-at "^[0-9]$")
+         (replace-match "123"))
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-srt--regenerate-ids)
+       (expect (buffer-string) :to-equal mock-srt-data)))
+    (it "runs before saving."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (while (looking-at "^[0-9]$")
+         (replace-match "123"))
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-prepare-to-save)
+       (expect (buffer-string) :to-equal mock-srt-data)))
+    (it "does not modify the kill-ring."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (kill-new "asdf")
+       (goto-char (point-min))
+       (while (looking-at "^[0-9]$")
+         (insert "555"))
+       (subed-srt--regenerate-ids)
+       (expect (car kill-ring) :to-equal "asdf")))
+    (it "does not modify empty buffer."
+      (with-temp-srt-buffer
+       (subed-srt--regenerate-ids)
+       (expect (buffer-string) :to-equal "")))
+    )
 
-(describe "Sorting"
-  (it "orders subtitles by start time."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-min))
-      (re-search-forward "01:01")
-      (replace-match "12:01")
-      (goto-char (point-min))
-      (re-search-forward "02:02")
-      (replace-match "10:02")
-      (goto-char (point-min))
-      (re-search-forward "03:03")
-      (replace-match "11:03")
-      (subed-sort)
-      (expect (buffer-string) :to-equal
-              (concat
-               "1\n"
-               "00:10:02,234 --> 00:02:10,345\n"
-               "Bar.\n"
-               "\n"
-               "2\n"
-               "00:11:03,45 --> 00:03:15,5\n"
-               "Baz.\n"
-               "\n"
-               "3\n"
-               "00:12:01,000 --> 00:01:05,123\n"
-               "Foo.\n"))))
-  (describe "preserves point in the current subtitle"
-    (it "when subtitle text is non-empty."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (re-search-forward "01:01")
-        (replace-match "12:01")
-        (search-forward "\n")
-        (expect (current-word) :to-equal "Foo")
-        (subed-sort)
-        (expect (current-word) :to-equal "Foo")))
-    (it "when subtitle text is empty."
-      (with-temp-srt-buffer
-        (insert "1\n00:12:01,000 --> 00:01:05,123\n")
-        (goto-char (point-max))
-        (subed-sort)
-        (expect (point) :to-equal 33)))
+  (describe "Sorting"
+    (it "orders subtitles by start time."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (re-search-forward "01:01")
+       (replace-match "12:01")
+       (goto-char (point-min))
+       (re-search-forward "02:02")
+       (replace-match "10:02")
+       (goto-char (point-min))
+       (re-search-forward "03:03")
+       (replace-match "11:03")
+       (subed-sort)
+       (expect (buffer-string) :to-equal
+               (concat
+                "1\n"
+                "00:10:02,234 --> 00:02:10,345\n"
+                "Bar.\n"
+                "\n"
+                "2\n"
+                "00:11:03,45 --> 00:03:15,5\n"
+                "Baz.\n"
+                "\n"
+                "3\n"
+                "00:12:01,000 --> 00:01:05,123\n"
+                "Foo.\n"))))
+    (describe "preserves point in the current subtitle"
+      (it "when subtitle text is non-empty."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (re-search-forward "01:01")
+         (replace-match "12:01")
+         (search-forward "\n")
+         (expect (current-word) :to-equal "Foo")
+         (subed-sort)
+         (expect (current-word) :to-equal "Foo")))
+      (it "when subtitle text is empty."
+        (with-temp-srt-buffer
+         (insert "1\n00:12:01,000 --> 00:01:05,123\n")
+         (goto-char (point-max))
+         (subed-sort)
+         (expect (point) :to-equal 33)))
+      )
     )
-  )
-(describe "Converting msecs to timestamp"
-  (it "uses the right format"
-    (with-temp-srt-buffer
-     (expect (subed-msecs-to-timestamp 1401) :to-equal "00:00:01,401"))))
+  (describe "Converting msecs to timestamp"
+    (it "uses the right format"
+      (with-temp-srt-buffer
+       (expect (subed-msecs-to-timestamp 1401) :to-equal "00:00:01,401"))))
+
+  (describe "Merging with next subtitle"
+    (it "throws an error in an empty buffer."
+      (with-temp-srt-buffer
+       (expect (subed-merge-with-next) :to-throw 'error)))
+    (it "throws an error with the last subtitle."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-text 3)
+       (expect (subed-merge-with-next) :to-throw 'error)))
+    (it "combines the text and the time."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-text 2)
+       (subed-merge-with-next)
+       (expect (subed-subtitle-text) :to-equal "Bar.\nBaz.")
+       (expect (subed-subtitle-msecs-start) :to-equal 122234)
+       (expect (subed-subtitle-msecs-stop) :to-equal 195500)))))
diff --git a/tests/test-subed-vtt.el b/tests/test-subed-vtt.el
index cedec364dc..7f27d9eb31 100644
--- a/tests/test-subed-vtt.el
+++ b/tests/test-subed-vtt.el
@@ -25,6 +25,51 @@ Baz.
 
 (describe "VTT"
   (describe "Getting"
+    (describe "the subtitle ID"
+      (it "returns the subtitle ID if it can be found."
+        (with-temp-vtt-buffer
+         (insert mock-vtt-data)
+         (subed-jump-to-subtitle-text "00:01:01.000")
+         (expect (subed-subtitle-id) :to-equal "00:01:01.000")))
+      (it "returns nil if no subtitle ID can be found."
+        (with-temp-vtt-buffer
+         (expect (subed-subtitle-id) :to-equal nil))))
+    (describe "the subtitle ID at playback time"
+      (it "returns subtitle ID if time is equal to start time."
+        (with-temp-vtt-buffer
+         (insert mock-vtt-data)
+         (expect (subed-subtitle-id-at-msecs (subed-timestamp-to-msecs 
"00:01:01.000"))
+                 :to-equal "00:01:01.000")))
+      (it "returns subtitle ID if time is equal to stop time."
+        (with-temp-vtt-buffer
+         (insert mock-vtt-data)
+         (expect (subed-subtitle-id-at-msecs (subed-timestamp-to-msecs 
"00:02:10.345"))
+                 :to-equal "00:02:02.234")))
+      (it "returns subtitle ID if time is between start and stop time."
+        (with-temp-vtt-buffer
+         (insert mock-vtt-data)
+         (expect (subed-subtitle-id-at-msecs (subed-timestamp-to-msecs 
"00:02:05.345"))
+                 :to-equal "00:02:02.234")))
+      (it "returns nil if time is before the first subtitle's start time."
+        (with-temp-vtt-buffer
+         (insert mock-vtt-data)
+         (let ((msecs (- (save-excursion
+                           (goto-char (point-min))
+                           (subed-subtitle-msecs-start))
+                         1)))
+           (expect (subed-subtitle-id-at-msecs msecs) :to-equal nil))))
+      (it "returns nil if time is after the last subtitle's start time."
+        (with-temp-vtt-buffer
+         (insert mock-vtt-data)
+         (let ((msecs (+ (save-excursion
+                           (goto-char (point-max))
+                           (subed-subtitle-msecs-stop)) 1)))
+           (expect (subed-subtitle-id-at-msecs msecs) :to-equal nil))))
+      (it "returns nil if time is between subtitles."
+        (with-temp-vtt-buffer
+         (insert mock-vtt-data)
+         (expect (subed-subtitle-id-at-msecs (subed-timestamp-to-msecs 
"00:01:06.123"))
+                 :to-equal nil))))
     (describe "the subtitle start/stop time"
       (it "returns the time in milliseconds."
         (with-temp-vtt-buffer
@@ -1218,4 +1263,22 @@ This is another test here.
        (subed-forward-subtitle-end)
        (expect (current-word) :to-equal "test")
        (subed-forward-subtitle-end)
-       (expect (current-word) :to-equal "here")))))
+       (expect (current-word) :to-equal "here"))))
+
+  (describe "Merging with next subtitle"
+    (it "throws an error in an empty buffer."
+      (with-temp-vtt-buffer
+       (expect (subed-merge-with-next) :to-throw 'error)))
+    (it "throws an error with the last subtitle."
+      (with-temp-vtt-buffer
+       (insert mock-vtt-data)
+       (subed-jump-to-subtitle-text 3)
+       (expect (subed-merge-with-next) :to-throw 'error)))
+    (it "combines the text and the time."
+      (with-temp-vtt-buffer
+       (insert mock-vtt-data)
+       (subed-jump-to-subtitle-text "00:02:02.234")
+       (subed-merge-with-next)
+       (expect (subed-subtitle-text) :to-equal "Bar.\nBaz.")
+       (expect (subed-subtitle-msecs-start) :to-equal 122234)
+       (expect (subed-subtitle-msecs-stop) :to-equal 195500)))))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]