Skip to content

Commit

Permalink
Fix timecop_date_create_from_format() for supportting time
Browse files Browse the repository at this point in the history
travelling / Refactoring / Add tests
  • Loading branch information
hnw committed Jan 8, 2017
1 parent f5bcffb commit 34ab027
Show file tree
Hide file tree
Showing 33 changed files with 1,507 additions and 872 deletions.
25 changes: 16 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ extension=timecop.so

## SYSTEM REQUIREMENTS

- OS: Linux, FreeBSD, MacOSX
- PHP: 5.3.x, 5.4.x, 5.5.x, 5.6.x, 7.0.x, 7.1.x
- OS: Linux, macOS
- PHP: 5.3.1 - 7.1.x (might work on 5.2.x and 5.3.0, but not tested enough)
- SAPI: Apache, CLI
- Other SAPIs are not tested, but there is no SAPI-dependent code.
- non-ZTS(recommended), ZTS
Expand All @@ -50,9 +50,13 @@ extension=timecop.so
- `gettimeofday()`
- `unixtojd()`
- `DateTime::_construct()`
- `DateTime::createFromFormat()` (PHP >= 5.3.4)
- `DateTime::createFromFormat()` (PHP >= 5.3.0)
- `DateTimeImmutable::_construct()` (PHP >= 5.5.0)
- `DateTimeImmutable::createFromFormat()` (PHP >= 5.5.0)
- `date_create()`
- `date_create_from_format()` (PHP >= 5.3.4)
- `date_create_from_format()` (PHP >= 5.3.0)
- `date_create_immutable()` (PHP >= 5.5.0)
- `date_create_immutable_from_format()` (PHP >= 5.5.0)
- Rewrite value of the following global variables when the time has been moved.
- `$_SERVER['REQUEST_TIME']`

Expand Down Expand Up @@ -98,12 +102,15 @@ var_dump((new DateTime())->format("c")); // string(25) "2017-01-01T00:00:05+00:0

## CHANGELOG

### version 1.2.2(alpha), 2017/1/4
- Implement Implement `TimecopDateTimeImmutable` class and `timecop_date_create_immutable()`, `timecop_date_create_immutable_from_format()` functions.
- Now `timecop_date_create_from_format()` returns DateTime instance
### version 1.2.3(beta), 2017/1/8
- Fix `timecop_date_create_from_format()`: support time travelling
- Now portions of the generated time not provided in `format` will be set to the travelled time
- The previous version is completely same behavior as `date_create_from_format()`.
- Remove `TimecopDateTime::getTimestamp()`, `TimecopDateTime::setTimestamp()` on PHP 5.2.x

### version 1.2.1(alpha), 2016/12/30
- Fix the year 2038 problem for PHP 7.x on 64bit Windows.
### version 1.2.2(alpha), 2017/1/4
- Implement `TimecopDateTimeImmutable` class and `timecop_date_create_immutable()`, `timecop_date_create_immutable_from_format()` functions.
- Now `timecop_date_create_from_format()` returns `DateTime` instance

### version 1.2.0(alpha), 2016/12/30
- Big internal change (without BC break): handle microseconds accurately in time traveling.
Expand Down
3 changes: 2 additions & 1 deletion circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ dependencies:

test:
override:
- make test REPORT_EXIT_STATUS=1 NO_INTERACTION=1 TESTS="--show-all" | tee tests-output.txt && if grep -q 'TEST SUMMARY$' tests-output.txt ; then exit 1 ; fi
- make test REPORT_EXIT_STATUS=1 NO_INTERACTION=1 TESTS="--show-all" | tee tests-output.txt && if grep -q 'TEST SUMMARY$' tests-output.txt ; then exit 1 ; fi:
parallel: true
2 changes: 1 addition & 1 deletion php-timecop.spec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
%define __ext_name timecop
Name: php-%{__ext_name}
Version: 1.2.1
Version: 1.2.3
Release: 1%{?dist}
Summary: php-timecop module

Expand Down
42 changes: 27 additions & 15 deletions php_timecop.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
#ifndef PHP_TIMECOP_H
#define PHP_TIMECOP_H

