# mupdf-textsearch.test --
#
#	Tests about structured text extraction and searching.
#

package require TTXN
  # package under test is tclMuPDF 2.1
package require tclMuPDF 2.1

set thisDir [file dirname [file normalize [info script]]]
set samplesDir [file join $thisDir samples]

 # -- some helpers for an easy comparing results -----------------------------
 
 # simply list of lists .. real to integer ..
proc simplifyListOfList4 {LL} {
    set RR {}
    foreach box $LL {
        set R {}
        foreach coord $box {
            lappend R [expr int($coord)]
        }
        lappend RR $R
    }
    return $RR
}

proc simplifySearchResults {LL} {
    set R {}
    foreach page_and_bbox $LL {
        lassign $page_and_bbox pageNum bbox        
        set bbox [simplifyListOfList4 $bbox]
        lappend R [list $pageNum $bbox]
    }
    return $R
}

#  --------------------------------------------------------------------------
#  Tests on Text extraction 
#  --------------------------------------------------------------------------

Name: text
Description: {text: get text from page 0}
Setup: {
    set pdf [mupdf::open [file join $samplesDir LoremIpsum.pdf]]
}
Test: {
    set page [$pdf getpage 0]
    set txt [$page text]
     # compare just the first 35 chars .. 
     #   (and replace newline with @)
     #   (and replace /uA0 (no break space) with " " (space))
    return "[string map {\n @ \uA0 \u20} [string range $txt 0 35]]"
}
Cleanup: { $pdf quit }
Expected: {Lorem Ipsum  @@Lákanie vônehulás umý}

Name: text_blocks
Description: {text: get text and blocks bbox from page 0}
Setup: {
    set pdf [mupdf::open [file join $samplesDir "Alphabets.pdf"]]
}
Test: {
    set page [$pdf getpage 0]
    set txtbbox [$page text -bbox blocks]

     # simplify numbers for comparision
    set bbox [simplifyListOfList4 [lindex $txtbbox 4]]
    set txt [lindex $txtbbox 5]
	     #   (and replace newline with @)
    set txt [string map {\n @} $txt]    
    return [list $bbox $txt]
}
Cleanup: { $pdf quit }
Expected: {{56 105 491 139} {Lorem ipsum dolor sit amet, periculis søluta at, mei æn iusto @constituto.}}

Name: text_bbox_lines
Description: {text: get text and lines bbox from page 0}
Setup: {
    set pdf [mupdf::open [file join $samplesDir "Alphabets.pdf"]]
}
Test: {
    set page [$pdf getpage 0]
    set txtbbox [$page text -bbox lines]

	 # get the 3rd block coords  (6th elem)
	 # get its first line boox   (0th elem of the 7th elem)
	 # get its first lline text  (1st elem of the 7th elem)
	 
	set blockbbox [lindex $txtbbox 6] 
     # simplify numbers for comparision
    set blockbbox [simplifyListOfList4 $blockbbox]
    
    set linebbox [lindex $txtbbox 7 0]
    set linebbox [simplifyListOfList4 $linebbox]
    set txt [lindex $txtbbox 7 1]

    return [list $blockbbox $linebbox $txt]
}
Cleanup: { $pdf quit }
Expected: {{56 156 501 190} {56 156 501 173} {Usu ut esse liber omnium. Ex søluta repudiare per, elitr eripuit }}

#  --------------------------------------------------------------------------
#  Tests on TextSearch 
#  --------------------------------------------------------------------------

Name: TextSearch.neg.1
Description: {create a text-search on a wrong object}
Setup: {
    set dummyObj [oo::object new]
}
Test: {
    set searchObj [mupdf::TextSearch new $dummyObj]    
}
Cleanup: { $dummyObj destroy }
Expected: error glob "* must be an instance of mupdf::Doc"


Name: TextSearch.neg.2
Description: {create a text-search on a wrong $doc}
Test: {
     # $pdf is a wrong (closed) document
    set pdf [mupdf::open [file join $samplesDir LoremIpsum.pdf]]
    $pdf quit    
    set searchObj [mupdf::TextSearch new $pdf]
}
Expected: error glob "* must be an instance of mupdf::Doc"

Name: TextSearch.check.destruction.on.doc.quit
Description: {check.destruction.on.doc.quit}
Test: {
    set pdf [mupdf::open [file join $samplesDir LoremIpsum.pdf]]
    set searchObj [mupdf::TextSearch new $pdf]
     # do some work
    $searchObj find "vônehulás"
     # close the doc and check if searchObj is destroyed
    $pdf quit
    info object class $searchObj   ;# this should raise an error
}
Expected: error glob "* does not refer to an object"


# -- Working with LoremIpsum.pdf 
#    This pdf contains text with non-US characters
#
# ====================================================
# All the following tests are based on a common setup:
# ====================================================
    set pdf [mupdf::open [file join $samplesDir LoremIpsum.pdf]]


Name: TextSearch.docref
Description: {get the related doc}
Setup: { set searchObj [mupdf::TextSearch new $pdf] }
Test: {
    $searchObj docref
}
Cleanup: { $searchObj destroy }
Expected: $pdf

