# vim: set ts=4 sw=4 expandtab : ''' Copyright (c) 2017 Tim Savannah All Rights Reserved. Licensed under the Lesser GNU Public License Version 3, LGPLv3. You should have recieved a copy of this with the source distribution as LICENSE, otherwise it is available at https://github.com/kata198/func_timeout/LICENSE TestUtils.py - Common functions and types used across unit tests ''' import copy import sys import time import uuid __all__ = ('ARG_NO_DEFAULT', 'getSleepLambda', 'getSleepLambdaWithArgs', 'compareTimes') class ARG_NO_DEFAULT_TYPE(object): def __eq__(self, other): ''' __eq__ - Equal operator ( == ). Returns True if both are instances of ARG_NO_DEFAULT_TYPE, or either is the type itself. @param other - The other item to compare against this item. @return - True if both objects are instances of ARG_NO_DEFAULT_TYPE, or either are the type itself. ''' # Is self == ARG_NO_DEFAULT_TYPE ever going to be True? Just in case... if issubclass(other.__class__, ARG_NO_DEFAULT_TYPE) or (other == ARG_NO_DEFAULT_TYPE or self == ARG_NO_DEFAULT_TYPE): return True return False def __ne__(self, other): ''' __ne__ - Not-equal operator ( != ). Equivilant to not ==. @see ARG_NO_DEFAULT_TYPE.__eq__ ''' return not self.__eq__(other) def __cmp__(self, other): ''' __cmp__ - Perform a "cmp" operation between self and other. Added for completeness, like python2 sorting etc. @param other - Another object, preferably one of ARG_NO_DEFAULT_TYPE. @return - Returns 0 if the objects are both equal (both instances of ARG_NO_DEFAULT_TYPE), otherwise to prevent recursion in sorting etc, the id (location in memory) is compared. ''' if self.__eq__(other): return 0 if id(self) > id(other): return 1 return -1 ARG_NO_DEFAULT = ARG_NO_DEFAULT_TYPE() def getUniqueID(prefix): uniqueName = prefix + '_' + str(uuid.uuid4().hex) return uniqueName def getSleepLambda(sleepTime): ''' getSleepLambda - Get a lambda that takes two integer arguments (a, b) and sleeps for a given number of seconds before returning the sum @param sleepTime - The number of seconds to sleep @return lambda takes two integer argumennts, "a" and "b". NOTE: Lambda's are usually to functions, as functions may get their scope/closure overridden @see getSleepLambdaWithArgs ''' # Ensure we don't get a strange reference override on somne versions of python _sleepTime = copy.copy(sleepTime) return eval('''lambda a, b : int(bool(time.sleep(%f))) + a + b''' %(_sleepTime,)) def getSleepLambdaWithArgs(sleepTime, args): ''' getSleepLambdaWithArgs - Get a lambda that takes a variable collection of arguments and sleeps for a given number of seconds before returning the sum of arguments @param sleepTime - The number of seconds to sleep @param args list - A list that represents the arguments to the returned lambda. Should be a list of tuples. The first tuple element is the name of the parameter. If a second paramater is present, it will be used as the default value for that argument. Keep in mind order is important ( i.e. no args with default following args without default), as they will be used in the order provided. All arguments should expect integer values. @return lambda with the provided arguments NOTE: Lambda's are usually to functions, as functions may get their scope/closure overridden @see getSleepLambda ''' # Ensure we don't get a strange reference override on somne versions of python _sleepTime = copy.copy(sleepTime) if not args: raise ValueError('Empty "args" param. See docstring for usage details. Got: ' + repr(args)) _args = copy.deepcopy(args) argStrs = [] argNames = [] for arg in _args: argNames.append(arg[0]) if len(arg) == 1: argStrs.append(arg[0]) else: argStrs.append('%s=%d' %( arg[0], arg[1] ) ) argStr = ', '.join(argStrs) sumStr = ' + '.join(argNames) # print ( 'Function is: %s' %('''lambda %s : int(bool(time.sleep(%f))) + %s''' %(argStr, sleepTime, sumStr, ) ) ) return eval('''lambda %s : int(bool(time.sleep(%f))) + %s''' % (argStr, sleepTime, sumStr, ) ) def compareTimes(timeEnd, timeStart, cmpTime, roundTo=None, deltaFixed=.05, deltaPct=None): ''' compareTimes - Compare two times, with support for max error @param timeEnd - End time @param timeStart - Start time @param cmpTime - Time to compare against @param roundTo - Number of digits to round-off to @param deltaFixed Default .05, If provided and if difference is within this much, the two values are considered equal @param deltaPct Default None, if provided and if difference is within this much, the two values are considered equal. 1 = 100%, .5 = 50% Example: if trying to determine if function ran for 2 seconds with an error of .05 seconds, if compareTimes( timeEnd, timeStart, 2, deltaFixed=.05, deltaPct=None) == 0 @return cmp style, < 0 if time delta is less than #cmpTime = 0 if time delta is equal (taking into account #deltaFixed and #deltaPct) > 0 if time delta is greater than #cmpTime ''' timeDiff = timeEnd - timeStart delta = timeDiff - cmpTime if roundTo is not None: delta = round(delta, roundTo) absDelta = abs(delta) if deltaFixed and absDelta <= deltaFixed: return 0 if deltaPct and absDelta <= (cmpTime * float(deltaPct)): return 0 return delta # vim: set ts=4 sw=4 expandtab :