summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--DEPS2
-rw-r--r--core/fxcrt/fx_extension.cpp14
-rw-r--r--core/fxcrt/fx_extension.h3
-rw-r--r--fpdfsdk/fpdf_ext.cpp5
-rw-r--r--fpdfsdk/fpdf_view_c_api_test.c1
-rw-r--r--fxjs/cfxjse_formcalc_context.cpp4
-rw-r--r--public/fpdf_ext.h10
-rw-r--r--samples/pdfium_test.cc20
-rw-r--r--testing/SUPPRESSIONS1
-rwxr-xr-xtesting/tools/api_check.py2
-rwxr-xr-xtesting/tools/make_expected.sh9
-rw-r--r--testing/tools/test_runner.py11
12 files changed, 73 insertions, 9 deletions
diff --git a/DEPS b/DEPS
index f211f446d5..de06b3ae98 100644
--- a/DEPS
+++ b/DEPS
@@ -29,7 +29,7 @@ vars = {
'jinja2_revision': '45571de473282bd1d8b63a8dfcb1fd268d0635d2',
'jpeg_turbo_revision': '7260e4d8b8e1e40b17f03fafdf1cd83296900f76',
'markupsafe_revision': '8f45f5cfa0009d2a70589bcda0349b8cb2b72783',
- 'pdfium_tests_revision': '96223aa3d32dcb606f4f33c5647abfd4e413f220',
+ 'pdfium_tests_revision': '62a57ad4d90cf1f68f41c24da7ea413750336235',
'skia_revision': '588f879677d4f36e16a42dd96876534f104c2e2f',
'tools_memory_revision': 'f7b00daf4df7f6c469f5fbc68d7f40f6bd15d6e6',
'trace_event_revision': '211b3ed9d0481b4caddbee1322321b86a483ca1f',
diff --git a/core/fxcrt/fx_extension.cpp b/core/fxcrt/fx_extension.cpp
index c754a85508..8320b45db4 100644
--- a/core/fxcrt/fx_extension.cpp
+++ b/core/fxcrt/fx_extension.cpp
@@ -11,6 +11,9 @@
#include <limits>
#include "third_party/base/compiler_specific.h"
+#include "third_party/base/ptr_util.h"
+
+time_t (*time_func)() = []() -> time_t { return time(nullptr); };
float FXSYS_wcstof(const wchar_t* pwsStr, int32_t iLength, int32_t* pUsedLen) {
ASSERT(pwsStr);
@@ -167,3 +170,14 @@ size_t FXSYS_ToUTF16BE(uint32_t unicode, char* buf) {
FXSYS_IntToFourHexChars(0xDC00 + unicode % 0x400, buf + 4);
return 8;
}
+
+void FXSYS_SetTimeFunction(time_t (*func)()) {
+ time_func = func ? func : []() -> time_t { return time(nullptr); };
+}
+
+time_t FXSYS_time(time_t* tloc) {
+ time_t ret_val = time_func();
+ if (tloc)
+ *tloc = ret_val;
+ return ret_val;
+}
diff --git a/core/fxcrt/fx_extension.h b/core/fxcrt/fx_extension.h
index dcdd64e1fc..6a49ee1116 100644
--- a/core/fxcrt/fx_extension.h
+++ b/core/fxcrt/fx_extension.h
@@ -109,4 +109,7 @@ bool FXSYS_SafeLT(const T& lhs, const T& rhs) {
return lhs < rhs;
}
+void FXSYS_SetTimeFunction(time_t (*func)());
+time_t FXSYS_time(time_t* tloc);
+
#endif // CORE_FXCRT_FX_EXTENSION_H_
diff --git a/fpdfsdk/fpdf_ext.cpp b/fpdfsdk/fpdf_ext.cpp
index 6a2ab061fd..23c3d468c1 100644
--- a/fpdfsdk/fpdf_ext.cpp
+++ b/fpdfsdk/fpdf_ext.cpp
@@ -10,6 +10,7 @@
#include "core/fpdfapi/parser/cpdf_document.h"
#include "core/fpdfdoc/cpdf_interform.h"
#include "core/fpdfdoc/cpdf_metadata.h"
+#include "core/fxcrt/fx_extension.h"
#include "fpdfsdk/cpdfsdk_helpers.h"
#ifdef PDF_ENABLE_XFA
@@ -76,6 +77,10 @@ FSDK_SetUnSpObjProcessHandler(UNSUPPORT_INFO* unsp_info) {
return true;
}
+FPDF_EXPORT void FPDF_CALLCONV FSDK_SetTimeFunction(time_t (*func)()) {
+ FXSYS_SetTimeFunction(func);
+}
+
FPDF_EXPORT int FPDF_CALLCONV FPDFDoc_GetPageMode(FPDF_DOCUMENT document) {
CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
if (!pDoc)
diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c
index 56e9d7abed..7dbe164932 100644
--- a/fpdfsdk/fpdf_view_c_api_test.c
+++ b/fpdfsdk/fpdf_view_c_api_test.c
@@ -217,6 +217,7 @@ int CheckPDFiumCApi() {
// fpdf_ext.h
CHK(FPDFDoc_GetPageMode);
+ CHK(FSDK_SetTimeFunction);
CHK(FSDK_SetUnSpObjProcessHandler);
// fpdf_flatten.h
diff --git a/fxjs/cfxjse_formcalc_context.cpp b/fxjs/cfxjse_formcalc_context.cpp
index 9973df69aa..d164c626b9 100644
--- a/fxjs/cfxjse_formcalc_context.cpp
+++ b/fxjs/cfxjse_formcalc_context.cpp
@@ -6,8 +6,6 @@
#include "fxjs/cfxjse_formcalc_context.h"
-#include <time.h>
-
#include <algorithm>
#include <string>
#include <utility>
@@ -2061,7 +2059,7 @@ void CFXJSE_FormCalcContext::Date(CFXJSE_Value* pThis,
}
time_t currentTime;
- time(&currentTime);
+ FXSYS_time(&currentTime);
struct tm* pTmStruct = gmtime(&currentTime);
args.GetReturnValue()->SetInteger(DateString2Num(
diff --git a/public/fpdf_ext.h b/public/fpdf_ext.h
index e488c5283b..a531f1407e 100644
--- a/public/fpdf_ext.h
+++ b/public/fpdf_ext.h
@@ -7,6 +7,8 @@
#ifndef PUBLIC_FPDF_EXT_H_
#define PUBLIC_FPDF_EXT_H_
+#include <time.h>
+
// NOLINTNEXTLINE(build/include)
#include "fpdfview.h"
@@ -67,6 +69,14 @@ typedef struct _UNSUPPORT_INFO {
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FSDK_SetUnSpObjProcessHandler(UNSUPPORT_INFO* unsp_info);
+// Sets generator function for calls to time.
+//
+// This API is intended to be used only for testing, thus may cause PDFium to
+// behave poorly in production environments.
+//
+// func - Function pointer to alternate implementation of time.
+FPDF_EXPORT void FPDF_CALLCONV FSDK_SetTimeFunction(time_t (*func)());
+
// Unknown page mode.
#define PAGEMODE_UNKNOWN -1
// Document outline, and thumbnails hidden.
diff --git a/samples/pdfium_test.cc b/samples/pdfium_test.cc
index 14a62a4bc4..b7538a8c6f 100644
--- a/samples/pdfium_test.cc
+++ b/samples/pdfium_test.cc
@@ -115,6 +115,7 @@ struct Options {
std::string font_directory;
int first_page = 0; // First 0-based page number to renderer.
int last_page = 0; // Last 0-based page number to renderer.
+ time_t time = -1;
};
Optional<std::string> ExpandDirectoryPath(const std::string& path) {
@@ -424,6 +425,17 @@ bool ParseCommandLine(const std::vector<std::string>& args,
}
} else if (cur_arg == "--md5") {
options->md5 = true;
+ } else if (cur_arg.size() > 7 && cur_arg.compare(0, 7, "--time=") == 0) {
+ if (options->time > -1) {
+ fprintf(stderr, "Duplicate --time argument\n");
+ return false;
+ }
+ const std::string time_string = cur_arg.substr(7);
+ std::stringstream(time_string) >> options->time;
+ if (options->time < 0) {
+ fprintf(stderr, "Invalid --time argument, must be non-negative\n");
+ return false;
+ }
} else if (cur_arg.size() >= 2 && cur_arg[0] == '-' && cur_arg[1] == '-') {
fprintf(stderr, "Unrecognized argument %s\n", cur_arg.c_str());
return false;
@@ -834,6 +846,7 @@ constexpr char kUsageString[] =
" --skp - write page images <pdf-name>.<page-number>.skp\n"
#endif
" --md5 - write output image paths and their md5 hashes to stdout.\n"
+ " --time=<number> - Seconds since the epoch to set system time.\n"
"";
} // namespace
@@ -889,6 +902,13 @@ int main(int argc, const char* argv[]) {
FSDK_SetUnSpObjProcessHandler(&unsupported_info);
+ if (options.time > -1) {
+ // This must be a static var to avoid explicit capture, so the lambda can be
+ // converted to a function ptr.
+ static time_t time_ret = options.time;
+ FSDK_SetTimeFunction([]() -> time_t { return time_ret; });
+ }
+
for (const std::string& filename : files) {
size_t file_length = 0;
std::unique_ptr<char, pdfium::FreeDeleter> file_contents =
diff --git a/testing/SUPPRESSIONS b/testing/SUPPRESSIONS
index ed2973c2ee..f3d5867dda 100644
--- a/testing/SUPPRESSIONS
+++ b/testing/SUPPRESSIONS
@@ -299,7 +299,6 @@ FRC_8.5_PO_GoToE_T_R&N.pdf * * *
Choose.pdf * * *
data_binding.pdf * * *
-Date_FormCale.pdf * * *
# TODO(npm): Add proper evt for MouseEvents.
MouseEvents_enter.pdf * * *
MouseEvents_exit.pdf * * *
diff --git a/testing/tools/api_check.py b/testing/tools/api_check.py
index 2c5cc4fa3e..934577b21b 100755
--- a/testing/tools/api_check.py
+++ b/testing/tools/api_check.py
@@ -22,6 +22,8 @@ def _IsValidFunctionName(function, filename):
return True
if function == 'FSDK_SetUnSpObjProcessHandler' and filename == 'fpdf_ext.h':
return True
+ if function == 'FSDK_SetTimeFunction' and filename == 'fpdf_ext.h':
+ return True
if function.startswith('FORM_') and filename == 'fpdf_formfill.h':
return True
return False
diff --git a/testing/tools/make_expected.sh b/testing/tools/make_expected.sh
index a70df797c2..9b7e3d8716 100755
--- a/testing/tools/make_expected.sh
+++ b/testing/tools/make_expected.sh
@@ -6,6 +6,11 @@
#
# Script to generate expected result files.
+# Arbitrary timestamp, expressed in seconds since the epoch, used to make sure
+# that tests that depend on the current time are stable. Happens to be the
+# timestamp of the first commit to repo, 2014/5/9 17:48:50.
+TEST_SEED_TIME=1399672130
+
# Do this before "set -e" so "which" failing is not fatal.
PNGOPTIMIZER="$(which optipng)"
@@ -15,9 +20,9 @@ while (( "$#" )); do
echo $INFILE | grep -qs ' ' && echo space in filename detected && exit 1
EVTFILE="${INFILE%.*}.evt"
if [ -f "$EVTFILE" ]; then
- out/Debug/pdfium_test --send-events --png $INFILE
+ out/Debug/pdfium_test --send-events --time=$TEST_SEED_TIME --png $INFILE
else
- out/Debug/pdfium_test --png $INFILE
+ out/Debug/pdfium_test --time=$TEST_SEED_TIME --png $INFILE
fi
RESULTS="$INFILE.*.png"
for RESULT in $RESULTS ; do
diff --git a/testing/tools/test_runner.py b/testing/tools/test_runner.py
index ecd87ad082..43dc578a90 100644
--- a/testing/tools/test_runner.py
+++ b/testing/tools/test_runner.py
@@ -17,6 +17,11 @@ import gold
import pngdiffer
import suppressor
+# Arbitrary timestamp, expressed in seconds since the epoch, used to make sure
+# that tests that depend on the current time are stable. Happens to be the
+# timestamp of the first commit to repo, 2014/5/9 17:48:50.
+TEST_SEED_TIME = "1399672130"
+
class KeyboardInterruptError(Exception): pass
# Nomenclature:
@@ -132,14 +137,16 @@ class TestRunner:
txt_path = os.path.join(self.working_dir, input_root + '.txt')
with open(txt_path, 'w') as outfile:
- cmd_to_run = [self.pdfium_test_path, '--send-events', pdf_path]
+ cmd_to_run = [self.pdfium_test_path, '--send-events',
+ '--time=' + TEST_SEED_TIME, pdf_path]
subprocess.check_call(cmd_to_run, stdout=outfile)
cmd = [sys.executable, self.text_diff_path, expected_txt_path, txt_path]
return common.RunCommand(cmd)
def TestPixel(self, input_root, pdf_path, use_ahem):
- cmd_to_run = [self.pdfium_test_path, '--send-events', '--png', '--md5']
+ cmd_to_run = [self.pdfium_test_path, '--send-events', '--png', '--md5',
+ '--time=' + TEST_SEED_TIME]
if self.oneshot_renderer:
cmd_to_run.append('--render-oneshot')