diff options
-rw-r--r-- | DEPS | 2 | ||||
-rw-r--r-- | core/fxcrt/fx_extension.cpp | 14 | ||||
-rw-r--r-- | core/fxcrt/fx_extension.h | 3 | ||||
-rw-r--r-- | fpdfsdk/fpdf_ext.cpp | 5 | ||||
-rw-r--r-- | fpdfsdk/fpdf_view_c_api_test.c | 1 | ||||
-rw-r--r-- | fxjs/cfxjse_formcalc_context.cpp | 4 | ||||
-rw-r--r-- | public/fpdf_ext.h | 10 | ||||
-rw-r--r-- | samples/pdfium_test.cc | 20 | ||||
-rw-r--r-- | testing/SUPPRESSIONS | 1 | ||||
-rwxr-xr-x | testing/tools/api_check.py | 2 | ||||
-rwxr-xr-x | testing/tools/make_expected.sh | 9 | ||||
-rw-r--r-- | testing/tools/test_runner.py | 11 |
12 files changed, 73 insertions, 9 deletions
@@ -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(¤tTime); + FXSYS_time(¤tTime); struct tm* pTmStruct = gmtime(¤tTime); 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') |