1111use SebastianBergmann \GlobalState \Snapshot ;
1212use SebastianBergmann \GlobalState \Restorer ;
1313use SebastianBergmann \GlobalState \Blacklist ;
14+ use SebastianBergmann \Diff \Differ ;
1415use SebastianBergmann \Exporter \Exporter ;
1516use Prophecy \Exception \Prediction \PredictionException ;
1617use Prophecy \Prophet ;
@@ -264,6 +265,11 @@ abstract class PHPUnit_Framework_TestCase extends PHPUnit_Framework_Assert imple
264265 */
265266 private $ prophet ;
266267
268+ /**
269+ * @var boolean
270+ */
271+ private $ disallowChangesToGlobalState = false ;
272+
267273 /**
268274 * Constructs a test case with the given name.
269275 *
@@ -1010,6 +1016,15 @@ public function setDependencyInput(array $dependencyInput)
10101016 $ this ->dependencyInput = $ dependencyInput ;
10111017 }
10121018
1019+ /**
1020+ * @param boolean $disallowChangesToGlobalState
1021+ * @since Method available since Release 4.6.0
1022+ */
1023+ public function setDisallowChangesToGlobalState ($ disallowChangesToGlobalState )
1024+ {
1025+ $ this ->disallowChangesToGlobalState = $ disallowChangesToGlobalState ;
1026+ }
1027+
10131028 /**
10141029 * Calling this method in setUp() has no effect!
10151030 *
@@ -1908,52 +1923,14 @@ private function stopOutputBuffering()
19081923
19091924 private function snapshotGlobalState ()
19101925 {
1911- if ($ this ->runTestInSeparateProcess || $ this ->inIsolation ) {
1912- return ;
1913- }
1914-
19151926 $ backupGlobals = $ this ->backupGlobals === null || $ this ->backupGlobals === true ;
19161927
1917- if ($ backupGlobals || $ this ->backupStaticAttributes ) {
1918- $ blacklist = new Blacklist ;
1919-
1920- if ($ backupGlobals ) {
1921- foreach ($ this ->backupGlobalsBlacklist as $ globalVariable ) {
1922- $ blacklist ->addGlobalVariable ($ globalVariable );
1923- }
1924- }
1925-
1926- if ($ this ->backupStaticAttributes && !defined ('PHPUNIT_TESTSUITE ' )) {
1927- $ blacklist ->addClassNamePrefix ('PHPUnit ' );
1928- $ blacklist ->addClassNamePrefix ('File_Iterator ' );
1929- $ blacklist ->addClassNamePrefix ('PHP_CodeCoverage ' );
1930- $ blacklist ->addClassNamePrefix ('PHP_Invoker ' );
1931- $ blacklist ->addClassNamePrefix ('PHP_Timer ' );
1932- $ blacklist ->addClassNamePrefix ('PHP_Token ' );
1933- $ blacklist ->addClassNamePrefix ('Symfony ' );
1934- $ blacklist ->addClassNamePrefix ('Text_Template ' );
1935- $ blacklist ->addClassNamePrefix ('Doctrine\Instantiator ' );
1936-
1937- foreach ($ this ->backupStaticAttributesBlacklist as $ class => $ attributes ) {
1938- foreach ($ attributes as $ attribute ) {
1939- $ blacklist ->addStaticAttribute ($ class , $ attribute );
1940- }
1941- }
1942- }
1943-
1944- $ this ->snapshot = new Snapshot (
1945- $ blacklist ,
1946- $ backupGlobals ,
1947- $ this ->backupStaticAttributes ,
1948- false ,
1949- false ,
1950- false ,
1951- false ,
1952- false ,
1953- false ,
1954- false
1955- );
1928+ if ($ this ->runTestInSeparateProcess || $ this ->inIsolation ||
1929+ (!$ backupGlobals && !$ this ->backupStaticAttributes )) {
1930+ return ;
19561931 }
1932+
1933+ $ this ->snapshot = $ this ->createGlobalStateSnapshot ($ backupGlobals );
19571934 }
19581935
19591936 private function restoreGlobalState ()
@@ -1962,9 +1939,18 @@ private function restoreGlobalState()
19621939 return ;
19631940 }
19641941
1942+ $ backupGlobals = $ this ->backupGlobals === null || $ this ->backupGlobals === true ;
1943+
1944+ if ($ this ->disallowChangesToGlobalState ) {
1945+ $ this ->compareGlobalStateSnapshots (
1946+ $ this ->snapshot ,
1947+ $ this ->createGlobalStateSnapshot ($ backupGlobals )
1948+ );
1949+ }
1950+
19651951 $ restorer = new Restorer ;
19661952
1967- if ($ this -> backupGlobals === null || $ this -> backupGlobals === true ) {
1953+ if ($ backupGlobals ) {
19681954 $ restorer ->restoreGlobalVariables ($ this ->snapshot );
19691955 }
19701956
@@ -1975,6 +1961,105 @@ private function restoreGlobalState()
19751961 $ this ->snapshot = null ;
19761962 }
19771963
1964+ /**
1965+ * @param boolean $backupGlobals
1966+ * @return Snapshot
1967+ */
1968+ private function createGlobalStateSnapshot ($ backupGlobals )
1969+ {
1970+ $ blacklist = new Blacklist ;
1971+
1972+ foreach ($ this ->backupGlobalsBlacklist as $ globalVariable ) {
1973+ $ blacklist ->addGlobalVariable ($ globalVariable );
1974+ }
1975+
1976+ if (!defined ('PHPUNIT_TESTSUITE ' )) {
1977+ $ blacklist ->addClassNamePrefix ('PHPUnit ' );
1978+ $ blacklist ->addClassNamePrefix ('File_Iterator ' );
1979+ $ blacklist ->addClassNamePrefix ('PHP_CodeCoverage ' );
1980+ $ blacklist ->addClassNamePrefix ('PHP_Invoker ' );
1981+ $ blacklist ->addClassNamePrefix ('PHP_Timer ' );
1982+ $ blacklist ->addClassNamePrefix ('PHP_Token ' );
1983+ $ blacklist ->addClassNamePrefix ('Symfony ' );
1984+ $ blacklist ->addClassNamePrefix ('Text_Template ' );
1985+ $ blacklist ->addClassNamePrefix ('Doctrine\Instantiator ' );
1986+
1987+ foreach ($ this ->backupStaticAttributesBlacklist as $ class => $ attributes ) {
1988+ foreach ($ attributes as $ attribute ) {
1989+ $ blacklist ->addStaticAttribute ($ class , $ attribute );
1990+ }
1991+ }
1992+ }
1993+
1994+ return new Snapshot (
1995+ $ blacklist ,
1996+ $ backupGlobals ,
1997+ $ this ->backupStaticAttributes ,
1998+ false ,
1999+ false ,
2000+ false ,
2001+ false ,
2002+ false ,
2003+ false ,
2004+ false
2005+ );
2006+ }
2007+
2008+ /**
2009+ * @param Snapshot $before
2010+ * @param Snapshot $after
2011+ * @throws PHPUnit_Framework_RiskyTestError
2012+ */
2013+ private function compareGlobalStateSnapshots (Snapshot $ before , Snapshot $ after )
2014+ {
2015+ $ backupGlobals = $ this ->backupGlobals === null || $ this ->backupGlobals === true ;
2016+
2017+ if ($ backupGlobals ) {
2018+ $ this ->compareGlobalStateSnapshotPart (
2019+ $ before ->globalVariables (),
2020+ $ after ->globalVariables (),
2021+ "--- Global variables before the test \n+++ Global variables after the test \n"
2022+ );
2023+
2024+ $ this ->compareGlobalStateSnapshotPart (
2025+ $ before ->superGlobalVariables (),
2026+ $ after ->superGlobalVariables (),
2027+ "--- Super-global variables before the test \n+++ Super-global variables after the test \n"
2028+ );
2029+ }
2030+
2031+ if ($ this ->backupStaticAttributes ) {
2032+ $ this ->compareGlobalStateSnapshotPart (
2033+ $ before ->staticAttributes (),
2034+ $ after ->staticAttributes (),
2035+ "--- Static attributes before the test \n+++ Static attributes after the test \n"
2036+ );
2037+ }
2038+ }
2039+
2040+ /**
2041+ * @param array $before
2042+ * @param array $after
2043+ * @param string $header
2044+ * @throws PHPUnit_Framework_RiskyTestError
2045+ */
2046+ private function compareGlobalStateSnapshotPart (array $ before , array $ after , $ header )
2047+ {
2048+ if ($ before != $ after ) {
2049+ $ differ = new Differ ($ header );
2050+ $ exporter = new Exporter ;
2051+
2052+ $ diff = $ differ ->diff (
2053+ $ exporter ->export ($ before ),
2054+ $ exporter ->export ($ after )
2055+ );
2056+
2057+ throw new PHPUnit_Framework_RiskyTestError (
2058+ $ diff
2059+ );
2060+ }
2061+ }
2062+
19782063 /**
19792064 * @return Prophecy\Prophet
19802065 * @since Method available since Release 4.5.0
0 commit comments