Viewing File: /usr/lib/python2.7/site-packages/passlib/tests/utils.pyo


Xc@sdZddlmZddlmZddlZddlmZmZddl	Z	ddl
Z
e
jeZ
ddlZddlZddlZddlZddlZddlZddlZddlmZmZddlmZmZddlZddlmZdd	lmZdd
lmZddl j!Z!ddl"m#Z$m%Z%m&Z&m'Z'm(Z(ddl)m*Z*m+Z+m,Z,m-Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4dd
lm5Z5m6Z6m7Z7m8Z8m9Z9ddl:m;Z;ddl<j=j>Z?dddddgZ@yddlAZBWneCk
r0eDZEnXeFZEdZGdZHeHe3ZIdddgZJeJjKejLjMddjNjOZPeQeQdZRdZSeQdZTdZUeQeDdZVdZWd ZXd!ZYejZd"Z[d#Z\d$Z]d%Z^d&Z_d'Z`d(ZaeQd)d*d+Zbd,d-d.Zcde$fd/YZ#d0dgZdde#fd1YZed2eefd3YZfd4eefd5YZgd6eefd7YZhd8ejifd9YZjdS(:shelpers for passlib unittestsi(twith_statement(t	unhexlifyN(twrapstpartial(tPasslibHashWarningtPasslibConfigWarning(tPY3tJYTHON(twarn(texc(tMissingBackendError(tTestCasetskiptskipIft
skipUnlesstSkipTest(
thas_rounds_infot
has_salt_infotrounds_cost_valuestrngt
getrandstrt
is_ascii_safet
to_native_strt
repeat_stringtticktbatch(t	iteritemstirangetutunicodetPY2(t
classpropertyt	TEST_MODEtset_filetget_fileRtHandlerCasecCsRtjj|}x9tjj||krMtjdtj|dqWdS(sensure file's mtime has changedg?N(tostpathtgetmtimettimetsleeptutimetNone(R%tlast((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytensure_mtime_changed;s
cs/fdtfdtdDS(Ncs1}}x||kr(}qW||S(N((tstarttcur(ttimer(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytsampleEs

c3s|]}VqdS(N((t.0t_(R0(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pys	<genexpr>Jsi(tmintrange(R/((R0R/s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt_get_timer_resolutionDstquicktdefaulttfulltPASSLIB_TEST_MODEcCsB|rttj|krtS|r>ttj|kr>tStS(scheck if test for specified mode should be enabled.

    ``"quick"``
        run the bare minimum tests to ensure functionality.
        variable-cost hashes are tested at their lowest setting.
        hash algorithms are only tested against the backend that will
        be used on the current host. no fuzz testing is done.

    ``"default"``
        same as ``"quick"``, except: hash algorithms are tested
        at default levels, and a brief round of fuzz testing is done
        for each hash.

    ``"full"``
        extra regression and internal tests are enabled, hash algorithms are tested
        against all available backends, unavailable ones are mocked whre possible,
        additional time is devoted to fuzz testing.
    (t
_test_modet_TEST_MODEStindextFalsetTrue(R3tmax((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR Ts
cCs2t|drtSd|jkp1t|tjS(s'check if handler supports 'relaxed' kwdtorig_prefixtrelaxed(thasattrR=tsetting_kwdst
issubclasstuhtGenericHandler(thandler((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pythas_relaxed_settingpscCs"t|}|d|dtjS(s'get effective rounds value from handlertroundstuse_defaults(tunwrap_handlerR>RI(RGRI((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytget_effective_rounds|scCs[y|j}Wntk
r$tSXz!|jd|j|kSWd|j|XdS(s*check if backend is the default for sourceR7N(tget_backendR
R=tset_backend(RGtbackendtorig((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytis_default_backends

ccs|dkr|j}n|j}|r=|j|dnd}x5||D])}||krN|j|rN|VqNqNWdS(s
    iterate over alternate backends available to handler.

    .. warning::
        not thread-safe due to has_backend() call
    iiN(R*RMtbackendsR<thas_backend(RGtcurrenttfallbackRRtidxRO((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytiter_alt_backendss	cOsxt||D]}|SWdS(N(RWR*(targstkwdsRO((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytget_alt_backendscCs#xt|dr|j}qW|S(s5return original handler, removing any wrapper objectstwrapped(RBR[(RG((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRKs
cCs||krtSt|tjrLx#|rG||kr;tS|j}q%WtSt|trzt|tjrzt||St	d|fdS(sG
    test if <handler> was derived from <base> via <base.using()>.
    s%don't know how to inspect handler: %rN(
R>t
isinstanceREt
PrefixWrappert
_derived_fromR=ttypeRDtMinimalHandlertNotImplementedError(RGtbase((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pythandler_derived_froms	
!
c#st|tr[t|tjr[|jfd}||_z	dVWd|_Xn9t|tjrt|j
dVWdQXn	dVdSdS(s
    internal helper for do_config_encrypt() --
    context manager which temporarily replaces handler's _calc_checksum()
    with one that uses min_rounds; useful when trying to generate config
    with high rounds value, but don't care if output is correct.
    cs:|j}z |j|_|||SWd||_XdS(N(RIt
min_rounds(tselfRXRYRI(R[(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytwrappers
	N(	R\R_RDREt	HasRoundst_calc_checksumR]tpatch_calc_min_roundsR[(RGRf((R[s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRis!			
cCsJt|tr!|jd}nt|d}|j|WdQXdS(sset file to specified bytessutf-8twbN(R\Rtencodetopentwrite(R%tcontenttfh((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR!scCs&t|d}|jSWdQXdS(sread file as bytestrbN(Rltread(R%Ro((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR"scCsYt|ts|Str&|jdSy|jdSWntk
rT|jdSXdS(s*convert native string to non-native stringsutf-8slatin-1N(R\tstrRRktdecodetUnicodeDecodeError(tsource((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttonns

cCsttjdd|S(sT
    helper for represent byte strings in hex.

    usage: ``hb("deadbeef23")``
    s\st(Rtretsub(Ru((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pythbscCs$||kr|S||kr |S|S(N((tvaluetlowertupper((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytlimits
cCs't}xt||kr"qWdS(sAbecause time.sleep() doesn't even have 10ms accuracy on some OSesN(R(tdelayR-((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt
quicksleeps	ii
c
Csddlm}ddlm}||d|p2d}d}t|}xXtrt|j||}	t|kr|	|t||dfS|d9}qNWdS(	s
    timeit() wrapper which tries to get as accurate a measurement as possible w/in maxtime seconds.

    :returns:
        ``(avg_seconds_per_call, log10_number_of_repetitions)``
    i(tTimer(tlogtsetupRwii
N(	ttimeitRtmathRRR>R3trepeattint(
tfuncRtmaxtimetbestofRRR/tnumbertendtdelta((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt	time_call	s
	iIj?$csfd}|S(s<
    decorator run test method w/ multiple fixed seeds.
    cs%tfd}|S(NcsJtj}x4tD]&}|jd|d<||qWdS(Ni tseed(trandomtRandomRtgetrandbits(RXRYRR2(tcountRtmaster_seed(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRf s(R(RRf(RR(Rs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytbuilders!((RRR((RRs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytrun_with_fixed_seedsscBsNeZdZdZdZedZedZe	Z
e	ZdZdZ
e	ZdZddZdZeZZdddddddd	Zd
ejfdYZddddZdd
ZdZdZdZdZdZej Z!dZ"dZ#dddZ$dZ%dZ&e	e'dZ(RS(sRpasslib-specific test case class

    this class adds a number of features to the standard TestCase...
    * common prefix for all test descriptions
    * resets warnings filter & registry for every test
    * tweaks to message formatting
    * __msg__ kwd added to assertRaises()
    * suite of methods for matching against warnings
    cCsGtt|j}|j}|rCd||p9t|f}n|S(s;wrap shortDescription() method to prepend descriptionPrefixs%s: %s(tsuperRtshortDescriptiontdescriptionPrefixRr(Retdesctprefix((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRBs
	cCs,|j}|jdp+t|d|tS(NR2s_%s__unittest_skip(t__name__t
startswithtgetattrR=(tclstname((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt__unittest_skip__Ns	cCs|jS(N(R(R((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt__test__UscCs!tt|j|jdS(N(RRtsetUpt
setUpWarnings(Re((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRdscCsS|jrOt}|j|j|jtjddtjddndS(s6helper to init warning filters before subclass setUp()tignores<the method .*\.(encrypt|genconfig|genhash)\(\) is deprecateds&the 'vary_rounds' option is deprecatedN(tresetWarningStatetreset_warningst	__enter__t
addCleanupt__exit__twarningstfilterwarnings(Retctx((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRhs		
cCsF|jr8|r8|jjdr8d|j|fS|pA|SdS(Nt:s%s %s(tlongMessagetrstriptendswith(Retmsgtstd((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt_formatMessage{s$c	Os|jdd}|dkr=tt|j|d||Sy|||}Wn|k
rf}|SXd||f}|j|j||dS(Nt__msg__s-function returned %r, expected it to raise %r(tpopR*RRtassertRaisestfailureExceptionR(	Ret	_exc_typet	_callableRXRYRtresultterrR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRs

cOstddS(Ns%this alias is deprecated by unittest2(tAssertionError(Retatk((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytassertEqualssc	CsOt|dr!|}	|j}nd}	|rI|jt|||n|rk|jt|||n|r|j|||n|s|r|	stdn|	j}
|
j	ds|
j	dr|
d }
n|r|j|
||n|r|j|
||qn|rK|	s2tdn|j|	j
||ndS(scheck if warning matches specified parameters.
        'warning' is the instance of Warning to match against;
        can also be instance of WarningMessage (as returned by catch_warnings).
        tcategorys7matching on filename requires a WarningMessage instances.pycs.pyois5matching on lineno requires a WarningMessage instanceN(RBtmessageR*tassertEqualRrtassertRegextassertIsInstancet	TypeErrortfilenameRtlineno(Retwarningt
message_reRRtfilename_reRRRtwmsgtreal((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt
assertWarnings0	
t_AssertWarningListcBs)eZdZdZdZdZRS(s'context manager for assertWarningList()cKs>||_||_ttj||_|jjdtdS(Ntrecord(tcaseRYRRRt_AssertWarningList__supert__init__R>(ReRRY((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRs		cCs|jj|_dS(N(RRR(Re((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRscGs@|jj||ddkr<|jj|j|jndS(Ni(RRR*RtassertWarningListRRY(Retexc_info((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRs(Rt
__module__t__doc__RRR(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRs		cCsq|dkr%|j|d|d|St|ttfsF|g}nxt|D]\}}t|trtd|}nNt|trt	|t
rtd|}nt|tstdny||}Wntk
rPnX|j
|d||qSWt|t|kr'dSdt|t||j||f}|j|j||dS(sBcheck that warning list (e.g. from catch_warnings) matches patternRRRRs#entry must be str, warning, or dictNs0expected %d warnings, found %d: wlist=%s desc=%r(R*RR\tlistttuplet	enumerateRrtdictR_RDtWarningRt
IndexErrorRtlent_formatWarningListRR(RetwlistRRRVtentrytdataR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRs*
(cOs3|dkrg}n|j|||||2dS(sD[deprecated] assertWarningList() variant that clears list afterwardsN(R*R(ReRRRXRY((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytconsumeWarningLists	cCsd}t|drWd|j|jf}|jrK|d|jf7}n|j}nt|}d|j|jt||fS(NRwRs filename=%r lineno=%rs line=%rs<%s.%s message=%r%s>(	RBRRtlineRR_RRRr(ReRttailR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt_formatWarnings	cs!ddjfd|DS(Ns[%s]s, c3s|]}j|VqdS(N(R(R1R(Re(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pys	<genexpr>
s(tjoin(ReR((Res7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRscCs@ddlm}|s<ddlm}|jd|ndS(s,helper to skip test if stringprep is missingi(t
stringprep(t_stringprep_missing_reasons%not available - stringprep module is N(t
passlib.utilsRRtskipTest(ReRR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytrequire_stringpreps
	cCs&t|s"|jd|ndS(s8skip test for all PASSLIB_TEST_MODE values below <level>srequires >= %r test modeN(R R(Retlevel((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytrequire_TEST_MODEscCstr|jdSdS(s'skip test if writeable FS not availables.GAE doesn't offer read/write filesystem accessN(tGAER(Re((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytrequire_writeable_filesystemsR7c	Csc|j}|r#||kr#||S|j1|j}|rP||krP||S|sfi}|_n|prtj}|dkrttjjdptjjdpt	j
d}t_tjd|nt
|}djt||j|j|j|g}tj|jdj}t|d d}tj|}||<|SWdQXdS(	sU
        Return a :class:`random.Random` object for current test method to use.
        Within an instance, multiple calls with the same name will return
        the same object.

        When first created, each RNG will be seeded with value derived from
        a global seed, the test class module & name, the current test method name,
        and the **name** parameter.

        The global seed taken from the $RANDOM_TEST_SEED env var,
        the $PYTHONHASHSEED env var, or a randomly generated the
        first time this method is called. In all cases, the value
        is logged for reproducibility.

        :param name:
            name to uniquely identify separate RNGs w/in a test
            (e.g. for threaded tests).

        :param seed:
            override global seed when initialzing rng.

        :rtype: random.Random
        tRANDOM_TEST_SEEDtPYTHONHASHSEEDi susing RANDOM_TEST_SEED=%ds
sutf-8iN(t
_random_cachet_random_global_lockRt_random_global_seedR*RR$tenvirontgettsys_rngRRtinfoR_RRrRRt_testMethodNamethashlibtsha256Rkt	hexdigestRR(	ReRRtcachetglobal_seedRRutdigestR{((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt	getRandom2s,	
	cs|jtj||\}}tj||jdkrpg|_fd}|j|nj||S(s1create temp file that's cleaned up at end of testcs;x0D](}tjj|rtj|qqW2dS(N(R$R%texiststremove(R%(tqueue(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytcleaner|s
N(	RttempfiletmkstempR$tcloset
_mktemp_queueR*Rtappend(ReRXRYtfdR%R((Rs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytmktempts

	

csyt}Wn<tk
rQ|r/nfd}|j|nX|jt||rt||}t||nt|dS(s=monkeypatch object value, restoring original value on cleanupcs)ytWntk
r$nXdS(N(tdelattrtAttributeError((tattrtobj(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytcleanups
N(RRRtsetattrRR(ReRRR{trequire_existingtwrapRPR((RRs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt	patchAttrs
N()RRRR*RRRRRR>t_TestCase__unittest_skipRRRRRRRtassertNotEqualstassertRegexMatchesRRtcatch_warningsRRRRRRRRt	threadingtLockRRRRR	RR=R(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR-sD	
				
	
+					@	tanycBseZdZdYZdYZgZgZgZgZ	gZ
dZd[d\gZededd	gZ
eZeZeZeZed
ZeZedZedZd
ZdYedZdZdZdZedYdYdZ dYdZ!dZ"dZ#dZ$dYdYdZ%dZ&edZ'edZ(dZ)dZ*dZ+dZ,edZ-d Z.d!Z/d"Z0d#Z1d$Z2d%Z3ed&Z4d'Z5d(Z6d)Z7eZ8d*Z9d+Z:ed,Z;d-Z<d.Z=d/Z>d0Z?d1Z@d2ZAd3ZBd4ZCd5ZDd6ZEd7ZFd8ZGd9ZHd:ZId;ZJd<ZKd=ZLd>ZMd?ZNd@ZOdAZPdBZQdCZRdDZSdEZTdFZUdGZVdHZWdIZXdJZYdKZZdLZ[dMZ\dNZ]edOZ^dPZ_edQZ`edRZad]ZbedTZcdUZddVeefdWYZfdXZgRS(^sbase class for testing password hash handlers (esp passlib.utils.handlers subclasses)

    In order to use this to test a handler,
    create a subclass will all the appropriate attributes
    filled as listed in the example below,
    and run the subclass via unittest.

    .. todo::

        Document all of the options HandlerCase offers.

    .. note::

        This is subclass of :class:`unittest.TestCase`
        (or :class:`unittest2.TestCase` if available).
    t	des_cryptt
6f8c114b58f2ct	md5_crypts"$1$dOHYPKoP$tnxS1T8Q6VVn3kpV8cN6o.tsha512_cryptsx$6$rounds=123456$asaltof16chars..$BtCwjqMJGx5hrJhZywWvt0RLE8uZ4oPwcelCjmw2kSYu.Ec6ycULevoBK25fs2xXgMNrCzIMVcgEJAstJeonj1ttests
\u20AC\u00A5$s€¥$cCs#dt|jddkrdSdS(Ntos_cryptRRt((RRGR*(R((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytforbidden_charactersscCs?|j}|j}t|dr;|d|jf7}n|S(NRMs
 (%s backend)(RGRRBRM(ReRGR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR
s
		ccsyx"|jD]\}}||fVq
Wx%|jD]\}}}||fVq/Wx%|jD]\}}}||fVqWWdS(s*iterate through known (secret, hash) pairsN(tknown_correct_hashestknown_correct_configstknown_alternate_hashes(Rtsecretthashtconfigtalt((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytiter_known_hashesscCs%t|j}|jj|S(s#test random sample secret/hash pair(RR,Rtchoice(Retknown((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytget_sample_hash#scCs|j||}|j|tkp-|tkd|f|jjsM|r|sWdS|spd||f}n|j|n2|rdS|sd||f}n|j|dS(s>helper to check verify() outcome, honoring is_disabled_handlers'verify() returned non-boolean value: %rNs4verify incorrectly returned True: secret=%r, hash=%rs!verify failed: secret=%r, hash=%r(t	do_verifyt
assertTrueR>R=RGtis_disabledR(ReR(R)RtnegateR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytcheck_verify+scCs!|j|td||fdS(Ns'%s() failed to return native string: %r(RRr(ReRt	func_name((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytcheck_returned_native_str>scCs|j}d|jkrd|kr|j}|j}tddr[td||d<qd}t|dddkr||8}n|d|>}td|||d<ndS(	s0subclassable method to populate default settingsRIR?R6itrounds_costtlog2iN(RGRCRdtdefault_roundsR R?RR*(ReRYRGtmntdftfactor((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytpopulate_settingsFs			
cCs|S(s?subclassable method allowing 'secret' to be encode context kwds((ReR(RY((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytpopulate_contextYscKs|j||dkr"i}n|j||}|rg}|rc|j||jdn|j||p|jj||SWdQXn"|p|jj|j	||SdS(s3call handler's hash() method with specified optionss"passing settings to.*is deprecatedN(
R=R*R>tupdateR
RRGtencrypttusingR)(ReR(tuse_encryptRGtcontexttsettingsR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt
do_encrypt^s
	
"cKs.|j||}|p|jj|||S(scall handler's verify method(R>RGtverify(ReR(R)RGRY((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR0pscCs|jj|S(scall handler's identify method(RGtidentify(ReR)((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytdo_identifyuscKs|j||jj|S(s6call handler's genconfig method with specified options(R=RGt	genconfig(ReRY((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytdo_genconfigys
cKs(|j||}|jj|||S(s4call handler's genhash method with specified options(R>RGtgenhash(ReR(R*RY((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt
do_genhash~scKsf|p|jj|}|dkr-i}n|jd|}t||j||SWdQXdS(s
        return sample hash for handler, w/o caring if digest is valid
        (uses some monkeypatching to minimize digest calculation cost)
        RwN(RGRAR*R>RiR)(ReRGRCRDR(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytdo_stub_encrypts	
sbackend not availablecCsD|j}t||r*tdr*dS|j|r=dS|jS(s
        helper for create_backend_case() --
        returns reason to skip backend, or None if backend should be tested
        R8s$only default backend is being testedN(RGRQR RSR*tBACKEND_NOT_AVAILABLE(RRORG((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt_get_skip_backend_reasons	c
Cs|j}|j}|f}|dkr7|tf7}ntd||f|tdd||fd|d|j}|j|}|rt||}n|S(NR"s
%s_%s_testRs%s (%s backend)ROR(RGRtOsCryptMixinR_RRROR(RRORGRtbasestsubclstskip_reason((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytcreate_backend_cases 			
cCstt|j|j}|j}|rrt|dsItdn|j|j|j	|j|nddl
m}|j|d|j
ddS(NRNs)handler doesn't support multiple backendsi(thandlersRssalt generator(RR#RRGRORBtRuntimeErrorRRNRMRRURR(ReRGRORU((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRs		cs|jfd}|d}|j|d|j|td|j|j|kd|jtjd|d|f|d}|j|dk	d	|j|td
|d}|j|dk	d|j|td
dS(svalidate required attributescst|dS(N(RR*(R(RG(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytgasRsname not defined:sname must be native strsname not lower-case:s^[a-z0-9_]+$s&name must be alphanum + underscore: %rRCssetting_kwds must be defined:ssetting_kwds must be a tuple:tcontext_kwdsscontext_kwds must be defined:scontext_kwds must be a tuple:N(	RGR1RRrR|RxtmatchR*R(ReRWRRDRC((RGs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_01_required_attributess	cCsr|j}|j|d|jd|}|j|d|jd||j|j|d|fdS(stest basic config-string workflow

        this tests that genconfig() returns the expected types,
        and that identify() and genhash() handle the result correctly.
        RItstubRKRws4identify() failed to identify genconfig() output: %rN(RJR6RLR0R1RH(ReR*R((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_02_config_workflows
cCs?|j}|j}|j|||j|j|jdS(stest basic using() workflowN(RGRAtassertIsNotRR(ReRGRR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_02_using_workflows	cCszd}xm|jD]b}|j|d|}|j|d|j|||j||dt|j||}|j|d|jjr|jr|j	||d|||fn |j
||d|||f|j||}|j|d|jjr9|jr9|j
||d||||fn#|j	||d	||||f|j|j|qWd
S(stest basic hash-string workflow.

        this tests that hash()'s hashes are accepted
        by verify() and identify(), and regenerated correctly by genhash().
        the test is run against a couple of different stock passwords.
        R[RBR)R3RKsBgenhash() failed to salt result hash: secret=%r hash=%r: result=%rs@genhash() failed to reproduce hash: secret=%r hash=%r: result=%rsYgenhash() failed to reproduce disabled-hash: secret=%r hash=%r other_secret=%r: result=%rsGgenhash() duplicated hash: secret=%r hash=%r wrong_secret=%r: result=%rN(
tstock_passwordsRER6R4R>RLRGR2tdisabled_contains_salttassertNotEqualRR1RH(Ret
use_16_legacytwrong_secretR(Rtother((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_03_hash_workflow"s*cCs|jdtdS(sEtest hash-string workflow with legacy .encrypt() & .genhash() methodsRbN(ReR>(Re((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_03_legacy_hash_workflowYscCs=|jtd}|j|d|jdt||jtdt||jdt|}|j|d|jjr|jr|j||n|j	|||jtdt|}|j|d|jjr
|jr
|j||n|j	|||j
|jt|dS(s#test hashes can be unicode or bytesR[R)RKN(RERvR6R4RLRGR2R`RaRR1RH(ReRRd((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_04_hash_types]scCs|j}t|ds*|jdn|j|j|jx|jD]}|j|t|j	|t
d|f|j|}|tkr|j||j
|j|qM|tkr|jt|j|qMtd||fqMWdS(stest multi-backend supportRNshandler only has one backendsinvalid backend name: %rs*has_backend(%r) returned invalid value: %rN(RGRBRRRNRMRRRRrtassertNotIntRESERVED_BACKEND_NAMESRSR>RR=RR
R(ReRGROtret((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_05_backendss"	

cCs(d|jjkr$|jdndS(Ntsaltshandler doesn't have salt(RGRCR(Re((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytrequire_saltscCs/|jt|js+|jdndS(Ns!handler doesn't provide salt info(RmRRGR(Re((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytrequire_salt_infos
c	Cs|j|j}|j}|jd
k	}|rO|jdkrO|dn|jdkrm|dn|r|j|jkr|dn|j|jkr|dn|r|j|jkr|dnd|jkr|s|j|jkrtd	|j	fn|j
rx|js<|d
nxQ|jD]+}||j
krF|d|fqFqFWn|js|dnd
S(s!validate optional salt attributesismax_salt_chars must be >= 1ismin_salt_chars must be >= 0s(min_salt_chars must be <= max_salt_charss*default_salt_size must be >= min_salt_sizes*default_salt_size must be <= max_salt_sizet	salt_sizesT%s: hash handler supports range of salt sizes, but doesn't offer 'salt_size' settings$default_salt_chars must not be emptysEdefault_salt_chars must be subset of salt_chars: %r not in salt_charss;default_salt_chars MUST be specified if salt_chars is emptyN(RnRRGt
max_salt_sizeR*t
min_salt_sizetdefault_salt_sizeRCRRt
salt_charstdefault_salt_chars(ReRRtmx_settc((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt test_10_optional_salt_attributess2
		(			cCs<|j}ddlm}t|j|t|jdS(s%calculate number of salt bits in hashi(Ri(RGRRRRrRRt(ReRGR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt	salt_bitss		csVjtddjfd}|j|fddS(s4test hash() / genconfig() creates new salt each timeiiicsS|}x-tD]}|}||krdSqWjdfdS(Ns.failed to find different salt after %d samples(RR(Rtvalue1R2tvalue2(tsamplesRe(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytsamplers			cs
jdS(NR[(RE((Re(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt<lambda>sNi(RmR?RxRJ(ReR|((R{Res7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_11_unique_salts


cCs|j|j}|jdd!}|j}||}|jd||jdd||dkr|jt|jd|d n|jt|jdd|ddS(s.test hash() / genconfig() honors min_salt_sizeiiRlR[RoiN(RnRGRsRqRJRERt
ValueError(ReRGt	salt_chartmin_sizets1((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_12_min_salt_sizes
		
c	
Cs|j|j}|j}|jdd!}|d	ksD|dkr|d}|jd|}|jd||}|j|||jddn||}|jd|}|jd|||}|jt|jd||jt|jd|dt	|rUt
jdt|jd|dt}Wd	QX|j
||n|j|kr|jd|d
 }|j||nd	S(s.test hash() / genconfig() honors max_salt_sizeiiiiRlRoRRANii(RnRGRpRsR*RMRaRRRHRRR>RRq(	ReRGtmax_sizeRRtc1tc2ts2tc3((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_13_max_salt_sizes.
		


cCs/|jr+ddlm}|j|}n|S(sprepare generated salti(tbcrypt64(tfuzz_salts_need_bcrypt_repairtpasslib.utils.binaryRt
repair_unused(ReRlR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytprepare_saltQs	c

Cs!|j|j}|j}|j}|j}t|t}x`t||pOdD]I}t||kr}t	||}n|j
|}|jd|qSWtd}|r|j
d}nt|d}xG|D]?}	|	|kr|jt|jd|	|dd|	fqqWdS(	stest hash() honors salt_charsi Rltslatin-1iRsinvalid salt char %r:N(RnRGRpRqRsR\tbytesRRRRRMRRkR?RR(
ReRGtmxR:tcstrawRlRutchunkRv((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_14_salt_charsXs&
				
cCs!t|jdtrtStSdS(s)hack to determine salt keyword's datatypet_salt_is_bytesN(RRGR=RR(Re((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt	salt_typessc
Cs|j|j}t|jddp+d}dtfdY}|jt|jdd||tk	r|jt|jddt	d|n|t
kpto|tks|jt|jddd|nd	S(
stest non-string salt valuesRqiitfakecBseZRS((RR(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRsR[RltxN(RmRRRGtobjectRRRERRRR(ReRRoR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_15_salt_type|s
	)c
Cs|j|j}|j}|j}|j}|jt|jdd|jt	g|jdddt
}WdQX|j|j||r|jt|jd|d|jt	g!|jd|ddt
}WdQX|j|j|n||kr|jd|d}|j|j|d|j|j||jd|d}|j|j|d|j|j|n||kr|}n
|d}|jdt|}|j|j||jt|jdt|d|jd|}|j|j|dS(	s$Handler.using() -- default_salt_sizeRriRANiitxxxRo(
RnRGRqRpRrRRRARRR>RRr(ReRGR:RR;ttemptref((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_using_salt_sizes:
				"	
#cCs%t|js!|jdndS(Nshandler lacks rounds attributes(RRGR(Re((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytrequire_rounds_infoscCs|j|j}|j}|jd
kr:|dn|jdkrX|dn|jdkrv|dn|j|jkr|dn|jd
k	r|j|jkr|dn|j|jkr|dqn|jtkr|d	|jfnd
S(s#validate optional rounds attributessmax_rounds not specifiedismax_rounds must be >= 1ismin_rounds must be >= 0s min_rounds must be <= max_roundss$default_rounds must be >= min_roundss$default_rounds must be <= max_roundss unknown rounds cost constant: %rN(	RRGRt
max_roundsR*RdR9R7R(ReRR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt"test_20_optional_rounds_attributess$
		cCs|j|j}|j}|jd||jdd||jt|jd|d|jt|jdd|ddS(s+test hash() / genconfig() honors min_roundsRIR[iN(RRGRdRJRERR(ReRGRd((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_21_min_roundss
		cCs|j|j}|j}|dk	rh|jt|jd|d|jt|jdd|dn|dkr|jddn|jd|dS(s+test hash() / genconfig() honors max_roundsRIiR[iNIi(	RRGRR*RRRJRERM(ReRGR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_21b_max_roundss
		#c

s?|j|j}|jdkrO||j}tfd|_n|j}|j}|j}|psd|d}||kr|d7}n||d}|pd|d}|jdkr|dO}|dO}|dO}d}nd}|j	g#|jd|d|d|}	Wd	QX||	||||fS(
sU
        setup test helpers for testing handler.using()'s rounds parameters.
        t
bsdi_cryptcst|jS(N(Rt_generate_rounds(R(torig_handler(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR}si'iitmin_desired_roundstmax_desired_roundsR9N(
RRGRRAtclassmethodRRdRR9R(
ReRGtorig_min_roundstorig_max_roundstorig_default_roundstmediumtsmalltlargetadjRR((Rs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt_create_using_rounds_helper
s4
				



		c
Cs|j|j}|j}|j}|j}|j\}}}}}}	|j|j||j|j||j|jd|j|j	d|j|j||j|j||j|j||j|j||j|j||j|j	|dS(s@
        HasRounds.using() -- sanity check test harness
        N(
RRGRdRR9RRRR*R(
ReRGRRRRRRRRR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_has_rounds_using_harness5s 
				c
Cs|j\}}}}}}|j}|j}|j}	|dkr|jt|jd|||jtg!|jd||dt	}
WdQX|j
|
j|n|r|jt|jd|||jtg!|jd||dt	}
WdQX|j
|
j|n|jg|jd||}
WdQX|j
|
j|||jd|d|}
|j
|
j|d||jg|jd||}
WdQX|j
|
j|||j
t||||||j
t||||jg&|j
t|||||WdQX|jd|}
|j
|
j||jdt
|}
|j
|
j||jt|jdt
|ddS(sF
        HasRounds.using() -- min_rounds / min_desired_rounds
        iRRANiRdR(RRdRR9RRRARRR>RRRLRr(ReRGRRRRRRRRRR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt"test_has_rounds_using_w_min_roundsOs>			""!'c

Cs|j\}}}}}}|j}|j}|dkr|jt|jd|||jtg!|jd||dt}	WdQX|j	|	j
|n|r|jt|jd|||jtg!|jd||dt}	WdQX|j	|	j
|n|jtg|jd||}	WdQX|j	|	j
||jt|jd||d|||jd|d|}	|j	|	j|d||jg|jd||}	WdQX|j	|	j
|||j	t
||||||j	t
||||jg&|j	t
|||||WdQX|jd|}	|j	|	j
||jdt|}	|j	|	j
||jt|jdt|ddS(	sF
        HasRounds.using() -- max_rounds / max_desired_rounds
        iRRANRiRR(RRdRRRRARRR>RRRRRLRr(
ReRGRRRRRRRRR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt$test_has_rounds_replace_w_max_roundssB		""
!'c	CsM|j\}}}}}}|j}|jd||}|j|j|||jd||}|j|j|||jt|jd|||r|jt|jd||n|jt|||jt||||||jdt|}|j|j||jt|jdt|ddS(s5
        HasRounds.using() -- default_rounds
        RdRR9RN(	RRRARR9RRRLRr(	ReRGRRRRRRRR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt&test_has_rounds_using_w_default_roundss	 !c	
Cs|j\}}}}}}|j}|jd||}|j|j|||j|j|||j|j|||jd|dd||d|d||}|j|j|||j|j||j|j||dS(s-
        HasRounds.using() -- rounds
        RIiRdR9RN(RRRARRR9R(	ReRGRRRRRRRR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_has_rounds_using_w_roundss	cs|j\}}}}}fd}|j|dd|j|dd|j|dd|j|dd|j|dd|jt|d|jt|dd	S(
s:
        HasRounds.using() -- vary_rounds parsing
        csjd|jS(Ntvary_rounds(RAR(R{(RR(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytparsesg?s0.1s10%it1000gg?N(RRRR(ReRGRRRRR((RRs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt+test_has_rounds_using_w_vary_rounds_parsingsc	szj\}}}}}dfd}|d|||d|||||||||dt||dt||d|jdkr|d|||d|||d	|||njd
d	\}}j|t||dj|t||dj|t||d
j|t||ddS(s=
        HasRounds.using() -- vary_rounds generation
        cs8tfdtdD}t|t|fS(Nc3s|]}tVqdS(N(RL(R1R2(R(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pys	<genexpr>si(tsetRR3R?(Rtseen((Rs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytget_effective_ranges"csNjd|}|\}}j||dj||ddS(NRs"vary_rounds had wrong lower limit:s"vary_rounds had wrong upper limit:(RAR(RR|R}Rt
seen_lowert
seen_upper(RReRR(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytassert_rounds_range!sis0%i2R8s1%s49%s50%Rg?g?g333333?g?N(RR?R3R7RAtassertGreaterEqualtassertLessEqual(	ReRGRRRRRR|R}((RReRRs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt.test_has_rounds_using_w_vary_rounds_generations 	*cCs|j\}}}}}}|jd|dd|d}|j|d|}|j|d|}	|j|d|}
|j|j||j|j|	|j|j|
|j|j||j|j|	|j|j|
dS(sF
        HasRounds.using() -- desired_rounds + needs_update()
        RiRRIN(RRARMtassertFalsetneeds_updateR1(ReRGRRRRRRRt
small_hashtmedium_hasht
large_hash((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt&test_has_rounds_using_and_needs_update@s cCsB|j}t|ts,t|tjr>|jdndS(Ns)handler doesn't derive from HasManyIdents(RGR\R_RDREt
HasManyIdentsR(ReRG((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytrequire_many_identsZs	#cCs|j}|j|jd|jkx$|jD]}|j|tdq3W|jt|jdkd|j|jtd|j|j|jkd|j	rxft
|j	D]R\}}|j|td|j|td|j||jkd	|fqWn|}|jd}|j|}|d=|d|j||j
t|||d
t||j
t|dd|dS(
s$validate HasManyIdents configurationtidents!cls.ident_values must be unicode:is'cls.ident_values must have 2+ elements:s"cls.default_ident must be unicode:s9cls.default_ident must specify member of cls.ident_valuess'cls.ident_aliases keys must be unicode:s)cls.ident_aliases values must be unicode:s:cls.ident_aliases must map to cls.ident_values members: %rRJtxXxN(RGRR1RCtident_valuesRRRt
default_identt
ident_aliasesRR/t	parsehashRRR>R(ReRR{taliasRRGR)RY((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_30_HasManyIdents_s8	
	cCs|j|j}|j}x:|jD]}||kr&Pq&q&Wtd||jfd}|j}|j|j||jd|}|j|j||j|j||j||||j||||jt|jdd|jd|}|j|j||j|j||jt	|jd|d||j
rxO|j
jD];\}}|jd|}|j|j|dd|qnWndS(	s=HasManyIdents.using() -- 'default_ident' and 'ident' keywordss6expected to find alternate ident: default=%r values=%rcSst|}|dtjS(NRJ(RKR>R(R((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyteffective_identsRRRRs	alias %r:N(RRGRRRRARRRRRtitems(ReRGt
orig_identt	alt_identRRRRR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_has_many_idents_usings2
				cs|jjdkr/|jdjdSjsK|jjndjkrn|jjdSfd}|j	|dj|j	|t
t
|j	|dt
|j	|tt|j	|dt|jt
|ddS(sH
        validate 'truncate_error' setting & related attributes
        ttruncate_errorNcsjd|jS(NR(RAR(R{(thasher(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytparse_valuesttruetfalseR(RGt
truncate_sizeR*RhRCRRttruncate_verify_rejectR1RR>R=RR(ReR((Rs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_truncate_error_settings 		cCs|j}|jd
k	r=|j|jd|jdndd}d}|j|}|j}|j|j|||dd|d |}|j	|j||d	d
S(sO
        test no password size limits enforced (if truncate_size=None)
        istruncate_size is setstoo many secretsiRRsverify rejected correct secretis full password not used in digestN(
RGRR*RRRER2RR0R(ReRR(R+R)tverify_successt
alt_secret((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_secret_wo_truncate_sizes		

cCsF|j}|j}|s*|jdntj}d|jkrr|jdt}|jdt}tj	}n$|j
rd	}|}n|}d	}d}d}t||d}|d }	|d |}
|	d |}|j
}|o|j}
x||gD]}|j|	d|}|j|j|	|d|||j|j||d|d|j|j||d||
qW|r|j|d|}|j|j||d|||j|j|
|d|||j|j|	|d|n|rB|j||j|d|}|j|j|nd	S(
sQ
        test password size limits raise truncate_error (if appropriate)
        struncate_size not setRstoo many secretsRiiRGs truncate_size value is too largeN(RGRRR	tPasswordSizeErrorRCRAR=R>tPasswordTruncateErrorRR*RR2RRERR0RR1RR(ReRGRtsize_error_typet
without_errort
with_errorRbR+tlong_secrettshort_secrettalt_long_secrettalt_short_secrettshort_verify_successtlong_verify_successtcand_hashert
short_hasht	long_hashR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_secret_w_truncate_sizes`					



cCsE|jtk}|jtdgk}d}d}|j|}|rq|jjrq|j|j||dn|j|j||d|j|}|r|jjr|j|j||dn|j|j||d|j||}|s|jjr.|j	r.|j
||dn|j||ddS(	stest password case sensitivitysverify-onlyR!tTESTs%verify() should not be case sensitives!verify() should be case sensitives&genhash() should not be case sensitives"genhash() should be case sensitiveN(tsecret_case_insensitiveR>RERGR2R1R0RRLR`RRa(Rethash_insensitivetverify_insensitiveR|R}th1th2((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_61_secret_case_sensitivets.	


cCs|jd}|jt|jd|jt|jd||jt|jd||jt|jd|jt|jd||jt|jd|dS(s&test non-string passwords are rejectediN(R/RRRER*RLR0(ReR)((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_62_secret_borderscCsddlm}ddlm}dd|}|jd}|j||j||}|j|j||j||j	||j||j
||dS(s"test MAX_PASSWORD_SIZE is enforcedi(R(tMAX_PASSWORD_SIZEt.iN(tpasslib.excRRRR/RRLRRRER0(ReRRR(R)R((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_63_large_secretscCs|j}|s!|jdntd}t|trjddlm}||}|jd}nx,|D]$}|jt	|j
|||qqWdS(s1test forbidden characters not allowed in passwordsnone listedR[i(titer_byte_charstasciiN(R$RRR\Rtpasslib.utils.compatRRkRRRE(RetcharsRbRRv((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_64_forbidden_charss	
cCs|j|i}t|S(N(R>R(ReR(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytis_secret_8bitscCsQtrM|jdkrMt|trMy|jdWqMtk
rItSXntS(sl
        check if we're expecting potential verify failure due to crypt.crypt() encoding limitation
        R"sutf-8(RROR\RRsRtR>R=(ReR(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytexpect_os_crypt_failures$
c
CsL|j|jp|jdt}x	|jD]\}}|j|rSt}n|j|j|d|f|j|}y|j	||d||f|j
||}|j|td|f|j
jr|jrw/n|j||d|||fWq/tk
r)|s*q*q/Xq/W|sHtd|jndS(stest known hashessOtest must set at least one of 'known_correct_hashes' or 'known_correct_configs's&identify() failed to identify hash: %rs1verify() of known hash failed: secret=%r, hash=%rs,genhash() failed to return native string: %rsGgenhash() failed to reproduce known hash: secret=%r, hash=%r: result=%rs%s: no 8-bit secrets testedN(R1R%R&R=R,RR>RHRR4RLRRrRGR2R`RR
Rt	__class__(Retsaw8bitR(R)RR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_70_hashess0	
c
Cs|js|jdnx|jD]\}}}|j|j|d|f|j||d||f|j||}|j|td|f|jj	r|j
rq%n|j||d||||fq%WdS(stest known alternate hashessno alternate hashes provideds0identify() failed to identify alternate hash: %rs;verify() of known alternate hash failed: secret=%r, hash=%rs,genhash() failed to return native string: %rsYgenhash() failed to normalize known alternate hash: secret=%r, alt=%r, hash=%r: result=%rN(R'RR1RHR4RLRRrRGR2R`R(ReR+R(R)R((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_71_alternatess	c	Cs!|jjs1|j|jd|jdn|jsL|jdn|jrktjddtnx|jD]\}}}|j	|j
|d|f|jt|j
||dd|f|j||}|j|td	|f|j||d
||||fquWdS(stest known config stringss&handler should not have config stringsshash has no settingssno config strings providedRRs5identify() failed to identify known config string: %rRs+verify() failed to reject config string: %rs,genhash() failed to return native string: %rs^genhash() failed to reproduce known hash from config: secret=%r, config=%r, hash=%r: result=%rN(RGRCRR&Rtfilter_config_warningsRRRR1RHRRR0RLRRrR(ReR*R(R)R((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_72_configs	s(		c	Cs|js|jdnx}|jD]r}|j|j|d|f|jt|jd|dd|f|jt|jd|dd|fq%WdS(s)test known unidentifiably-mangled stringssno unidentified hashes provideds?identify() incorrectly identified known unidentifiable hash: %rR[Rs:verify() failed to throw error for unidentifiable hash: %rs;genhash() failed to throw error for unidentifiable hash: %rN(tknown_unidentified_hashesRRRHRRR0RL(ReR)((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_73_unidentified;	s	c	Cs|js|jdnx}|jD]r}|j|j|d|f|jt|jd|dd|f|jt|jd|dd|fq%WdS(s-test known identifiable-but-malformed stringssno malformed hashes provideds6identify() failed to identify known malformed hash: %rR[Rs5verify() failed to throw error for malformed hash: %rs6genhash() failed to throw error for malformed hash: %rN(tknown_malformed_hashesRR1RHRRR0RL(ReR)((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_74_malformedP	s	c
Cs:|jr|jdn|js6|jdnx|jD]\}}||jjkr|j|j|d|f|jd||jd|}|j	|t
d|fq@|j|j|d||f|jt
|jd|dd||f|jt
|jd|dd	||fq@Wd
S(stest known foreign hashessnot applicablesno foreign hashes provideds,identify() failed to identify known hash: %rR[s,genhash() failed to return native string: %rs:identify() incorrectly identified hash belonging to %s: %rRs;verify() failed to throw error for hash belonging to %s: %rs<genhash() failed to throw error for hash belonging to %s: %rN(taccepts_all_hashesRtknown_other_hashesRGRR1RHR0RLRRrRRR(ReRR)R((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_75_foreigne	s*		cCsv|jt|jd|jt|jdd|jt|jdd|jt|jd|jt|jdd|jt|jddxtddgD]}|jr|j|j||jd||jd|}|j	|dq|j
|j|d|jt|jd|dd|jt|jd|ddqW|jd	|jd
dS(s#test non-string hashes are rejectedR[iRwRKs,identify() incorrectly identified empty hashRs$verify() failed to reject empty hashs%genhash() failed to reject empty hashs€¥$sabcN(RRRHR*R0RLRRR1R6RR(ReR)R((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_76_hash_border	s(	
c	sp|jjr|jdnddlm}|j}|dkrU|jdn|jd|}d|rtjj	}nd}|j
d	|}|j||}tj
d
|j||t|djfd|D|}||}	d}
x=||	krH|j}|d
}|d}
|d}|d}|rb||d<n|j||}x|D]}|}||||}|dkrq{n|s|jd||||fn|jdkr{||
||}|r7|dkr7|jd||
|||fq7q{q{W|
d7}
qWtj
d|j||||
dS(sfuzz testing -- random passwords and options

        This test attempts to perform some basic fuzz testing of the hash,
        based on whatever information can be found about it.
        It does as much as it can within a fixed amount of time
        (defaults to 1 second, but can be overridden via $PASSLIB_TEST_FUZZ_TIME).
        It tests the following:

        * randomly generated passwords including extended unicode chars
        * randomly selected rounds values (if rounds supported)
        * randomly selected salt sizes (if salts supported)
        * randomly selected identifiers (if multiple found)
        * runs output of selected backend against other available backends
          (if any) to detect errors occurring between different backends.
        * runs output against other "external" verifiers such as OS crypt()

        :param report_thread_state:
            if true, writes state of loop to current_thread().passlib_fuzz_state.
            used to help debug multi-threaded fuzz test issues (below)
        snot applicablei(Risdisabled by test modetthreadedcSs|jp|jjdS(Ni(RRt
splitlines(tv((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytvname	ss	fuzz testRs.%s: %s: started; max_time=%r verifiers=%d (%s)s, c3s|]}|VqdS(N((R1R(R(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pys	<genexpr>	sR(RdRDRCRsAfailed to verify against %r verifier: secret=%r config=%r hash=%rg?s\was able to verify wrong password using %s: wrong_secret=%r real_secret=%r config=%r hash=%ris!%s: %s: done; elapsed=%r count=%rN(RGR2RRRt
max_fuzz_timetget_fuzz_verifiersRtcurrent_threadRRtFuzzHashGeneratorRtdebugRRRtgenerateRERR(ReRRtmax_timet	verifierstthread_nameRt	generatorR-tstopRtoptsR(RdRDRR)RFRR((Rs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_77_fuzz_input	sX			 	






		#	csjdddljjr7jdnj}|dks[jdkrmjdnjdgfdfd	}gt|D]}||^q}j|d
}d}xM|D]E}|j	||j
sqntjd|j
||d7}qWdr_jdd|fn|rjd
||fndS(smultithreaded fuzz testing -- random password & options using multiple threads

        run test_77 simultaneously in multiple threads
        in an attempt to detect any concurrency issues
        (e.g. the bug fixed by pybcrypt 0.3)
        R8iNsnot applicableiisdisabled by test modecsRyjdtWn7tk
r'n'dcd7<WdQXnXdS(NRii(R%R>R((tfailedtfailed_lockRe(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRf*
s
cs@d|f}jdd|}|jt|j|S(NsFuzz-Thread-%dttargetR(tThreadt	setDaemonR>R-(tnRtthread(RRf(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytlaunch3
s



is%s timed out after %f secondssH%d/%d threads failed concurrent fuzz testing (see error log for details)sP%d/%d threads stalled during concurrent fuzz testing (see error log for details)(RRRGR2Rtfuzz_thread_countRRRRtis_aliveRterrorRtfail(Retthread_countR-R+tthreadsttimeouttstalledR,((R&R'ReRRfs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_78_fuzz_threading
s4
			%


		cCsVttjjdpd}|r(|Stddr;dStddrNdSdSdS(	s'amount of time to spend on fuzz testingtPASSLIB_TEST_FUZZ_TIMEiR?R6R7iiN(tfloatR$RRR (ReR{((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRR
scCsCttjjdpd}|r(|Stddr;dSdSdS(s+number of threads for threaded fuzz testingtPASSLIB_TEST_FUZZ_THREADSiR?R6i
N(RR$RRR (ReR{((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR._
stfuzz_verifier_defaultcs|jg}x?|jD]4}t||}|dk	r|j|qqWtdrtdr|rfd}x*tD]}|j||qWn|S(sreturn list of password verifiers (including external libs)

        used by fuzz testing.
        verifiers should be callable with signature
        ``func(password: unicode, hash: ascii str) -> ok: bool``.
        RRR8cs4fd}dd|_d|_|S(NcsBj}z!jj||SWdj|XdS(N(RMRNRF(R(R)torig_backend(RORG(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR
s

tcheck_t_backends-backend(RR(ROR(RG(ROs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytmaker
s
N(RGtfuzz_verifiersRR*R
RBR RW(ReRR tmethod_nameRR>RO((RGs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRs
s	"cs8fd}jr+jd|_n	d|_|S(Ncsj|||S(N(R0(R(R)R(Re(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt
check_default
ss-backendRe(ROR(ReRA((Res7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR:
s
		RcBseZdZedZdZeddddddZiZd	Z	d
Z
dZdZd
Z
dZdZdZdZRS(s
        helper which takes care of generating random
        passwords & configuration options to test hash with.
        separate from test class so we can create one per thread.
        s.qwertyASDF1234<>.@*#! \u00E1\u0259\u0411\u2113sutf-8RIt
random_roundsRotrandom_salt_sizeRtrandom_identcCs"||_|j|_||_dS(N(R!RGR(ReR!R((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR
s	c
sRfd}j\}}td|d|d|jd|jS(s
            generate random password and options for fuzz testing.
            :returns:
                `(secret, other_secret, settings_kwds, context_kwds)`
            csai}xT|jD]F\}}t|}t|}|dk	r|||<qqW|S(N(RRR*(tmaptouttkeytmethRR{(Re(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytgendict
sR(RdRDRC(trandom_password_pairRtsettings_maptcontext_map(ReRIR(Rd((Res7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR
scCs+|jj||}tt|||S(s)generate random int w/ gauss distirbution(Rt
normalvariateRR~(ReR|R}tmutsigmaR{((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytrandintgauss
scCs||j}t|sdS|jp(|j}|j}|jdkrL|}nt|d|j}|j||||dS(NR8ig?(	RGRR*R9RdR7R3RRP(ReRGR7R|R}((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRB
s			cCsg|j}t|o!d|jks(dS|j}|j}|jpJ|d}|j||||dS(NRoig?(RGRRCR*RrRqRpRP(ReRGR7R|R}((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRC
s			cCsm|j}|j}d|jks1t|dr5dS|jdkrKdSt|d|}|j|jS(NRRg?R[(	RRGRCRBR*RRR-R(ReRRG((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRD
s		cCs|j}x,tr:|j}|j||rPqqW|j}|jddrk|j|j}n|jddr|j|j}n||fS(s=generate random password, and non-matching alternate passwordii(trandom_passwordR>taccept_password_pairRtrandintRktpassword_encoding(ReR(RdR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRJs		cCs|j}|jdkr%tdS|j}|jo=|j}|pId}|dksj|jdkr|jdt|ddd}n!|jdt|dd	d
}t||j	|}|rt
|trx,t|j
d|kr|d }qWn|S(
s*generate random passwords for fuzz testingg-C6?Rwi?Bi2g?iiiciFisutf-8i(RRRRGRRRPR3Rtpassword_alphabetR\RRRk(ReRRGRRtsizeR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRQs	
	$!cCs
||kS(s-verify fuzz pair contains different passwords((ReR(Rd((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRR7s(RRRRRURTRRKRLRRRPRBRCRDRJRQRR(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR
s 											cCs|j}|js`|jt|d|jt|d|j|j|jdn|j}|j|tdd|j	|j
|dd||jj|j
d}|j|}|j|tdd|j	|j
|dd||jtd|j|y|j|}d}Wntk
rV}d}|}nX|dkr|j|tdd	|j||n&|j|t|jdt||j}|jr|j||n|dkr|j||n|j|}	|jr$|j|	|n|j|	||j|d
}
|js\|dkro|j|
|n|j|
|dS(s.disable() / .enable() methodstdisabletenablesnot applicableRs#disable() must return native strings0identify() didn't recognize disable() result: %riscannot restore original hashs"enable() must return native stringRN(RGR2RRBR`RRWRRrR1RGRR-RtassertRaisesRegexRRXR*RRRa(ReRGtdisabled_defaultR[t
disabled_stubRR0tetdisabled_default2tdisabled_stub2tdisabled_other((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_disable_and_enableCsX		


		N(RR(Rs"$1$dOHYPKoP$tnxS1T8Q6VVn3kpV8cN6o.(R sx$6$rounds=123456$asaltof16chars..$BtCwjqMJGx5hrJhZywWvt0RLE8uZ4oPwcelCjmw2kSYu.Ec6ycULevoBK25fs2xXgMNrCzIMVcgEJAstJeonj1(sfuzz_verifier_default(hRRRR*RGROR%R&R'R
RRRR_R=RRR`RRR$R>t_HandlerCase__unittest_skiptpropertyRRR,R/R4R6R=R>RER0RHRJRLRMRNRORTRRZR\R^ReRfRgRkRmRnRwRxR~RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR	R
RRRRRR%R6RR.R?RR:RRR`(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR#s
				

							
		 	)		7		#	,			)			6					2					+		8	<	&			)			3	4	!	 	m	&						,		#			&	.Y	@
$	
RPcBseZdZgZeZdZeZdZ	e
ZdZe
dZdZe
dZdZdZdZd	Zd
ZdZRS(
shelper used by create_backend_case() which adds additional features
    to test the os_crypt backend.

    * if crypt support is missing, inserts fake crypt support to simulate
      a working safe_crypt, to test passlib's codepath as fully as possible.

    * extra tests to verify non-conformant crypt implementations are handled
      correctly.

    * check that native crypt support is detected correctly for known platforms.
    R"cCs6|jjds|jntt|jdS(NR"(RGRSt_patch_safe_cryptRRPR(Re((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRs
cCsD|j}|s!t|j}n|jt|d}||fS(s
        return (handler, backend) pair to use for faking crypt.crypt() support for hash.
        backend will be None if none availabe.
        R"(talt_safe_crypt_handlerRKRGRMRZ(RRGtalt_backend((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt_get_safe_crypt_handler_backends	
cs~|j\}}|s'tdn|jj|fd}ddlj}|j|d|t|_dS(sif crypt() doesn't support current hash alg, this patches
        safe_crypt() so that it transparently uses another one of the handler's
        backends, so that we can go ahead and test as much of code path
        as possible.
        s,handler has no available alternate backends!csj||}|S(N(RK(R(R)(talt_handler(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt
crypt_stubsiNt_crypt(	RfRRARNRtutilsRR>tusing_patched_crypt(ReRGReRhtmod((Rgs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRcs
cCshtt|j|}ddlm}||jkrd|rdtdr]|jdr]dSdSn|S(s|
        make sure os_crypt backend is tested
        when it's known os_crypt will be faked by _patch_safe_crypt()
        i(t	has_cryptR8is hash not supported by os crypt()N(	RRPRORRmRNR RfR*(RROtreasonRm((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyROscsJddlj}fd|j_d_|j|dS(s
        patch passlib.utils.safe_crypt() so it returns mock value for duration of test.
        returns function whose .return_value controls what's returned.
        this defaults to None.
        iNcs'|dkrj||SjSdS(NR!(t__wrapped__treturn_value(R(R*(t
mock_crypt(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRqsRi(RRjRiRoR*RpR(ReRl((Rqs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt_use_mock_crypts	csojdtfjfd}|dd|d |ddS(stest with faulty crypt()icsU|_jjdjjdjjddS(NR[(RpRRLRER0(R{(t	exc_typesR)RqRe(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR!/s	s$xiiRN(R/RRr(ReR!((RsR)RqRes7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_80_faulty_crypt)s	cCs|j}d|_|jrk|jd}|jd|}|j|||j|jd|nhddl	m
}|jd}|j||jd|j||jd||j||jd|dS(stest per-call crypt() fallbackR[i(R
iN(
RrR*Rpthas_os_crypt_fallbackRERLRR1R0RR
R/R(ReRqRRR
R)((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_81_crypt_fallback;s		cCst|jdr$|jdntj}x@|jD]"\}}tj||r7Pq7q7W|jd||dkr|jd|nV||j	krdS|r|j
d||jjfn|j
d||jjfdS(s0test platform-specific crypt() support detectionR@snot applicable to wrapperssno data for %r platformsvaried support on %r platformNs5expected %r platform would have native support for %rs;did not expect %r platform would have native support for %r(RBRGRtsystplatformtplatform_crypt_supportRxRYR*RkR1R(ReRxtpatterntstate((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_82_crypt_supportPs 			csZj}js!t|dr%dSddlmjjfd}|S(stest results against OS crypt()R[i(tcryptcs5j|sdSt|}|||kS(sstdlib-cryptR(tcrypt_supports_variantR(R(R)(R}tencodingRe(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytcheck_cryptysN(RGRkRBR*R}RRT(ReRGR((R}RRes7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytfuzz_verifier_cryptls	cCstS(s~
        fuzzy_verified_crypt() helper --
        used to determine if os crypt() supports a particular hash variant.
        (R>(ReR)((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR~sN(RRRRyR>RuR*Rdt_OsCryptMixin__unittest_skipROR=RkRRRfRcRORrRtRvR|RR~(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRPs"							tUserHandlerMixincBsceZdZdZeZeZeZdZ	dZ
dZdZde
jfdYZRS(s(helper for handlers w/ 'user' context kwd; mixin for HandlerCase

    this overrides the HandlerCase test harness methods
    so that a username is automatically inserted to hash/verify
    calls. as well, passing in a pair of strings as the password
    will be interpreted as (secret,user)
    tusercCs|j}d}|j|d|j}|jr{|jt|j||jt|j|||jt|j||n-|j||j|||j||dS(stest user context keywordR[RN(RGR)tdefault_usert
requires_userRRRKRF(ReRGtpasswordR)((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_80_users		
cCs|jj}|j}|jddtd|}|jrg|j|jd|d|dn"|j|jd|d|ddS(stest user case sensitivityR[RCRs!user should not be case sensitivesuser should be case sensitiveN(	RR|R}RERtuser_case_insensitiveR1R0R(ReR|R}R)((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_81_user_cases	
cCsx|j}|jd|dd}|jd|dd}|j|||jd|dd}|j||dS(stest user used as saltR[RtadmintrootN(RMRLRRa(ReR*RRth3((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_82_user_saltscCsQt|tr|\}}n|js+|S|j}d|krM||d<n|S(sinsert username into kwdsR(R\RRR(ReR(RYR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR>s		
RcBs?eZejjjZejddedZdZ	RS(Rtrandom_usert	asdQWE123cCsK|j}|jjr,|jdkr,dSt||j|jddS(Ng?ii
(RR!RRR*Rt
user_alphabetRS(ReR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRs	(
RRR#RRLtcopyR?RRR(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRs(RRRRR>RR=Rt _UserHandlerMixin__unittest_skipRRRR>R#R(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRs				tEncodingHandlerMixincBsQeZdZeZeddedgZdejfdYZdZ	RS(s helper for handlers w/ 'encoding' context kwd; mixin for HandlerCase

    this overrides the HandlerCase test harness methods
    so that an encoding can be inserted to hash/verify
    calls by passing in a pair of strings as the password
    will be interpreted as (secret,encoding)
    R!s\u00AC\u00BARcBseZedZRS(sqwerty1234<>.@*#! \u00AC(RRRRU(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR
scCs2t|tr.|\}}|jd|n|S(sinsert encoding into kwdsR(R\Rt
setdefault(ReR(RYR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR>
s(
RRRR>t$_EncodingHandlerMixin__unittest_skipRR_R#RR>(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRs	RcBs/eZdZdddZdZdZRS(s@catch_warnings() wrapper which clears warning registry & filterstalwayss.*cKsAtt|j|||_|r4tj|nd|_dS(N(RRRt
_reset_filterRxtcompileR*t_reset_registry(Retreset_filtertreset_registryRY((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR
s	cCstt|j}|jr;tjtj|jn|j}|ri}|_x}t	t
jjD]c\}}|dksm|j|rqmnt|dd}|rm|j||<|jqmqmWn|S(Nt__warningregistry__(RRRRRt
resetwarningstsimplefilterRt_orig_registryRRwtmodulesRR*RYRRtclear(ReRjRztbackupRRltreg((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR
s	
	
"cGs|j}|r|j}xttjjD]\}}|dks.|j|r\q.nt|dd}|r|j	n|j
|}|r.|dkrt|d|q|j|q.q.Wnt
t|j|dS(NR(RRRRwRRR*RYRRRRR?RRR(ReRRzRRRlRRP((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR3
s		"
(RRRRRR(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR
s	(kRt
__future__RtbinasciiRt
contextlibt	functoolsRRRtloggingt	getLoggerRRRRxR$RwRRR'RRRRRRRRtpasslibR	R
tpasslib.registrytregistrytpasslib.tests.backportsRt	_TestCaseRR
RRRRRRRRRRRRRRRRRRRtpasslib.utils.decorRtpasslib.utils.handlersRjRUREt__all__tgoogle.appenginetgoogletImportErrorR=RR>R,R5tTICK_RESOLUTIONR;R<RRtstripR|R:R*R RHRLRQRWRZRKRctcontextmanagerRiR!R"RvRzR~RRRRiR#RPRRRR(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt<module>s(F(		

								!						t	a&
Back to Directory File Manager