Skip to content

Commit

Permalink
First cut of the new ContractLib
Browse files Browse the repository at this point in the history
  • Loading branch information
stuartherbert committed Oct 22, 2011
1 parent 99564c5 commit 406a763
Show file tree
Hide file tree
Showing 7 changed files with 782 additions and 0 deletions.
274 changes: 274 additions & 0 deletions src/php/Phix_Project/ContractLib/Contract.php
@@ -0,0 +1,274 @@
<?php

/**
* Copyright (c) 2011 Stuart Herbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of the copyright holders nor the names of the
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package Phix_Project
* @subpackage ContractLib
* @author Stuart Herbert <stuart@stuartherbert.com>
* @copyright 2011 Stuart Herbert
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
* @link http://phix-project.org
* @version @@PACKAGE_VERSION@@
*/

namespace Phix_Project\ContractLib;

class Contract
{
/**
* Are we currently enforcing any contracts passed to
* self::Enforce()?
*
* By default, we do not!
*
* @var boolean
*/
static protected $enforcing = false;

/**
* Stateless library; cannot instantiate
*/
protected function __construct()
{
// do nothing
}

/**
* Precondition: is the expression $expr true?
*
* Use this method at the start of your method to make sure you're
* happy with the data that you have been passed, and with the
* current state of your object
*
* Throws an E5xx_ContractPreconditionException if the parameter
* passed in is false
*
* @throw E5xx_ContractPreconditionException
* @param boolean $expr
*/
static public function Requires($expr)
{
if (!$expr)
{
throw new E5xx_ContractPreconditionException();
}
}

/**
* Precondition: is the expression $expr true?
*
* Use this method at the start of your method to make sure you're
* happy with the data that you have been passed, and with the
* current state of your object
*
* Throws an E5xx_ContractPreconditionException if $expr is false,
* and adds $value to the exception's error message so that you
* can see which value failed the test
*
* @param boolean $expr
* @param mixed $value
*/
static public function RequiresValue($expr, $value)
{
if (!$expr)
{
throw new E5xx_ContractPreconditionException(true, $value);
}
}

/**
* Postcondition: is the expression $expr true?
*
* Use this method at the end of your method to make sure you're
* happy with the results before your method returns to the caller
*
* Throws an E5xx_ContractPostconditionException if $expr is false.
*
* @param boolean $expr
*/
static public function Ensures($expr)
{
if (!$expr)
{
throw new E5xx_ContractPostconditionException();
}
}

/**
* Postcondition: is the expression $expr true?
*
* Use this method at the end of your method to make sure you're
* happy with the results before your method returns to the caller
*
* Throws an E5xx_ContractPostConditionException if $expr is false,
* and adds $value to the exception's error message so that you
* can see which value failed the test
*
* @param boolean $expr
* @param mixed $value
*/
static public function EnsuresValue($expr, $value)
{
if (!$expr)
{
throw new E5xx_ContractPostconditionException(true, $value);
}
}

/**
* Condition: is the expr $expr true?
*
* Use this method in the middle of your method, to check the
* workings of your method before continuing.
*
* Throws an E5xx_ContractConditionException if $expr is false.
*
* @param type $expr
*/
static public function Asserts($expr)
{
if (!$expr)
{
throw new E5xx_ContractConditionException();
}
}

/**
* Condition: is the expr $expr true?
*
* Use this method in the middle of your method, to check the
* workings of your method before continuing.
*
* Throws an E5xx_ContractConditionException if $expr is false,
* and adds $value to the exception's error message so that you
* can see which value failed the test
*
* @param boolean $expr
* @param mixed $value
*/
static public function AssertsValue($expr, $value)
{
if (!$expr)
{
throw new E5xx_ContractConditionException(true, $value);
}
}

/**
*
* @param type $values
* @param type $callback
*/
static public function ForAll($values, $callback)
{
array_walk($values, $callback);
}

// ================================================================
//
// Wrapped contract support
//
// ----------------------------------------------------------------

/**
* Tell us to enforce contracts passed to self::Enforce()
*/
static public function EnforceWrappedContracts()
{
self::$enforcing = true;
}

/**
* Tell us to enforce only calls made directly to the individual
* contract conditions: Requires, Assert, Ensures et al
*/
static public function EnforceOnlyDirectContracts()
{
self::$enforcing = false;
}

/**
* Check a set of preconditions *if* we are enforcing wrapped
* contracts.
*
* This exists as a performance boost, allowing us to leave
* contracts in the code even in production environments
*
* @param callback $callback
* @param array $params
*/
static public function Preconditions($callback, $params = array())
{
if (self::$enforcing)
{
call_user_func_array($callback, $params);
}
}

/**
* Check a set of postconditions *if* we are enforcing wrapped
* contracts.
*
* This exists as a performance boost, allowing us to leave
* contracts in the code even in production environments
*
* @param callback $callback
* @param array $params
*/
static public function Postconditions($callback, $params = array())
{
if (self::$enforcing)
{
call_user_func_array($callback, $params);
}
}

/**
* Check a set of conditions mid-method *if* we are enforcing
* wrapped contracts.
*
* This exists as a performance boost, allowing us to leave
* contracts in the code even in production environments
*
* @param callback $callback
* @param array $params
*/
static public function Conditionals($callback, $params = array())
{
if (self::$enforcing)
{
call_user_func_array($callback, $params);
}
}
}
55 changes: 55 additions & 0 deletions src/php/Phix_Project/ContractLib/ContractInvariant.php
@@ -0,0 +1,55 @@
<?php

/**
* Copyright (c) 2011 Stuart Herbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of the copyright holders nor the names of the
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package Phix_Project
* @subpackage ContractLib
* @author Stuart Herbert <stuart@stuartherbert.com>
* @copyright 2011 Stuart Herbert
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
* @link http://phix-project.org
* @version @@PACKAGE_VERSION@@
*/

namespace Phix_Project\ContractLib;

interface ContractInvariant
{
/**
* A test method that can be called at any time during the life
* of an object, which will run a series of assert()s to prove
* that the object is in a sane state
*/
public function objectInvariant();
}
@@ -0,0 +1,63 @@
<?php

/**
* Copyright (c) 2011 Stuart Herbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of the copyright holders nor the names of the
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package Phix_Project
* @subpackage ContractLib
* @author Stuart Herbert <stuart@stuartherbert.com>
* @copyright 2011 Stuart Herbert
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
* @link http://phix-project.org
* @version @@PACKAGE_VERSION@@
*/

namespace Phix_Project\ContractLib;

/**
* This exception is thrown when an assert() statement fails
*/
class E5xx_ContractConditionException extends E5xx_ContractFailedException
{
public function __construct($hasValue = false, $value = false)
{
if (!$hasValue)
{
parent::__construct("Contract::Assert() failed");
}
else
{
parent::__construct("Contract::AssertValue() failed with value '" . print_r($value, true) . "'");
}
}
}

0 comments on commit 406a763

Please sign in to comment.