summaryrefslogtreecommitdiff
path: root/testsuite/lib/pdfgrep.exp
blob: b967fd9149d084715f425c71b3e2e455bb9c36e4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
# This file contains functions that can be used by all test scripts in
# pdfgrep.tests.
#
# It is only loaded once for all tests.

########################################
### Running pdfgrep ####################
########################################

# Don't remove null bytes by default. pdfgrep should not have them in the output
# unless explicitly told so. And then we want to be able to test for them.
remove_nulls -d 0

set pdfgrep_path [file normalize ../src/pdfgrep]

# Just spawns pdfgrep with the given arguments
proc pdfgrep args {
    global spawn_id pdfgrep_path
    spawn $pdfgrep_path {*}$args
}


# Spawns pdfgrep and fail if pdfgrep prints something on stderr.
proc pdfgrep_noerr args {
    global spawn_id test
    pdfgrep {*}$args
    expect_before {
	-re "^pdfgrep:" {pfail "$test -- error from pdfgrep"; expect eof}
    }
}

# The version of poppler that this pdfgrep is built against.
# Format [Major Minor Patchlevel]
#
# You can disable all poppler version checks (for example, if you have a patched
# poppler installed) by setting the variable $disable_poppler_version_check to
# true.
set poppler_version {0 0 0}

# Is pdfgrep compiled with pcre support?
set have_pcre false

# Is pdfgrep compiled with libunac support?
set have_unac false

# Parse the output of pdfgrep --version, to get the configuration parameters.
log_user 0
pdfgrep --version
while {1} {
    expect {
        -re "Using poppler version (\[^\r\]+)\r\n" {
	    set poppler_version [split $expect_out(1,string) "."]
	}
        -re "Using libunac version \[^\r\]*\r\n" {
            set have_unac true
        }
        -re "Using libpcre version \[^\r\]*\r\n" {
            set have_pcre true
        }
        eof break
    }
}
log_user 1

# This can be set in test scripts to generate UNSUPPORTED test results, if the
# actual poppler version is less than the required one.
set required_poppler_version {0 0 0}

# This can be set in test scripts to generate UNSUPPORTED test results, if
# pdfgrep is not build with libpcre support.
set requires_pcre_support false

# This can be set in test scripts to generate UNSUPPORTED test results, if
# pdfgrep is not build with libunac support.
set requires_unac_support false

# Syntax: pdfgrep_expect args pattern
#
# Spawns pdfgrep with args, fail on stderr and compares the output with pattern.
#
# pattern is a regular expression that _completely_ matches the output. I.e it
# pdfgrep_expect encloses it int ^$.
proc pdfgrep_expect args {
    pdfgrep_expect_internal 0 0 {*}$args
}

# Same as above, but expect the test to fail
proc pdfgrep_expect_x args {
    pdfgrep_expect_internal 1 0 {*}$args
}

# Same as pdfgrep_expect, but don't immediately fail if pdfgrep prints to
# stderr.
proc pdfgrep_expect_with_err args {
    pdfgrep_expect_internal 0 1 {*}$args
}

# Same as before, but expect the test to fail
proc pdfgrep_expect_with_err_x args {
    pdfgrep_expect_internal 1 1 {*}$args
}

proc pdfgrep_expect_internal {expected_failure allow_errors args} {
    global spawn_id test required_poppler_version

    set output [lindex $args end]
    set args [lreplace $args end end]

    # expect configures the terminal to use \r\n for newlines, but since we
    # don't want to sprinkle our source code with \r, we convert newlines.
    set output [string map {\n \r\n} $output]

    # --color=never is necessary because we dont want to have escape sequences
    # in the output.
    if {$allow_errors} {
	pdfgrep --color=never {*}$args
    } else {
	pdfgrep_noerr --color=never {*}$args
    }
    expect {
	# The final newline is only optionally matched, because some client code
	# may include it
	-re "^[set output](\r\n)?\$" {
	    expect eof {
		if {$expected_failure} {
		    pxpass $test
		} else {
		    ppass $test
		}
	    }
	}
	default {
	    if {$expected_failure} {
		pxfail $test
	    } else {
		pfail $test
	    }
	}
    }

    # reset, so the next test must set it again
    reset_configuration
}


