Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F5962267
ForAll.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
ForAll.php
View Options
<?php
namespace
Eris\Quantifier
;
use
Eris\Antecedent
;
use
Eris\Generator
;
use
Eris\Generator\GeneratedValueSingle
;
use
Eris\Generator\SkipValueException
;
use
BadMethodCallException
;
use
PHPUnit\Framework\Constraint\Constraint
;
use
Exception
;
use
RuntimeException
;
use
Eris\Listener
;
use
Eris\Random\RandomRange
;
/**
* @method self and()
*/
class
ForAll
{
const
DEFAULT_MAX_SIZE
=
200
;
private
$generators
;
private
$iterations
;
private
$maxSize
;
private
$shrinkerFactory
;
private
$antecedents
=
[];
private
$ordinaryEvaluations
=
0
;
private
$aliases
=
[
'and'
=>
'when'
,
];
private
$terminationConditions
=
[];
private
$listeners
=
[];
private
$shrinkerFactoryMethod
;
/**
* @var RandomRange
*/
private
$rand
;
private
$shrinkingEnabled
=
true
;
public
function
__construct
(
array
$generators
,
$iterations
,
$shrinkerFactory
,
$shrinkerFactoryMethod
,
RandomRange
$rand
)
{
$this
->
generators
=
$this
->
generatorsFrom
(
$generators
);
$this
->
iterations
=
$iterations
;
$this
->
shrinkerFactory
=
$shrinkerFactory
;
$this
->
shrinkerFactoryMethod
=
$shrinkerFactoryMethod
;
$this
->
rand
=
$rand
;
$this
->
maxSize
=
self
::
DEFAULT_MAX_SIZE
;
}
/**
* @param integer $maxSize
* @return self
*/
public
function
withMaxSize
(
$maxSize
)
{
$this
->
maxSize
=
$maxSize
;
return
$this
;
}
/**
* @return self
*/
public
function
hook
(
Listener
$listener
)
{
$this
->
listeners
[]
=
$listener
;
return
$this
;
}
/**
* @return self
*/
public
function
stopOn
(
TerminationCondition
$terminationCondition
)
{
$this
->
terminationConditions
[]
=
$terminationCondition
;
return
$this
;
}
/**
* @return self
*/
public
function
disableShrinking
()
{
$this
->
shrinkingEnabled
=
false
;
return
$this
;
}
/**
* Examples of calls:
* when($constraint1, $constraint2, ..., $constraintN)
* when(callable $takesNArguments)
* when(Antecedent $antecedent)
* @return self
*/
public
function
when
(
/* see docblock */
)
{
$arguments
=
func_get_args
();
if
(
$arguments
[
0
]
instanceof
Antecedent
)
{
$antecedent
=
$arguments
[
0
];
}
elseif
(
$arguments
[
0
]
instanceof
Constraint
)
{
$antecedent
=
Antecedent\IndependentConstraintsAntecedent
::
fromAll
(
$arguments
);
}
elseif
(
$arguments
&&
count
(
$arguments
)
==
1
)
{
$antecedent
=
Antecedent\SingleCallbackAntecedent
::
from
(
$arguments
[
0
]);
}
else
{
throw
new
\InvalidArgumentException
(
"Invalid call to when(): "
.
var_export
(
$arguments
,
true
));
}
$this
->
antecedents
[]
=
$antecedent
;
return
$this
;
}
public
function
__invoke
(
callable
$assertion
)
{
$sizes
=
Size
::
withTriangleGrowth
(
$this
->
maxSize
)
->
limit
(
$this
->
iterations
);
try
{
$redTestException
=
null
;
$this
->
notifyListeners
(
'startPropertyVerification'
);
for
(
$iteration
=
0
;
$iteration
<
$this
->
iterations
&&
!
$this
->
terminationConditionsAreSatisfied
();
$iteration
++
)
{
$generatedValues
=
[];
$values
=
[];
try
{
foreach
(
$this
->
generators
as
$name
=>
$generator
)
{
$value
=
$generator
(
$sizes
->
at
(
$iteration
),
$this
->
rand
);
if
(!(
$value
instanceof
GeneratedValueSingle
))
{
throw
new
RuntimeException
(
"The value returned by a generator should be an instance of GeneratedValueSingle, but it is "
.
var_export
(
$value
,
true
));
}
$generatedValues
[]
=
$value
;
$values
[]
=
$value
->
unbox
();
}
}
catch
(
SkipValueException
$e
)
{
continue
;
}
$generation
=
GeneratedValueSingle
::
fromValueAndInput
(
$values
,
$generatedValues
,
'tuple'
);
$this
->
notifyListeners
(
'newGeneration'
,
$generation
->
unbox
(),
$iteration
);
if
(!
$this
->
antecedentsAreSatisfied
(
$values
))
{
continue
;
}
$this
->
ordinaryEvaluations
++;
Evaluation
::
of
(
$assertion
)
// TODO: coupling between here and the TupleGenerator used inside?
->
with
(
$generation
)
->
onFailure
(
function
(
$generatedValues
,
$exception
)
use
(
$assertion
)
{
$this
->
notifyListeners
(
'failure'
,
$generatedValues
->
unbox
(),
$exception
);
if
(!
$this
->
shrinkingEnabled
)
{
throw
$exception
;
}
$shrinkerFactoryMethod
=
$this
->
shrinkerFactoryMethod
;
$shrinking
=
$this
->
shrinkerFactory
->
$shrinkerFactoryMethod
(
$this
->
generators
,
$assertion
);
// MAYBE: put into ShrinkerFactory?
$shrinking
->
addGoodShrinkCondition
(
function
(
GeneratedValueSingle
$generatedValues
)
{
return
$this
->
antecedentsAreSatisfied
(
$generatedValues
->
unbox
());
})
->
onAttempt
(
function
(
GeneratedValueSingle
$generatedValues
)
{
$this
->
notifyListeners
(
'shrinking'
,
$generatedValues
->
unbox
());
})
->
from
(
$generatedValues
,
$exception
);
})
->
execute
();
}
}
catch
(
Exception
$e
)
{
$redTestException
=
$e
;
if
((
bool
)
getenv
(
'ERIS_ORIGINAL_INPUT'
))
{
$message
=
"Original input: "
.
var_export
(
$values
,
true
)
.
PHP_EOL
.
"Possibly shrinked input follows."
.
PHP_EOL
;
throw
new
RuntimeException
(
$message
,
-
1
,
$e
);
}
else
{
throw
$e
;
}
}
finally
{
$this
->
notifyListeners
(
'endPropertyVerification'
,
$this
->
ordinaryEvaluations
,
$this
->
iterations
,
$redTestException
);
}
}
public
function
then
(
callable
$assertion
)
{
$this
->
__invoke
(
$assertion
);
}
/**
* @see $this->aliases
* @method then($assertion)
* @method implies($assertion)
* @method imply($assertion)
*/
public
function
__call
(
$method
,
$arguments
)
{
if
(
isset
(
$this
->
aliases
[
$method
]))
{
return
call_user_func_array
(
[
$this
,
$this
->
aliases
[
$method
]],
$arguments
);
}
throw
new
BadMethodCallException
(
"Method "
.
__CLASS__
.
"::{$method} does not exist"
);
}
private
function
generatorsFrom
(
$supposedToBeGenerators
)
{
$generators
=
[];
foreach
(
$supposedToBeGenerators
as
$supposedToBeGenerator
)
{
if
(!
$supposedToBeGenerator
instanceof
Generator
)
{
$generators
[]
=
new
Generator\ConstantGenerator
(
$supposedToBeGenerator
);
}
else
{
$generators
[]
=
$supposedToBeGenerator
;
}
}
return
$generators
;
}
private
function
notifyListeners
(
/*$event, [$parameterA[, $parameterB[, ...]]]*/
)
{
$arguments
=
func_get_args
();
$event
=
array_shift
(
$arguments
);
foreach
(
$this
->
listeners
as
$listener
)
{
call_user_func_array
(
[
$listener
,
$event
],
$arguments
);
}
}
private
function
antecedentsAreSatisfied
(
array
$values
)
{
foreach
(
$this
->
antecedents
as
$antecedentToVerify
)
{
if
(!
call_user_func
(
[
$antecedentToVerify
,
'evaluate'
],
$values
))
{
return
false
;
}
}
return
true
;
}
private
function
terminationConditionsAreSatisfied
()
{
foreach
(
$this
->
terminationConditions
as
$terminationCondition
)
{
if
(
$terminationCondition
->
shouldTerminate
())
{
return
true
;
}
}
return
false
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Sat, Oct 3, 08:45 (1 w, 5 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
f9/b2/60c6fc8a7c53ce1732bf07bd7255
Default Alt Text
ForAll.php (8 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment