mirror of https://github.com/qpdf/qpdf.git
Move numrange code from qpdf.cc to QUtil.cc
Also move tests to libtests.
This commit is contained in:
parent
313ba08126
commit
fa3664357b
|
@ -26,6 +26,7 @@
|
||||||
#include <qpdf/Types.h>
|
#include <qpdf/Types.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <vector>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
@ -220,6 +221,11 @@ namespace QUtil
|
||||||
|
|
||||||
QPDF_DLL
|
QPDF_DLL
|
||||||
bool is_number(char const*);
|
bool is_number(char const*);
|
||||||
|
|
||||||
|
// This method parses the numeric range syntax used by the qpdf
|
||||||
|
// command-line tool. May throw std::runtime_error.
|
||||||
|
QPDF_DLL
|
||||||
|
std::vector<int> parse_numrange(char const* range, int max);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // QUTIL_HH
|
#endif // QUTIL_HH
|
||||||
|
|
174
libqpdf/QUtil.cc
174
libqpdf/QUtil.cc
|
@ -718,3 +718,177 @@ QUtil::strcasecmp(char const *s1, char const *s2)
|
||||||
return ::strcasecmp(s1, s2);
|
return ::strcasecmp(s1, s2);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int maybe_from_end(int num, bool from_end, int max)
|
||||||
|
{
|
||||||
|
if (from_end)
|
||||||
|
{
|
||||||
|
if (num > max)
|
||||||
|
{
|
||||||
|
num = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
num = max + 1 - num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int>
|
||||||
|
QUtil::parse_numrange(char const* range, int max)
|
||||||
|
{
|
||||||
|
std::vector<int> result;
|
||||||
|
char const* p = range;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::vector<int> work;
|
||||||
|
static int const comma = -1;
|
||||||
|
static int const dash = -2;
|
||||||
|
|
||||||
|
enum { st_top,
|
||||||
|
st_in_number,
|
||||||
|
st_after_number } state = st_top;
|
||||||
|
bool last_separator_was_dash = false;
|
||||||
|
int cur_number = 0;
|
||||||
|
bool from_end = false;
|
||||||
|
while (*p)
|
||||||
|
{
|
||||||
|
char ch = *p;
|
||||||
|
if (isdigit(ch))
|
||||||
|
{
|
||||||
|
if (! ((state == st_top) || (state == st_in_number)))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("digit not expected");
|
||||||
|
}
|
||||||
|
state = st_in_number;
|
||||||
|
cur_number *= 10;
|
||||||
|
cur_number += (ch - '0');
|
||||||
|
}
|
||||||
|
else if (ch == 'z')
|
||||||
|
{
|
||||||
|
// z represents max
|
||||||
|
if (! (state == st_top))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("z not expected");
|
||||||
|
}
|
||||||
|
state = st_after_number;
|
||||||
|
cur_number = max;
|
||||||
|
}
|
||||||
|
else if (ch == 'r')
|
||||||
|
{
|
||||||
|
if (! (state == st_top))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("r not expected");
|
||||||
|
}
|
||||||
|
state = st_in_number;
|
||||||
|
from_end = true;
|
||||||
|
}
|
||||||
|
else if ((ch == ',') || (ch == '-'))
|
||||||
|
{
|
||||||
|
if (! ((state == st_in_number) || (state == st_after_number)))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("unexpected separator");
|
||||||
|
}
|
||||||
|
cur_number = maybe_from_end(cur_number, from_end, max);
|
||||||
|
work.push_back(cur_number);
|
||||||
|
cur_number = 0;
|
||||||
|
from_end = false;
|
||||||
|
if (ch == ',')
|
||||||
|
{
|
||||||
|
state = st_top;
|
||||||
|
last_separator_was_dash = false;
|
||||||
|
work.push_back(comma);
|
||||||
|
}
|
||||||
|
else if (ch == '-')
|
||||||
|
{
|
||||||
|
if (last_separator_was_dash)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("unexpected dash");
|
||||||
|
}
|
||||||
|
state = st_top;
|
||||||
|
last_separator_was_dash = true;
|
||||||
|
work.push_back(dash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("unexpected character");
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
if ((state == st_in_number) || (state == st_after_number))
|
||||||
|
{
|
||||||
|
cur_number = maybe_from_end(cur_number, from_end, max);
|
||||||
|
work.push_back(cur_number);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("number expected");
|
||||||
|
}
|
||||||
|
|
||||||
|
p = 0;
|
||||||
|
for (size_t i = 0; i < work.size(); i += 2)
|
||||||
|
{
|
||||||
|
int num = work.at(i);
|
||||||
|
// max == 0 means we don't know the max and are just
|
||||||
|
// testing for valid syntax.
|
||||||
|
if ((max > 0) && ((num < 1) || (num > max)))
|
||||||
|
{
|
||||||
|
throw std::runtime_error(
|
||||||
|
"number " + QUtil::int_to_string(num) + " out of range");
|
||||||
|
}
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
result.push_back(work.at(i));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int separator = work.at(i-1);
|
||||||
|
if (separator == comma)
|
||||||
|
{
|
||||||
|
result.push_back(num);
|
||||||
|
}
|
||||||
|
else if (separator == dash)
|
||||||
|
{
|
||||||
|
int lastnum = result.back();
|
||||||
|
if (num > lastnum)
|
||||||
|
{
|
||||||
|
for (int j = lastnum + 1; j <= num; ++j)
|
||||||
|
{
|
||||||
|
result.push_back(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int j = lastnum - 1; j >= num; --j)
|
||||||
|
{
|
||||||
|
result.push_back(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::logic_error(
|
||||||
|
"INTERNAL ERROR parsing numeric range");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::runtime_error const& e)
|
||||||
|
{
|
||||||
|
std::string message;
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
message = "error at * in numeric range " +
|
||||||
|
std::string(range, p - range) + "*" + p + ": " + e.what();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
message = "error in numeric range " +
|
||||||
|
std::string(range) + ": " + e.what();
|
||||||
|
}
|
||||||
|
throw std::runtime_error(message);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ BINS_libtests = \
|
||||||
json \
|
json \
|
||||||
lzw \
|
lzw \
|
||||||
md5 \
|
md5 \
|
||||||
|
numrange \
|
||||||
pointer_holder \
|
pointer_holder \
|
||||||
predictors \
|
predictors \
|
||||||
qutil \
|
qutil \
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
#include <qpdf/QUtil.hh>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
static void test_numrange(char const* range)
|
||||||
|
{
|
||||||
|
if (range == 0)
|
||||||
|
{
|
||||||
|
std::cout << "null" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::vector<int> result = QUtil::parse_numrange(range, 15);
|
||||||
|
std::cout << "numeric range " << range << " ->";
|
||||||
|
for (std::vector<int>::iterator iter = result.begin();
|
||||||
|
iter != result.end(); ++iter)
|
||||||
|
{
|
||||||
|
std::cout << " " << *iter;
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
test_numrange(argv[1]);
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
std::cout << e.what() << std::endl;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
require 5.008;
|
||||||
|
use warnings;
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
require TestDriver;
|
||||||
|
|
||||||
|
my $td = new TestDriver('numrange');
|
||||||
|
|
||||||
|
my @nrange_tests = (
|
||||||
|
[",5",
|
||||||
|
"error at * in numeric range *,5: unexpected separator",
|
||||||
|
2],
|
||||||
|
["4,,5",
|
||||||
|
"error at * in numeric range 4,*,5: unexpected separator",
|
||||||
|
2],
|
||||||
|
["4,5,",
|
||||||
|
"error at * in numeric range 4,5,*: number expected",
|
||||||
|
2],
|
||||||
|
["z1,",
|
||||||
|
"error at * in numeric range z*1,: digit not expected",
|
||||||
|
2],
|
||||||
|
["1z,",
|
||||||
|
"error at * in numeric range 1*z,: z not expected",
|
||||||
|
2],
|
||||||
|
["1-5?",
|
||||||
|
"error at * in numeric range 1-5*?: unexpected character",
|
||||||
|
2],
|
||||||
|
["1-30",
|
||||||
|
"error in numeric range 1-30: number 30 out of range",
|
||||||
|
2],
|
||||||
|
["1-10,0,5",
|
||||||
|
"error in numeric range 1-10,0,5: number 0 out of range",
|
||||||
|
2],
|
||||||
|
["1-10,1234,5",
|
||||||
|
"error in numeric range 1-10,1234,5: number 1234 out of range",
|
||||||
|
2],
|
||||||
|
["1,r,3",
|
||||||
|
"error in numeric range 1,r,3: number 16 out of range",
|
||||||
|
2],
|
||||||
|
["1,r16,3",
|
||||||
|
"error in numeric range 1,r16,3: number 0 out of range",
|
||||||
|
2],
|
||||||
|
["1,3,5-10,z-13,13,9,z,2,r2-r4",
|
||||||
|
"numeric range 1,3,5-10,z-13,13,9,z,2,r2-r4" .
|
||||||
|
" -> 1 3 5 6 7 8 9 10 15 14 13 13 9 15 2 14 13 12",
|
||||||
|
0],
|
||||||
|
["r1-r15", # r\d+ at end
|
||||||
|
"numeric range r1-r15" .
|
||||||
|
" -> 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1",
|
||||||
|
0],
|
||||||
|
);
|
||||||
|
foreach my $d (@nrange_tests)
|
||||||
|
{
|
||||||
|
my ($range, $output, $status) = @$d;
|
||||||
|
$td->runtest("numeric range $range",
|
||||||
|
{$td->COMMAND => ['numrange', $range],
|
||||||
|
$td->FILTER => "grep 'numeric range'"},
|
||||||
|
{$td->STRING => $output . "\n", $td->EXIT_STATUS => $status},
|
||||||
|
$td->NORMALIZE_NEWLINES);
|
||||||
|
}
|
||||||
|
|
||||||
|
$td->report(scalar(@nrange_tests));
|
193
qpdf/qpdf.cc
193
qpdf/qpdf.cc
|
@ -635,180 +635,25 @@ static void show_encryption(QPDF& pdf, Options& o)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int maybe_from_end(int num, bool from_end, int max)
|
|
||||||
{
|
|
||||||
if (from_end)
|
|
||||||
{
|
|
||||||
if (num > max)
|
|
||||||
{
|
|
||||||
num = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
num = max + 1 - num;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::vector<int> parse_numrange(char const* range, int max,
|
static std::vector<int> parse_numrange(char const* range, int max,
|
||||||
bool throw_error = false)
|
bool throw_error = false)
|
||||||
{
|
{
|
||||||
std::vector<int> result;
|
|
||||||
char const* p = range;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
std::vector<int> work;
|
return QUtil::parse_numrange(range, max);
|
||||||
static int const comma = -1;
|
|
||||||
static int const dash = -2;
|
|
||||||
|
|
||||||
enum { st_top,
|
|
||||||
st_in_number,
|
|
||||||
st_after_number } state = st_top;
|
|
||||||
bool last_separator_was_dash = false;
|
|
||||||
int cur_number = 0;
|
|
||||||
bool from_end = false;
|
|
||||||
while (*p)
|
|
||||||
{
|
|
||||||
char ch = *p;
|
|
||||||
if (isdigit(ch))
|
|
||||||
{
|
|
||||||
if (! ((state == st_top) || (state == st_in_number)))
|
|
||||||
{
|
|
||||||
throw std::runtime_error("digit not expected");
|
|
||||||
}
|
|
||||||
state = st_in_number;
|
|
||||||
cur_number *= 10;
|
|
||||||
cur_number += (ch - '0');
|
|
||||||
}
|
|
||||||
else if (ch == 'z')
|
|
||||||
{
|
|
||||||
// z represents max
|
|
||||||
if (! (state == st_top))
|
|
||||||
{
|
|
||||||
throw std::runtime_error("z not expected");
|
|
||||||
}
|
|
||||||
state = st_after_number;
|
|
||||||
cur_number = max;
|
|
||||||
}
|
|
||||||
else if (ch == 'r')
|
|
||||||
{
|
|
||||||
if (! (state == st_top))
|
|
||||||
{
|
|
||||||
throw std::runtime_error("r not expected");
|
|
||||||
}
|
|
||||||
state = st_in_number;
|
|
||||||
from_end = true;
|
|
||||||
}
|
|
||||||
else if ((ch == ',') || (ch == '-'))
|
|
||||||
{
|
|
||||||
if (! ((state == st_in_number) || (state == st_after_number)))
|
|
||||||
{
|
|
||||||
throw std::runtime_error("unexpected separator");
|
|
||||||
}
|
|
||||||
cur_number = maybe_from_end(cur_number, from_end, max);
|
|
||||||
work.push_back(cur_number);
|
|
||||||
cur_number = 0;
|
|
||||||
from_end = false;
|
|
||||||
if (ch == ',')
|
|
||||||
{
|
|
||||||
state = st_top;
|
|
||||||
last_separator_was_dash = false;
|
|
||||||
work.push_back(comma);
|
|
||||||
}
|
|
||||||
else if (ch == '-')
|
|
||||||
{
|
|
||||||
if (last_separator_was_dash)
|
|
||||||
{
|
|
||||||
throw std::runtime_error("unexpected dash");
|
|
||||||
}
|
|
||||||
state = st_top;
|
|
||||||
last_separator_was_dash = true;
|
|
||||||
work.push_back(dash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw std::runtime_error("unexpected character");
|
|
||||||
}
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
if ((state == st_in_number) || (state == st_after_number))
|
|
||||||
{
|
|
||||||
cur_number = maybe_from_end(cur_number, from_end, max);
|
|
||||||
work.push_back(cur_number);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw std::runtime_error("number expected");
|
|
||||||
}
|
|
||||||
|
|
||||||
p = 0;
|
|
||||||
for (size_t i = 0; i < work.size(); i += 2)
|
|
||||||
{
|
|
||||||
int num = work.at(i);
|
|
||||||
// max == 0 means we don't know the max and are just
|
|
||||||
// testing for valid syntax.
|
|
||||||
if ((max > 0) && ((num < 1) || (num > max)))
|
|
||||||
{
|
|
||||||
throw std::runtime_error(
|
|
||||||
"number " + QUtil::int_to_string(num) + " out of range");
|
|
||||||
}
|
|
||||||
if (i == 0)
|
|
||||||
{
|
|
||||||
result.push_back(work.at(i));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int separator = work.at(i-1);
|
|
||||||
if (separator == comma)
|
|
||||||
{
|
|
||||||
result.push_back(num);
|
|
||||||
}
|
|
||||||
else if (separator == dash)
|
|
||||||
{
|
|
||||||
int lastnum = result.back();
|
|
||||||
if (num > lastnum)
|
|
||||||
{
|
|
||||||
for (int j = lastnum + 1; j <= num; ++j)
|
|
||||||
{
|
|
||||||
result.push_back(j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int j = lastnum - 1; j >= num; --j)
|
|
||||||
{
|
|
||||||
result.push_back(j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw std::logic_error(
|
|
||||||
"INTERNAL ERROR parsing numeric range");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (std::runtime_error const& e)
|
catch (std::runtime_error& e)
|
||||||
{
|
{
|
||||||
if (throw_error)
|
if (throw_error)
|
||||||
{
|
{
|
||||||
throw e;
|
throw(e);
|
||||||
}
|
|
||||||
if (p)
|
|
||||||
{
|
|
||||||
usage("error at * in numeric range " +
|
|
||||||
std::string(range, p - range) + "*" + p + ": " + e.what());
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
usage("error in numeric range " +
|
usage(e.what());
|
||||||
std::string(range) + ": " + e.what());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return std::vector<int>();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1213,25 +1058,6 @@ parse_pages_options(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_numrange(char const* range)
|
|
||||||
{
|
|
||||||
if (range == 0)
|
|
||||||
{
|
|
||||||
std::cout << "null" << std::endl;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::vector<int> result = parse_numrange(range, 15);
|
|
||||||
std::cout << "numeric range " << range << " ->";
|
|
||||||
for (std::vector<int>::iterator iter = result.begin();
|
|
||||||
iter != result.end(); ++iter)
|
|
||||||
{
|
|
||||||
std::cout << " " << *iter;
|
|
||||||
}
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QPDFPageData::QPDFPageData(std::string const& filename,
|
QPDFPageData::QPDFPageData(std::string const& filename,
|
||||||
QPDF* qpdf,
|
QPDF* qpdf,
|
||||||
char const* range) :
|
char const* range) :
|
||||||
|
@ -1429,14 +1255,7 @@ static void parse_options(int argc, char* argv[], Options& o)
|
||||||
*parameter++ = 0;
|
*parameter++ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arguments that start with space are undocumented and
|
if (strcmp(arg, "password") == 0)
|
||||||
// are for use by the test suite.
|
|
||||||
if (strcmp(arg, " test-numrange") == 0)
|
|
||||||
{
|
|
||||||
test_numrange(parameter);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
else if (strcmp(arg, "password") == 0)
|
|
||||||
{
|
{
|
||||||
if (parameter == 0)
|
if (parameter == 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1319,63 +1319,6 @@ $td->runtest("check output",
|
||||||
{$td->FILE => "a.pdf"},
|
{$td->FILE => "a.pdf"},
|
||||||
{$td->FILE => "minimal-rotated.pdf"});
|
{$td->FILE => "minimal-rotated.pdf"});
|
||||||
|
|
||||||
show_ntests();
|
|
||||||
# ----------
|
|
||||||
$td->notify("--- Numeric range parsing tests ---");
|
|
||||||
my @nrange_tests = (
|
|
||||||
[",5",
|
|
||||||
"qpdf: error at * in numeric range *,5: unexpected separator",
|
|
||||||
2],
|
|
||||||
["4,,5",
|
|
||||||
"qpdf: error at * in numeric range 4,*,5: unexpected separator",
|
|
||||||
2],
|
|
||||||
["4,5,",
|
|
||||||
"qpdf: error at * in numeric range 4,5,*: number expected",
|
|
||||||
2],
|
|
||||||
["z1,",
|
|
||||||
"qpdf: error at * in numeric range z*1,: digit not expected",
|
|
||||||
2],
|
|
||||||
["1z,",
|
|
||||||
"qpdf: error at * in numeric range 1*z,: z not expected",
|
|
||||||
2],
|
|
||||||
["1-5?",
|
|
||||||
"qpdf: error at * in numeric range 1-5*?: unexpected character",
|
|
||||||
2],
|
|
||||||
["1-30",
|
|
||||||
"qpdf: error in numeric range 1-30: number 30 out of range",
|
|
||||||
2],
|
|
||||||
["1-10,0,5",
|
|
||||||
"qpdf: error in numeric range 1-10,0,5: number 0 out of range",
|
|
||||||
2],
|
|
||||||
["1-10,1234,5",
|
|
||||||
"qpdf: error in numeric range 1-10,1234,5: number 1234 out of range",
|
|
||||||
2],
|
|
||||||
["1,r,3",
|
|
||||||
"qpdf: error in numeric range 1,r,3: number 16 out of range",
|
|
||||||
2],
|
|
||||||
["1,r16,3",
|
|
||||||
"qpdf: error in numeric range 1,r16,3: number 0 out of range",
|
|
||||||
2],
|
|
||||||
["1,3,5-10,z-13,13,9,z,2,r2-r4",
|
|
||||||
"numeric range 1,3,5-10,z-13,13,9,z,2,r2-r4" .
|
|
||||||
" -> 1 3 5 6 7 8 9 10 15 14 13 13 9 15 2 14 13 12",
|
|
||||||
0],
|
|
||||||
["r1-r15", # r\d+ at end
|
|
||||||
"numeric range r1-r15" .
|
|
||||||
" -> 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1",
|
|
||||||
0],
|
|
||||||
);
|
|
||||||
$n_tests += scalar(@nrange_tests);
|
|
||||||
foreach my $d (@nrange_tests)
|
|
||||||
{
|
|
||||||
my ($range, $output, $status) = @$d;
|
|
||||||
$td->runtest("numeric range $range",
|
|
||||||
{$td->COMMAND => ['qpdf', '-- test-numrange=' . $range],
|
|
||||||
$td->FILTER => "grep 'numeric range'"},
|
|
||||||
{$td->STRING => $output . "\n", $td->EXIT_STATUS => $status},
|
|
||||||
$td->NORMALIZE_NEWLINES);
|
|
||||||
}
|
|
||||||
|
|
||||||
show_ntests();
|
show_ntests();
|
||||||
# ----------
|
# ----------
|
||||||
$td->notify("--- Merging and Splitting ---");
|
$td->notify("--- Merging and Splitting ---");
|
||||||
|
|
Loading…
Reference in New Issue