# Expect pdfgrep to print an error message
proc pdfgrep_expect_error args {
    global test required_poppler_version

    pdfgrep {*}$args
    expect {
	-re "pdfgrep: " { ppass $test; expect eof }
	default { pfail $test }
    }

    # reset, so the next test must set it again
    reset_configuration
}

# Compare the exit status of the last spawned program to $expected
proc expect_exit_status {expected} {
    global test required_poppler_version

    set wait_status [wait]

    if {[lindex $wait_status 3] != $expected} {
	send_log "Exit status is [lindex $wait_status 3], but expected $expected\n"
	pfail "$test \[exit status\]"
    } else {
	ppass "$test \[exit status\]"
    }

    # reset, so the next test must set it again
    reset_configuration
}

# Test if the required version is greater than the detected poppler version
#
# @return A boolean depending on the poppler version
proc poppler_greater {} {
    global poppler_version required_poppler_version disable_poppler_version_check
    lassign $required_poppler_version rmaj rmin rpatch
    lassign $poppler_version maj min patch


    # Always return true if the check is disabled
    if {[info exists disable_poppler_version_check]
	&& $disable_poppler_version_check} {

	return true
    }

    if {$maj > $rmaj} { return true }
    if {$maj == $rmaj && $min > $rmin } {return true}
    if {$maj == $rmaj && $min == $rmin && $patch >= $rpatch} {return true}
    return false
}

# The following four procedures are like pass, fail, xpass and xfail but call
# unsupported, if the poppler version is not the requested one.
proc ppass arg {
    when_supported pass $arg
}
proc pfail arg {
    when_supported fail $arg
}
proc pxpass arg {
    when_supported xpass $arg
}
proc pxfail arg {
    when_supported xfail $arg
}

proc when_supported {action arg} {
    global poppler_version required_poppler_version
    global requires_pcre_support have_pcre
    global requires_unac_support have_unac
    if {[poppler_greater] && \
	    (!$requires_pcre_support || $have_pcre) && \
	    (!$requires_unac_support || $have_unac)} {
	$action $arg
    } else {
	unsupported "$arg -- required configuration was not found"
    }
}

proc reset_configuration {} {
    global required_poppler_version requires_pcre_support requires_unac_support
    set required_poppler_version {0 0 0}
    set requires_pcre_support false
    set requires_unac_support false
}

########################################
### PDF generation ####################
########################################

# The following code supports on the fly generation of PDFs. This way,
# individual tests can use highly customized PDFs and we don't have to check
# those into version control.


# The directory where the PDFs will be generated.
# NOTE This will frequently be # removed, so don't put important data there
# TODO On Linux, the -t option for mktemp is marked as deprecated and the
# --tmpdir option should be used. Unfortunately, this option is not available on
# the BSDs.
set pdfdir [exec mktemp -t -d pdfgrep_tests.XXXXXXXXXX]


# Delete $pdfdir recursively and create it anew
proc clear_pdfdir {} {
    global pdfdir
    file delete -force -- $pdfdir
    file mkdir $pdfdir
}

# The latex template
set latex_pre {\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[parfill]{parskip}
\pagestyle{empty}
\begin{document}}
set latex_post {\end{document}}


# Create a pdf called $name.pdf in $pdfdir containing $content.
#
# THis is done by first creating a .tex file with $content between
# \begin{document} and \end{document} and then calling pdflatex on it.
#
# Returns the name of the newly created PDF file
proc mkpdf {name content} {
    global pdfdir latex_pre latex_post
    set fp [open "$pdfdir/$name.tex" w]
    puts $fp $latex_pre
    puts $fp $content
    puts $fp $latex_post
    close $fp

    set saved_dir [pwd]
    cd $pdfdir
    if {[catch {exec pdflatex -interaction=batchmode "$name.tex"}]} {
	unsupported "could not execute pdflatex"
	cd $saved_dir
	error "pdflatex"
    }
    cd $saved_dir

    return "$pdfdir/$name.pdf"
}


########################################
### Infrastructure #####################
########################################

# The following functions are called by dejagnu

proc pdfgrep_version {} {
    global pdfgrep_path
    puts ""
    note [exec $pdfgrep_path --version]
    puts ""
}