import std/[strutils, unittest] import ../src/embedded_bible import ../src/kjv import ../src/reference_parser suite "reference parser": test "parses single verse references": let reference = parseReference("John 3:16") check reference.book.code == "JHN" check reference.ranges.len == 1 check reference.ranges[0].start.chapter == 3 check reference.ranges[0].start.verse == 16 check reference.ranges[0].finish == reference.ranges[0].start check $reference == "John 3:16" test "parses verse lists using the previous chapter": let reference = parseReference("John 3:16,20-21") check reference.ranges.len == 2 check reference.ranges[1].start.chapter == 3 check reference.ranges[1].start.verse == 20 check reference.ranges[1].finish.chapter == 3 check reference.ranges[1].finish.verse == 21 check $reference == "John 3:16, 3:20-21" test "parses chapter ranges": let reference = parseReference("John 3-4") check reference.ranges.len == 1 check reference.ranges[0].start.chapter == 3 check reference.ranges[0].start.verse == 0 check reference.ranges[0].finish.chapter == 4 check reference.ranges[0].finish.verse == 0 check $reference == "John 3-4" test "parses abbreviated numbered books": let reference = parseReference("1 Jn 1:9") check reference.book.code == "1JN" check reference.ranges[0].start.chapter == 1 check reference.ranges[0].start.verse == 9 check $reference == "1 John 1:9" test "parses unique canonical book prefixes": check parseReference("Gene 1:1").book.code == "GEN" check parseReference("Phile 3").book.code == "PHM" check parseReference("Phili 1:6").book.code == "PHP" test "rejects ambiguous canonical book prefixes": expect ValueError: discard parseReference("Phil 1") test "normalizes single-chapter book references": let reference = parseReference("Jude 3-4") check reference.book.code == "JUD" check reference.ranges[0].start.chapter == 1 check reference.ranges[0].start.verse == 3 check reference.ranges[0].finish.chapter == 1 check reference.ranges[0].finish.verse == 4 check $reference == "Jude 3-4" test "parses semicolon-separated references": let references = parseReferences("Psalm 23; John 3:16") check references.len == 2 check references[0].book.code == "PSA" check references[1].book.code == "JHN" suite "offline KJV backend": test "fetches a single embedded verse": let passages = kjv.fetchPassages("John 3:16") check passages.len == 1 check passages[0].startsWith("John 3:16\n") check passages[0].contains(" [16] ") test "fetches a single-chapter embedded verse": let passages = kjv.fetchPassages("Jude 3") check passages.len == 1 check passages[0].startsWith("Jude 3\n") check passages[0].contains(" [3] ") suite "embedded Bible layout": const layoutRows = """ JHN 8 31 0 paragraph 0 Then Jesus said, JHN 8 31 1 same 0 "If you remain in My word, JHN 8 32 0 same 0 you shall know the truth." JHN 8 33 0 paragraph 0 They answered Him. JHN 8 39 0 paragraph 0 They answered Him, "Abraham is our father." JHN 8 39 1 paragraph 0 Jesus said to them, "If you were Abraham's children, JHN 8 40 0 same 0 you would do the works of Abraham." JHN 8 41 0 paragraph 0 You shall be free' JHN 8 41 1 same 0 ? HEB 4 7 0 paragraph 0 again He establishes a certain day: HEB 4 7 1 line 0 "Today, if you will hear His voice, HEB 4 7 2 line 1 do not harden your hearts." """ test "preserves inline verse markers within a paragraph": let passages = embedded_bible.fetchPassages(layoutRows, "John 8:31-32", "TEST") check passages.len == 1 check passages[0] == "John 8:31-32\n" & " [31] Then Jesus said, \"If you remain in My word, [32] you shall know the truth.\"" test "preserves paragraph breaks": let passages = embedded_bible.fetchPassages(layoutRows, "John 8:31-33", "TEST") check passages[0] == "John 8:31-33\n" & " [31] Then Jesus said, \"If you remain in My word, [32] you shall know the truth.\"\n" & "\n" & " [33] They answered Him." test "preserves indented quote lines": let passages = embedded_bible.fetchPassages(layoutRows, "Hebrews 4:7", "TEST") check passages[0] == "Hebrews 4:7\n" & " [7] again He establishes a certain day:\n" & " \"Today, if you will hear His voice,\n" & " do not harden your hearts.\"" test "starts mid-paragraph ranges on a fresh line": let passages = embedded_bible.fetchPassages(layoutRows, "John 8:32-33", "TEST") check passages[0] == "John 8:32-33\n" & " [32] you shall know the truth.\"\n" & "\n" & " [33] They answered Him." test "joins markerless paragraph continuations": let passages = embedded_bible.fetchPassages(layoutRows, "John 8:39-40", "TEST") check passages[0] == "John 8:39-40\n" & " [39] They answered Him, \"Abraham is our father.\" " & "Jesus said to them, \"If you were Abraham's children, " & "[40] you would do the works of Abraham.\"" test "joins punctuation-only segments without extra spacing": let passages = embedded_bible.fetchPassages(layoutRows, "John 8:41", "TEST") check passages[0] == "John 8:41\n [41] You shall be free'?" test "supports legacy verse rows": const legacyRows = "JHN\t3\t16\tFor God so loved the world.\n" let passages = embedded_bible.fetchPassages(legacyRows, "John 3:16", "TEST") check passages[0] == "John 3:16\n [16] For God so loved the world." test "ignores layout metadata while rendering": const metadataRows = "JHN\t8\t31\t0\tparagraph\t0\tJesus said.\t" & """{"wordsOfChrist":true,"annotations":[{"kind":"crossReference","marker":"a","href":"index_split_1.html#x","offset":6}]}""" & "\n" let passages = embedded_bible.fetchPassages(metadataRows, "John 8:31", "TEST") check passages[0] == "John 8:31\n [31] Jesus said." test "groups legacy rows into paragraphs using pilcrows": const legacyRows = "JHN\t8\t31\tThen Jesus said.\n" & "JHN\t8\t32\tYou shall know the truth.\n" & "JHN\t8\t33\t\xC2\xB6 They answered Him.\n" let passages = embedded_bible.fetchPassages(legacyRows, "John 8:31-33", "TEST") check passages[0] == "John 8:31-33\n" & " [31] Then Jesus said. [32] You shall know the truth.\n" & "\n" & " [33] They answered Him." test "plain output renders annotation footnotes": const rows = "JHN\t8\t1\t0\tparagraph\t0\tBut Jesus went to the Mount of Olives.\t" & """{"annotations":[{"kind":"crossReference","marker":"a","offset":40,"targetText":"Mt 21:1"}]}""" & "\n" & "JHN\t8\t2\t0\tsame\t0\tEarly in the morning He returned to the temple.\t" & """{"annotations":[{"kind":"crossReference","marker":"a","offset":49,"targetText":"Mt 26:55; Lk 4:20"}]}""" & "\n" let passages = embedded_bible.fetchPlainPassages(rows, "John 8:1-2", "TEST") check passages[0] == "1 But Jesus went to the Mount of Olives.[a] 2 Early in the morning He\n" & "returned to the temple.[b]\n" & "\n" & "a. Mt 21:1\n" & "b. Mt 26:55; Lk 4:20\n" & "\n" & "– John 8:1-2 (TEST)" test "plain output resets footnote labels per chapter": const rows = "JHN\t8\t59\t0\tparagraph\t0\tThey took up stones.\t" & """{"annotations":[{"kind":"crossReference","marker":"a","offset":21,"targetText":"Lev 24:16"}]}""" & "\n" & "JHN\t9\t1\t0\tparagraph\t0\tAs Jesus passed by.\t" & """{"annotations":[{"kind":"crossReference","marker":"a","offset":20,"targetText":"Jn 8:12"}]}""" & "\n" let passages = embedded_bible.fetchPlainPassages(rows, "John 8:59-9:1", "TEST") check passages[0] == "59 They took up stones.[a]\n" & "\n" & "a. Lev 24:16\n" & "\n" & "1 As Jesus passed by.[a]\n" & "\n" & "a. Jn 8:12\n" & "\n" & "– John 8:59-9:1 (TEST)" test "markdown output renders native footnotes": const rows = "JHN\t8\t1\t0\tparagraph\t0\tBut Jesus went to the Mount of Olives.\t" & """{"annotations":[{"kind":"crossReference","marker":"a","offset":40,"targetText":"Mt 21:1"}]}""" & "\n" & "JHN\t8\t2\t0\tsame\t0\tEarly in the morning He returned to the temple.\t" & """{"annotations":[{"kind":"crossReference","marker":"a","offset":49,"targetText":"Mt 26:55; Lk 4:20"}]}""" & "\n" let passages = embedded_bible.fetchMarkdownPassages(rows, "John 8:1-2", "TEST") check passages[0] == "> **1** But Jesus went to the Mount of Olives.[^a] **2** Early in the\n" & "> morning He returned to the temple.[^b]\n" & "\n" & "[^a]: Mt 21:1\n" & "[^b]: Mt 26:55; Lk 4:20\n" & "\n" & "> -- *John 8:1-2 (TEST)*" test "markdown output resets native footnotes per chapter": const rows = "JHN\t8\t59\t0\tparagraph\t0\tThey took up stones.\t" & """{"annotations":[{"kind":"crossReference","marker":"a","offset":21,"targetText":"Lev 24:16"}]}""" & "\n" & "JHN\t9\t1\t0\tparagraph\t0\tAs Jesus passed by.\t" & """{"annotations":[{"kind":"crossReference","marker":"a","offset":20,"targetText":"Jn 8:12"}]}""" & "\n" let passages = embedded_bible.fetchMarkdownPassages(rows, "John 8:59-9:1", "TEST") check passages[0] == "> **59** They took up stones.[^a]\n" & "\n" & "[^a]: Lev 24:16\n" & "\n" & "> **1** As Jesus passed by.[^a]\n" & "\n" & "[^a]: Jn 8:12\n" & "\n" & "> -- *John 8:59-9:1 (TEST)*"