Name: TextSearch.currpage.set&get
Description: {set and get the currpage}
Setup: { set searchObj [mupdf::TextSearch new $pdf] }
Test: {
    $searchObj currpage 1
    $searchObj currpage
}
Cleanup: { $searchObj destroy }
Expected: 1

Name: find.currpage.neg
Description: {try to set a wrong page-number}
Setup: { set searchObj [mupdf::TextSearch new $pdf] }
Test: {
    $searchObj currpage -33
    $searchObj currpage
}
Cleanup: { $searchObj destroy }
Expected: error glob {page-number must be between 0 and *}


Name: TextSearch.find.wrong.args.neg
Description: {try to run a find with wrong args}
Setup: { set searchObj [mupdf::TextSearch new $pdf] }
Test: {
    $searchObj find hello -badoption 22
}
Cleanup: { $searchObj destroy }
Expected: error glob {bad option "-badoption": should be *}


Name: TextSearch.find.max-hits.too.high.neg
Description: {try to run a find with -max too high}
Setup: { set searchObj [mupdf::TextSearch new $pdf] }
Test: {
    $searchObj find hello -max 1000
}
Cleanup: { $searchObj destroy }
Expected: error {value for "-max" must be between 1 and 100}

Name: TextSearch.find.
Description: {find a string (accented letters)- global search vs progressive search}
Setup: { set searchObj [mupdf::TextSearch new $pdf] }
Test: {
     # count the hit numbers
    set N1 [llength [$searchObj find "slochyòsko" -max 100]] ; # expected 8
    set N2 0
    $searchObj currpage 0
    while {true} {
        set n [llength [$searchObj find "slochyòsko" -max 3]]
        if { $n == 0 } break
        incr N2 $n
    }        
    expr {$N1 == 8 && $N1 == $N2}
}
Cleanup: { $searchObj destroy }
Expected: 1


Name: TextSearch.find.simple
Description: {find a string and check the position}
Setup: { set searchObj [mupdf::TextSearch new $pdf] }
Test: {
    set L [$searchObj find "robo"]
     # simplify numbers for comparision
    simplifySearchResults $L
}
Cleanup: { $searchObj destroy }
Expected: {{0 {140 291 161 302}} {0 {122 613 143 624}} {1 {218 226 239 237}} {1 {377 354 399 365}} {1 {218 385 239 396}}}


Name: TextSearch.find.simple.currpageonly
Description: {find a string and check the position}
Setup: { 
      # Book.pdf has 5 pages; 
      # we are going to find text "Nusc suspendisse" ( it's on page 2 and 4)
      # but starting from page 1, we limit the search to one page
    set pdf2 [mupdf::open [file join $samplesDir Book.pdf]]
    set searchObj [mupdf::TextSearch new $pdf2] 
}
Test: {
     # full doc search : we expect 2 matches
    $searchObj currpage 0
    set L1 [$searchObj find "Nunc suspendisse" -currpageonly false -max 100]

     # search in page 0 only: we expect 0 matches
    $searchObj currpage 0
    set L2 [$searchObj find "Nunc suspendisse" -currpageonly true -max 100]

     # search in page 2 only: we expect 1 matches
    $searchObj currpage 2
    set L3 [$searchObj find "Nunc suspendisse" -currpageonly true -max 100]

    return [list [llength $L1] [llength $L2] [llength $L3]]
}
Cleanup: { 
    $searchObj destroy 
    $pdf2 quit
}
Expected: {2 0 1}


Name: TextSearch.find.simple.limited
Description: {find a string and check the position}
Setup: { set searchObj [mupdf::TextSearch new $pdf] }
Test: {
     # start search frompage 1
    $searchObj currpage 1
    set L [$searchObj find "robo" -max 1]
     # simplify numbers for comparision
    simplifySearchResults $L
}
Cleanup: { $searchObj destroy }
Expected: {{1 {218 226 239 237}}}


Name: TextSearch.find.unmatched.string
Description: {find a string and check the position}
Setup: { set searchObj [mupdf::TextSearch new $pdf] }
Test: {
    $searchObj currpage 0
    set L [$searchObj find "Aldo Buratti"]
     # check also if currpage advanced to the last page (the second page is 1)
    return [list $L [$searchObj currpage]]
}
Cleanup: { $searchObj destroy }
Expected: {{} 1}


Name: TextSearch.alternative.creation.
Description: {alternative creation of TextSearch and simple search}
Setup: { 
     # alternative creation
    set searchObj [$pdf newsearch] 
}
Test: {
     # start search frompage 1
    $searchObj currpage 1
    set L [$searchObj find "robo" -max 1]
     # simplify numbers for comparision
    simplifySearchResults $L
}
Cleanup: { $searchObj destroy }
Expected: {{1 {218 226 239 237}}}


# ============================================================================

#
# -- Common cleanup
#
    $pdf quit


 # FINAL TEST----------------------------------------------------------------
Name: memory-leaks
Description: { check if all created objects were properly destroyed }
Test: {
    mupdf::TextSearch names
}    
Expected: {}


# === cleanup ========================================
::tcltest::cleanupTests