#define PHP_TIMECOP_VERSION "1.2.2"
#define PHP_TIMECOP_VERSION "1.2.3"

extern zend_module_entry timecop_module_entry;
#define phpext_timecop_ptr &timecop_module_entry
Expand Down Expand Up @@ -68,6 +68,10 @@ PHP_FUNCTION(timecop_date_create_from_format);
PHP_FUNCTION(timecop_date_create_immutable);
PHP_FUNCTION(timecop_date_create_immutable_from_format);
#endif
#if !defined(PHP_VERSION_ID) || PHP_VERSION_ID < 50300
PHP_FUNCTION(date_timestamp_set);
PHP_FUNCTION(date_timestamp_get);
#endif

PHP_METHOD(TimecopDateTime, __construct);
PHP_METHOD(TimecopOrigDateTime, __construct);
Expand All @@ -80,11 +84,6 @@ PHP_METHOD(TimecopOrigDateTimeImmutable, __construct);
PHP_METHOD(Timecop, freeze);
PHP_METHOD(Timecop, travel);

#if !defined(PHP_VERSION_ID) || PHP_VERSION_ID < 50300
PHP_METHOD(TimecopDateTime, getTimestamp);
PHP_METHOD(TimecopDateTime, setTimestamp);
#endif

typedef enum timecop_mode_t {
TIMECOP_MODE_REALTIME,
TIMECOP_MODE_FREEZE,
Expand All @@ -104,6 +103,7 @@ ZEND_BEGIN_MODULE_GLOBALS(timecop)
tc_timeval travel_origin;
tc_timeval travel_offset;
tc_timeval_long scaling_factor;
zend_class_entry *ce_DateTimeZone;
zend_class_entry *ce_DateTimeInterface;
zend_class_entry *ce_DateTime;
zend_class_entry *ce_TimecopDateTime;
Expand All @@ -125,9 +125,6 @@ ZEND_END_MODULE_GLOBALS(timecop)
#define ORIG_FUNC_NAME(fname) \
(TIMECOP_G(func_override) ? (SAVE_FUNC_PREFIX fname) : fname)

#define ORIG_FUNC_NAME_SIZEOF(fname) \
(TIMECOP_G(func_override) ? sizeof(SAVE_FUNC_PREFIX fname) : sizeof(fname))

#define TIMECOP_OFE(fname) {fname, OVRD_FUNC_PREFIX fname, SAVE_FUNC_PREFIX fname}
#define TIMECOP_OCE(cname, mname) \
{cname, mname, OVRD_CLASS_PREFIX cname, SAVE_FUNC_PREFIX mname}
Expand All @@ -145,14 +142,29 @@ struct timecop_override_class_entry {
char *save_method;
};

#define timecop_call_orig_method_with_0_params(obj, obj_ce, fn_proxy, function_name, retval) \
zend_call_method(obj, obj_ce, fn_proxy, ORIG_FUNC_NAME(function_name), ORIG_FUNC_NAME_SIZEOF(function_name)-1, retval, 0, NULL, NULL TSRMLS_CC)
#define call_php_method_with_0_params(obj, ce, method_name, retval) \
_call_php_method_with_0_params(obj, ce, method_name, retval TSRMLS_CC)

#define call_php_method_with_1_params(obj, ce, method_name, retval, arg1) \
_call_php_method_with_1_params(obj, ce, method_name, retval, arg1 TSRMLS_CC)

#define call_php_method_with_2_params(obj, ce, method_name, retval, arg1, arg2) \
_call_php_method_with_2_params(obj, ce, method_name, retval, arg1, arg2 TSRMLS_CC)

#define call_php_function_with_0_params(function_name, retval) \
_call_php_function_with_0_params(function_name, retval TSRMLS_CC)

#define call_php_function_with_1_params(function_name, retval, arg1) \
_call_php_function_with_1_params(function_name, retval, arg1 TSRMLS_CC)

#define call_php_function_with_2_params(function_name, retval, arg1, arg2) \
_call_php_function_with_2_params(function_name, retval, arg1, arg2 TSRMLS_CC)

#define timecop_call_orig_method_with_1_params(obj, obj_ce, fn_proxy, function_name, retval, arg1) \
zend_call_method(obj, obj_ce, fn_proxy, ORIG_FUNC_NAME(function_name), ORIG_FUNC_NAME_SIZEOF(function_name)-1, retval, 1, arg1, NULL TSRMLS_CC)
#define call_php_function_with_3_params(function_name, retval, arg1, arg2, arg3) \
_call_php_function_with_3_params(function_name, retval, arg1, arg2, arg3 TSRMLS_CC)

#define timecop_call_orig_method_with_2_params(obj, obj_ce, fn_proxy, function_name, retval, arg1, arg2) \
zend_call_method(obj, obj_ce, fn_proxy, ORIG_FUNC_NAME(function_name), ORIG_FUNC_NAME_SIZEOF(function_name)-1, retval, 2, arg1, arg2 TSRMLS_CC)
#define call_php_function_with_params(function_name, retval, param_count, params) \
_call_php_function_with_params(function_name, retval, param_count, params TSRMLS_CC)

/* In every utility function you add that needs to use variables
in php_timecop_globals, call TSRMLS_FETCH(); after declaring other
Expand Down
27 changes: 0 additions & 27 deletions tests/006.phpt

This file was deleted.

22 changes: 0 additions & 22 deletions tests/008.phpt

This file was deleted.

23 changes: 0 additions & 23 deletions tests/009.phpt

This file was deleted.

16 changes: 8 additions & 8 deletions tests/core_001.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,18 @@ if (PHP_INT_SIZE === 8) {
timecop_freeze(1);
$dt7 =new TimecopDateTime();

var_dump($dt2->format("Y-m-d H:i:s.u"));
var_dump($dt4->format("Y-m-d H:i:s.u"));
var_dump($dt6->format("Y-m-d H:i:s.u"));
var_dump($dt2->format("Y-m-d H:i:s.uP"));
var_dump($dt4->format("Y-m-d H:i:s.uP"));
var_dump($dt6->format("Y-m-d H:i:s.uP"));
var_dump($dt1 == $dt2);
var_dump($dt3 == $dt4);
var_dump($dt5 == $dt6);
var_dump($dt7->format("Y-m-d H:i:s.u"));
var_dump($dt7->format("Y-m-d H:i:s.uP"));
--EXPECT--
string(26) "1969-12-31 16:00:00.000000"
string(26) "1970-01-01 01:00:00.000000"
string(26) "2039-12-31 16:00:00.000000"
string(32) "1969-12-31 16:00:00.000000-08:00"
string(32) "1970-01-01 01:00:00.000000-08:00"
string(32) "2039-12-31 16:00:00.000000-08:00"
bool(true)
bool(true)
bool(true)
string(26) "1969-12-31 16:00:01.000000"
string(32) "1969-12-31 16:00:01.000000-08:00"
21 changes: 11 additions & 10 deletions tests/core_005.phpt
Original file line number Diff line number Diff line change
@@ -1,40 +1,41 @@
--TEST--
Check for Timecop::freeze()
Test for Timecop::freeze()
--SKIPIF--
<?php
$required_func = array();
$required_class = array("TimecopDateTime");
$required_method = array(array("Timecop", "freeze"));
include(__DIR__."/../tests-skipcheck.inc.php");
--INI--
date.timezone=America/Los_Angeles
date.timezone=Pacific/Honolulu
; Pacific/Honolulu=UTC-10
timecop.func_override=1
--FILE--
<?php
$dt1 = new DateTime("1970-01-01 00:00:00.000 GMT");
Timecop::freeze($dt1);
$dt2 =new TimecopDateTime();

if (class_exists("DateTimeImmutable")) {
$dt3 = new DateTimeImmutable("1970-01-01 09:00:00.000 GMT");
$dt3 = new DateTimeImmutable("1970-01-01 11:00:00.000 GMT");
Timecop::freeze($dt3);
$dt4 =new TimecopDateTime();
} else {
$dt3 = new DateTime("1970-01-01 01:00:00.000");
$dt4 = new DateTime("1970-01-01 01:00:00.000");
}

$dt5 = new TimecopDateTime("2040-01-01 00:00:00.000 GMT");
$dt5 = new TimecopDateTime("2040-01-01 00:00:05.000 GMT");
Timecop::freeze($dt5);

if (PHP_INT_SIZE === 8) {
$dt6 = new TimecopDateTime();
} else {
// force pass the test on 32bit environment
$dt6 = $dt5;
$dt6->setTimeZone(new DateTimezone("America/Los_Angeles"));
$dt6->setTimeZone(new DateTimezone("Pacific/Honolulu"));
}

Timecop::freeze(1);
Timecop::freeze(7);
$dt7 =new TimecopDateTime();

var_dump($dt2->format("Y-m-d H:i:s.u"));
Expand All @@ -45,10 +46,10 @@ var_dump($dt3 == $dt4);
var_dump($dt5 == $dt6);
var_dump($dt7->format("Y-m-d H:i:s.u"));
--EXPECT--
string(26) "1969-12-31 16:00:00.000000"
string(26) "1969-12-31 14:00:00.000000"
string(26) "1970-01-01 01:00:00.000000"
string(26) "2039-12-31 16:00:00.000000"
string(26) "2039-12-31 14:00:05.000000"
bool(true)
bool(true)
bool(true)
string(26) "1969-12-31 16:00:01.000000"
string(26) "1969-12-31 14:00:07.000000"
17 changes: 17 additions & 0 deletions tests/core_009.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
Test for date_timestamp_get() on PHP 5.2
--SKIPIF--
<?php
if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
die("skip this test is for PHP 5.2.x");
}
$required_class = array("timecopdatetime");
include(__DIR__."/../tests-skipcheck.inc.php");
--INI--
date.timezone=America/Los_Angeles
--FILE--
<?php
$dt = new TimecopDateTime("@1000");
var_dump(date_timestamp_get($dt));
--EXPECT--
int(1000)
18 changes: 18 additions & 0 deletions tests/core_010.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
Test for date_timestamp_set() on PHP 5.2
--SKIPIF--
<?php
if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
die("skip this test is for PHP 5.2.x");
}
$required_class = array("timecopdatetime");
include(__DIR__."/../tests-skipcheck.inc.php");
--INI--
date.timezone=America/Los_Angeles
--FILE--
<?php
$dt = new TimecopDateTime("@1000");
date_timestamp_set($dt, 2000);
var_dump($dt->format("U"));
--EXPECT--
string(4) "2000"
22 changes: 22 additions & 0 deletions tests/core_011.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
Test for $_SERVER['REQUEST_TIME'] when timecop.sync_request_time=1
--SKIPIF--
<?php
$required_func = array("timecop_freeze", "timecop_travel", "timecop_return");
include(__DIR__."/../tests-skipcheck.inc.php");
--INI--
date.timezone=UTC
timecop.sync_request_time=1
--FILE--
<?php
$orig_request_time = $_SERVER['REQUEST_TIME'];
timecop_freeze(1234);
var_dump($_SERVER['REQUEST_TIME']);
timecop_travel(12345);
var_dump($_SERVER['REQUEST_TIME']);
timecop_return();
var_dump($orig_request_time === $_SERVER['REQUEST_TIME']);
--EXPECT--
int(1234)
int(12345)
bool(true)
12 changes: 3 additions & 9 deletions tests/007.phpt → tests/core_012.phpt
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
--TEST--
Check for timecop.sync_request_time=0 and $_SERVER['REQUEST_TIME']
Test for $_SERVER['REQUEST_TIME'] when timecop.sync_request_time=0
--SKIPIF--
<?php
extension_loaded('timecop') or die('skip timecop not available');
$required_func = array("timecop_freeze", "timecop_travel", "timecop_return");
foreach ($required_func as $func_name) {
if (!function_exists($func_name)) {
die("skip $func_name() function is not available.");
}
}
?>
$required_func = array("timecop_freeze", "timecop_travel", "timecop_return");
include(__DIR__."/../tests-skipcheck.inc.php");
--INI--
date.timezone=UTC
timecop.sync_request_time=0
Expand Down
Loading

0 comments on commit 34ab027

Please sign in to comment.