Create python bindings.
CVS patchset: 6856 CVS date: 2003/05/17 19:27:47
This commit is contained in:
parent
fb3f3b2e97
commit
bba59fdb64
|
@ -36,7 +36,7 @@ AUTOMAKE_OPTIONS = gnu check-news no-dependencies
|
|||
|
||||
LINT = splint
|
||||
|
||||
SUBDIRS = docs gas masm mwerks tests
|
||||
SUBDIRS = docs gas masm mwerks python tests
|
||||
|
||||
SUFFIXES = .s
|
||||
|
||||
|
|
|
@ -669,5 +669,7 @@ AC_CONFIG_FILES([Makefile
|
|||
gas/Makefile
|
||||
masm/Makefile
|
||||
mwerks/Makefile
|
||||
python/Makefile
|
||||
python/test/Makefile
|
||||
tests/Makefile])
|
||||
AC_OUTPUT
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
.deps
|
||||
.libs
|
||||
Makefile
|
||||
Makefile.in
|
||||
*.la
|
||||
*.lo
|
||||
*.pyc
|
|
@ -0,0 +1,40 @@
|
|||
# Makefile for rpm library.
|
||||
|
||||
AUTOMAKE_OPTIONS = 1.4 foreign
|
||||
|
||||
LINT = splint
|
||||
|
||||
PYVER= 2.2
|
||||
|
||||
pylibdir = $(shell python -c 'import sys; print sys.path[1]')
|
||||
pyincdir = $(prefix)/include/python${PYVER}
|
||||
|
||||
EXTRA_DIST = bcdebug-py.c
|
||||
|
||||
INCLUDES = -I. \
|
||||
-I$(top_srcdir) \
|
||||
-I$(pyincdir)
|
||||
|
||||
noinst_HEADERS = mpw-py.h rng-py.h
|
||||
|
||||
mylibs= $(top_builddir)/.libs/libbeecrypt.so
|
||||
|
||||
LDADD =
|
||||
|
||||
pythondir = $(pylibdir)/site-packages
|
||||
python_PROGRAMS = _bc.so
|
||||
|
||||
_bc_so_SOURCES = _bc-py.c
|
||||
_bc_so_LDFLAGS = $(mylibs) $(LIBS) -shared -Wl,-soname,_bc.so
|
||||
|
||||
noinst_LTLIBRARIES = libbc.la
|
||||
libbc_la_SOURCES = mpw-py.c rng-py.c
|
||||
|
||||
_bc.so$(EXEEXT): $(_bc_so_OBJECTS) $(libbc_la_OBJECTS)
|
||||
$(CC) -o $@ $(_bc_so_OBJECTS) $(libbc_la_OBJECTS) $(_bc_so_LDFLAGS)
|
||||
|
||||
splint_srcs = _bc-py.c $(libbc_la_sources)
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
$(LINT) $(DEFS) $(INCLUDES) $(splint_srcs)
|
|
@ -0,0 +1,100 @@
|
|||
/** \ingroup py_c
|
||||
* \file python/_bc-py.c
|
||||
*/
|
||||
|
||||
#define _REENTRANT 1 /* XXX config.h collides with pyconfig.h */
|
||||
#include "system.h"
|
||||
|
||||
#include "Python.h"
|
||||
#ifdef __LCLINT__
|
||||
#undef PyObject_HEAD
|
||||
#define PyObject_HEAD int _PyObjectHead;
|
||||
#endif
|
||||
|
||||
#include "mpw-py.h"
|
||||
#include "rng-py.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#ifdef __LCLINT__
|
||||
#undef PyObject_HEAD
|
||||
#define PyObject_HEAD int _PyObjectHead
|
||||
#endif
|
||||
|
||||
/**
|
||||
*/
|
||||
PyObject * py_bcError;
|
||||
|
||||
/**
|
||||
*/
|
||||
static PyMethodDef _bcModuleMethods[] = {
|
||||
{ NULL }
|
||||
} ;
|
||||
|
||||
/**
|
||||
*/
|
||||
static char _bc__doc__[] =
|
||||
"";
|
||||
|
||||
void init_bc(void); /* XXX eliminate gcc warning */
|
||||
/**
|
||||
*/
|
||||
void init_bc(void)
|
||||
{
|
||||
PyObject *d, *m;
|
||||
#ifdef NOTYET
|
||||
PyObject *o, *dict;
|
||||
int i;
|
||||
#endif
|
||||
|
||||
if (PyType_Ready(&mpw_Type) < 0) return;
|
||||
if (PyType_Ready(&rng_Type) < 0) return;
|
||||
|
||||
m = Py_InitModule3("_bc", _bcModuleMethods, _bc__doc__);
|
||||
if (m == NULL)
|
||||
return;
|
||||
|
||||
d = PyModule_GetDict(m);
|
||||
|
||||
py_bcError = PyErr_NewException("_bc.error", NULL, NULL);
|
||||
if (py_bcError != NULL)
|
||||
PyDict_SetItemString(d, "error", py_bcError);
|
||||
|
||||
Py_INCREF(&mpw_Type);
|
||||
PyModule_AddObject(m, "mpw", (PyObject *) &mpw_Type);
|
||||
|
||||
Py_INCREF(&rng_Type);
|
||||
PyModule_AddObject(m, "rng", (PyObject *) &rng_Type);
|
||||
|
||||
#ifdef NOTYET
|
||||
dict = PyDict_New();
|
||||
|
||||
for (i = 0; i < _bcTagTableSize; i++) {
|
||||
tag = PyInt_FromLong(_bcTagTable[i].val);
|
||||
PyDict_SetItemString(d, (char *) _bcTagTable[i].name, tag);
|
||||
Py_DECREF(tag);
|
||||
PyDict_SetItem(dict, tag, o=PyString_FromString(_bcTagTable[i].name + 7));
|
||||
Py_DECREF(o);
|
||||
}
|
||||
|
||||
while (extensions->name) {
|
||||
if (extensions->type == HEADER_EXT_TAG) {
|
||||
(const struct headerSprintfExtension *) ext = extensions;
|
||||
PyDict_SetItemString(d, (char *) extensions->name, o=PyCObject_FromVoidPtr(ext, NULL));
|
||||
Py_DECREF(o);
|
||||
PyDict_SetItem(dict, tag, o=PyString_FromString(ext->name + 7));
|
||||
Py_DECREF(o);
|
||||
}
|
||||
extensions++;
|
||||
}
|
||||
|
||||
PyDict_SetItemString(d, "tagnames", dict);
|
||||
Py_DECREF(dict);
|
||||
|
||||
#define REGISTER_ENUM(val) \
|
||||
PyDict_SetItemString(d, #val, o=PyInt_FromLong( val )); \
|
||||
Py_DECREF(o);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
|
||||
/*@unchecked@*/
|
||||
extern PyTypeObject PyCode_Type;
|
||||
/*@unchecked@*/
|
||||
extern PyTypeObject PyDictIter_Type;
|
||||
/*@unchecked@*/
|
||||
extern PyTypeObject PyFrame_Type;
|
||||
|
||||
#include "mpw-py.h" /* XXX debug only */
|
||||
#include "rng-py.h" /* XXX debug only */
|
||||
|
||||
/**
|
||||
*/
|
||||
static const char * lbl(void * s)
|
||||
/*@*/
|
||||
{
|
||||
PyObject * o = s;
|
||||
|
||||
if (o == NULL) return "null";
|
||||
|
||||
if (o == Py_None) return "None";
|
||||
|
||||
if (o->ob_type == &PyType_Type) return o->ob_type->tp_name;
|
||||
|
||||
if (o->ob_type == &PyBaseObject_Type) return "BaseObj";
|
||||
if (o->ob_type == &PyBuffer_Type) return "Buffer";
|
||||
if (o->ob_type == &PyCFunction_Type) return "CFunction";
|
||||
if (o->ob_type == &PyCObject_Type) return "CObject";
|
||||
if (o->ob_type == &PyCell_Type) return "Cell";
|
||||
if (o->ob_type == &PyClass_Type) return "Class";
|
||||
if (o->ob_type == &PyClassMethod_Type) return "ClassMethod";
|
||||
if (o->ob_type == &PyStaticMethod_Type) return "StaticMethod";
|
||||
if (o->ob_type == &PyCode_Type) return "Code";
|
||||
if (o->ob_type == &PyComplex_Type) return "Complex";
|
||||
if (o->ob_type == &PyDict_Type) return "Dict";
|
||||
if (o->ob_type == &PyDictIter_Type) return "DictIter";
|
||||
if (o->ob_type == &PyFile_Type) return "File";
|
||||
if (o->ob_type == &PyFloat_Type) return "Float";
|
||||
if (o->ob_type == &PyFrame_Type) return "Frame";
|
||||
if (o->ob_type == &PyFunction_Type) return "Function";
|
||||
if (o->ob_type == &PyInstance_Type) return "Instance";
|
||||
if (o->ob_type == &PyInt_Type) return "Int";
|
||||
if (o->ob_type == &PyList_Type) return "List";
|
||||
if (o->ob_type == &PyLong_Type) return "Long";
|
||||
if (o->ob_type == &PyMethod_Type) return "Method";
|
||||
if (o->ob_type == &PyWrapperDescr_Type) return "WrapperDescr";
|
||||
if (o->ob_type == &PyProperty_Type) return "Property";
|
||||
if (o->ob_type == &PyModule_Type) return "Module";
|
||||
if (o->ob_type == &PyRange_Type) return "Range";
|
||||
if (o->ob_type == &PySeqIter_Type) return "SeqIter";
|
||||
if (o->ob_type == &PyCallIter_Type) return "CallIter";
|
||||
if (o->ob_type == &PySlice_Type) return "Slice";
|
||||
if (o->ob_type == &PyString_Type) return "String";
|
||||
if (o->ob_type == &PySuper_Type) return "Super";
|
||||
if (o->ob_type == &PyTuple_Type) return "Tuple";
|
||||
if (o->ob_type == &PyType_Type) return "Type";
|
||||
if (o->ob_type == &PyUnicode_Type) return "Unicode";
|
||||
|
||||
if (o->ob_type == &mpw_Type) return "mpw";
|
||||
if (o->ob_type == &rng_Type) return "rng";
|
||||
|
||||
return "Unknown";
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,40 @@
|
|||
#ifndef H_MPW_PY
|
||||
#define H_MPW_PY
|
||||
|
||||
/** \ingroup py_c
|
||||
* \file python/mpw-py.h
|
||||
*/
|
||||
#include "mp.h"
|
||||
|
||||
/**
|
||||
*/
|
||||
typedef struct mpwObject_s {
|
||||
PyObject_HEAD
|
||||
int ob_size;
|
||||
mpw data[1];
|
||||
} mpwObject;
|
||||
|
||||
/**
|
||||
*/
|
||||
/*@unchecked@*/
|
||||
extern PyTypeObject mpw_Type;
|
||||
|
||||
#define mpw_Check(_o) PyObject_TypeCheck((_o), &mpw_Type)
|
||||
#define mpw_CheckExact(_o) ((_o)->ob_type == &mpw_Type)
|
||||
|
||||
#define MP_ROUND_B2W(_b) MP_BITS_TO_WORDS((_b) + MP_WBITS - 1)
|
||||
|
||||
#define MPW_SIZE(_a) (size_t)((_a)->ob_size < 0 ? -(_a)->ob_size : (_a)->ob_size)
|
||||
#define MPW_DATA(_a) ((_a)->data)
|
||||
|
||||
/**
|
||||
*/
|
||||
mpwObject * mpw_New(int ob_size)
|
||||
/*@*/;
|
||||
|
||||
/**
|
||||
*/
|
||||
mpwObject * mpw_FromMPW(size_t size, mpw* data, int normalize)
|
||||
/*@*/;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,330 @@
|
|||
/** \ingroup py_c
|
||||
* \file python/rng-py.c
|
||||
*/
|
||||
|
||||
#define _REENTRANT 1 /* XXX config.h collides with pyconfig.h */
|
||||
#include "system.h"
|
||||
|
||||
#include "Python.h"
|
||||
#ifdef __LCLINT__
|
||||
#undef PyObject_HEAD
|
||||
#define PyObject_HEAD int _PyObjectHead;
|
||||
#endif
|
||||
|
||||
#include "rng-py.h"
|
||||
|
||||
#include "debug-py.c"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
/*@unchecked@*/
|
||||
static int _rng_debug = 0;
|
||||
|
||||
/*@unchecked@*/ /*@observer@*/
|
||||
static const char initialiser_name[] = "_bc.rng";
|
||||
|
||||
/* ---------- */
|
||||
|
||||
static void
|
||||
rng_dealloc(rngObject * s)
|
||||
/*@modifies s @*/
|
||||
{
|
||||
if (_rng_debug < -1)
|
||||
fprintf(stderr, "*** rng_dealloc(%p)\n", s);
|
||||
|
||||
/*@-modobserver@*/
|
||||
randomGeneratorContextFree(&s->rngc);
|
||||
/*@=modobserver@*/
|
||||
mpbfree(&s->b);
|
||||
PyObject_Del(s);
|
||||
}
|
||||
|
||||
static int
|
||||
rng_print(rngObject * s, FILE * fp, /*@unused@*/ int flags)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies fileSystem @*/
|
||||
{
|
||||
if (_rng_debug < -1)
|
||||
fprintf(stderr, "*** rng_print(%p)\n", s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** \ingroup py_c
|
||||
*/
|
||||
static int rng_init(rngObject * s, PyObject *args, PyObject *kwds)
|
||||
/*@modifies s @*/
|
||||
{
|
||||
PyObject * o = NULL;
|
||||
const randomGenerator* rng = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|O:Cvt", &o)) return -1;
|
||||
|
||||
if (o) {
|
||||
/* XXX "FIPS 186" or "Mersenne Twister" */
|
||||
if (PyString_Check(o))
|
||||
rng = randomGeneratorFind(PyString_AsString(o));
|
||||
}
|
||||
|
||||
if (rng == NULL)
|
||||
rng = randomGeneratorDefault();
|
||||
|
||||
/*@-modobserver@*/
|
||||
if (randomGeneratorContextInit(&s->rngc, rng) != 0)
|
||||
return -1;
|
||||
/*@=modobserver@*/
|
||||
mpbzero(&s->b);
|
||||
|
||||
if (_rng_debug)
|
||||
fprintf(stderr, "*** rng_init(%p[%s],%p[%s],%p[%s])\n", s, lbl(s), args, lbl(args), kwds, lbl(kwds));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** \ingroup py_c
|
||||
*/
|
||||
static void rng_free(/*@only@*/ rngObject * s)
|
||||
/*@modifies s @*/
|
||||
{
|
||||
if (_rng_debug)
|
||||
fprintf(stderr, "*** rng_free(%p[%s])\n", s, lbl(s));
|
||||
/*@-modobserver@*/
|
||||
randomGeneratorContextFree(&s->rngc);
|
||||
/*@=modobserver@*/
|
||||
mpbfree(&s->b);
|
||||
PyObject_Del(s);
|
||||
}
|
||||
|
||||
/** \ingroup py_c
|
||||
*/
|
||||
static PyObject * rng_alloc(PyTypeObject * subtype, int nitems)
|
||||
/*@*/
|
||||
{
|
||||
PyObject * ns = PyType_GenericAlloc(subtype, nitems);
|
||||
|
||||
if (_rng_debug)
|
||||
fprintf(stderr, "*** rng_alloc(%p[%s},%d) ret %p[%s]\n", subtype, lbl(subtype), nitems, ns, lbl(ns));
|
||||
return (PyObject *) ns;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
rng_new(PyTypeObject * subtype, PyObject *args, PyObject *kwds)
|
||||
/*@*/
|
||||
{
|
||||
PyObject * ns = (PyObject *) PyObject_New(rngObject, &rng_Type);
|
||||
|
||||
if (_rng_debug < -1)
|
||||
fprintf(stderr, "*** rng_new(%p[%s],%p[%s],%p[%s]) ret %p[%s]\n", subtype, lbl(subtype), args, lbl(args), kwds, lbl(kwds), ns, lbl(ns));
|
||||
return ns;
|
||||
}
|
||||
|
||||
static rngObject *
|
||||
rng_New(void)
|
||||
{
|
||||
rngObject * ns = PyObject_New(rngObject, &rng_Type);
|
||||
|
||||
return ns;
|
||||
}
|
||||
|
||||
/* ---------- */
|
||||
|
||||
/** \ingroup py_c
|
||||
*/
|
||||
static PyObject *
|
||||
rng_Debug(/*@unused@*/ rngObject * s, PyObject * args)
|
||||
/*@globals _Py_NoneStruct @*/
|
||||
/*@modifies _Py_NoneStruct @*/
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, "i:Debug", &_rng_debug)) return NULL;
|
||||
|
||||
if (_rng_debug < 0)
|
||||
fprintf(stderr, "*** rng_Debug(%p)\n", s);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
/** \ingroup py_c
|
||||
*/
|
||||
static PyObject *
|
||||
rng_Seed(rngObject * s, PyObject * args)
|
||||
/*@globals _Py_NoneStruct @*/
|
||||
/*@modifies _Py_NoneStruct @*/
|
||||
{
|
||||
PyObject * o;
|
||||
randomGeneratorContext* rc = &s->rngc;
|
||||
mpwObject *z;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O:Seed", &o)) return NULL;
|
||||
|
||||
if (!mpw_Check(o) || MPW_SIZE(z = (mpwObject*)o) > 0)
|
||||
return NULL;
|
||||
|
||||
rc->rng->seed(rc->param, (byte*) MPW_DATA(z), MPW_SIZE(z));
|
||||
|
||||
if (_rng_debug < 0)
|
||||
fprintf(stderr, "*** rng_Seed(%p)\n", s);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
/** \ingroup py_c
|
||||
*/
|
||||
static PyObject *
|
||||
rng_Next(rngObject * s, PyObject * args)
|
||||
/*@*/
|
||||
{
|
||||
PyObject * o = NULL;
|
||||
randomGeneratorContext* rc = &s->rngc;
|
||||
mpbarrett* b = &s->b;
|
||||
mpwObject *z;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|O:Next", &o)) return NULL;
|
||||
|
||||
if (o) {
|
||||
if (mpw_Check(o) && MPW_SIZE(z = (mpwObject*)o) > 0) {
|
||||
b = alloca(sizeof(*b));
|
||||
mpbzero(b);
|
||||
/* XXX z probably needs normalization here. */
|
||||
mpbset(b, MPW_SIZE(z), MPW_DATA(z));
|
||||
} else
|
||||
; /* XXX error? */
|
||||
}
|
||||
|
||||
if (b == NULL || b->size == 0 || b->modl == NULL) {
|
||||
z = mpw_New(1);
|
||||
rc->rng->next(rc->param, (byte*) MPW_DATA(z), sizeof(*MPW_DATA(z)));
|
||||
} else {
|
||||
mpw* wksp = alloca(b->size * sizeof(*wksp));
|
||||
z = mpw_New(b->size);
|
||||
mpbrnd_w(b, rc, MPW_DATA(z), wksp);
|
||||
}
|
||||
|
||||
if (_rng_debug)
|
||||
fprintf(stderr, "*** rng_Next(%p) %p[%d]\t", s, MPW_DATA(z), MPW_SIZE(z)), mpfprintln(stderr, MPW_SIZE(z), MPW_DATA(z));
|
||||
|
||||
return (PyObject *)z;
|
||||
}
|
||||
|
||||
/** \ingroup py_c
|
||||
*/
|
||||
static PyObject *
|
||||
rng_Prime(rngObject * s, PyObject * args)
|
||||
/*@*/
|
||||
{
|
||||
randomGeneratorContext* rc = &s->rngc;
|
||||
unsigned pbits = 160;
|
||||
int trials = -1;
|
||||
size_t psize;
|
||||
mpbarrett* b;
|
||||
mpw *temp;
|
||||
mpwObject *z;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|ii:Prime", &pbits, &trials)) return NULL;
|
||||
|
||||
psize = MP_ROUND_B2W(pbits);
|
||||
temp = alloca((8*psize+2) * sizeof(*temp));
|
||||
|
||||
b = alloca(sizeof(*b));
|
||||
mpbzero(b);
|
||||
|
||||
if (trials <= 2)
|
||||
trials = mpptrials(pbits);
|
||||
#if 1
|
||||
mpprnd_w(b, rc, pbits, trials, (const mpnumber*) 0, temp);
|
||||
#else
|
||||
mpprndsafe_w(b, rc, pbits, trials, temp);
|
||||
#endif
|
||||
|
||||
z = mpw_FromMPW(b->size, b->modl, 1);
|
||||
if (z != NULL && _rng_debug)
|
||||
fprintf(stderr, "*** rng_Prime(%p) %p[%d]\t", s, MPW_DATA(z), MPW_SIZE(z)), mpfprintln(stderr, MPW_SIZE(z), MPW_DATA(z));
|
||||
|
||||
return (PyObject *)z;
|
||||
}
|
||||
|
||||
/*@-fullinitblock@*/
|
||||
/*@unchecked@*/ /*@observer@*/
|
||||
static struct PyMethodDef rng_methods[] = {
|
||||
{"Debug", (PyCFunction)rng_Debug, METH_VARARGS,
|
||||
NULL},
|
||||
{"seed", (PyCFunction)rng_Seed, METH_VARARGS,
|
||||
NULL},
|
||||
{"next", (PyCFunction)rng_Next, METH_VARARGS,
|
||||
NULL},
|
||||
{"prime", (PyCFunction)rng_Prime, METH_VARARGS,
|
||||
NULL},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
/*@=fullinitblock@*/
|
||||
|
||||
static PyObject * rng_getattro(PyObject * o, PyObject * n)
|
||||
/*@*/
|
||||
{
|
||||
return PyObject_GenericGetAttr(o, n);
|
||||
}
|
||||
|
||||
static int rng_setattro(PyObject * o, PyObject * n, PyObject * v)
|
||||
/*@*/
|
||||
{
|
||||
return PyObject_GenericSetAttr(o, n, v);
|
||||
}
|
||||
|
||||
/* ---------- */
|
||||
|
||||
/**
|
||||
*/
|
||||
/*@unchecked@*/ /*@observer@*/
|
||||
static char rng_doc[] =
|
||||
"";
|
||||
|
||||
/*@-fullinitblock@*/
|
||||
PyTypeObject rng_Type = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0, /* ob_size */
|
||||
"_bc.rng", /* tp_name */
|
||||
sizeof(rngObject), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
/* methods */
|
||||
(destructor) rng_dealloc, /* tp_dealloc */
|
||||
(printfunc) rng_print, /* tp_print */
|
||||
(getattrfunc)0, /* tp_getattr */
|
||||
(setattrfunc)0, /* tp_setattr */
|
||||
(cmpfunc)0, /* tp_compare */
|
||||
(reprfunc)0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
(hashfunc)0, /* tp_hash */
|
||||
(ternaryfunc)0, /* tp_call */
|
||||
(reprfunc)0, /* tp_str */
|
||||
(getattrofunc) rng_getattro, /* tp_getattro */
|
||||
(setattrofunc) rng_setattro, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
rng_doc, /* tp_doc */
|
||||
#if Py_TPFLAGS_HAVE_ITER
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
(getiterfunc)0, /* tp_iter */
|
||||
(iternextfunc)0, /* tp_iternext */
|
||||
rng_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
(initproc) rng_init, /* tp_init */
|
||||
(allocfunc) rng_alloc, /* tp_alloc */
|
||||
(newfunc) rng_new, /* tp_new */
|
||||
(destructor) rng_free, /* tp_free */
|
||||
0, /* tp_is_gc */
|
||||
#endif
|
||||
};
|
||||
/*@=fullinitblock@*/
|
||||
|
||||
/* ---------- */
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef H_RNG_PY
|
||||
#define H_RNG_PY
|
||||
|
||||
/** \ingroup py_c
|
||||
* \file python/rng-py.h
|
||||
*/
|
||||
#include "beecrypt.h"
|
||||
#include "mpprime.h"
|
||||
|
||||
/**
|
||||
*/
|
||||
typedef struct rngObject_s {
|
||||
PyObject_HEAD
|
||||
PyObject *md_dict; /*!< to look like PyModuleObject */
|
||||
randomGeneratorContext rngc;
|
||||
mpbarrett b;
|
||||
} rngObject;
|
||||
|
||||
/**
|
||||
*/
|
||||
/*@unchecked@*/
|
||||
extern PyTypeObject rng_Type;
|
||||
#define is_rng(o) ((o)->ob_type == &rng_Type)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,3 @@
|
|||
Makefile
|
||||
Makefile.in
|
||||
*.pyc
|
|
@ -0,0 +1,17 @@
|
|||
# Makefile for rpm library.
|
||||
|
||||
AUTOMAKE_OPTIONS = 1.4 foreign
|
||||
|
||||
PYVER= 2.2
|
||||
|
||||
pylibdir = $(shell python -c 'import sys; print sys.path[1]')
|
||||
VALGRIND = # valgrind --verbose --leak-check=yes
|
||||
|
||||
EXTRA_DIST = \
|
||||
test_all.py test_methods.py \
|
||||
unittest.py
|
||||
|
||||
all:
|
||||
|
||||
check:
|
||||
$(VALGRIND) python test_all.py verbose
|
|
@ -0,0 +1,59 @@
|
|||
"""Run all test cases.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import unittest
|
||||
|
||||
verbose = 0
|
||||
if 'verbose' in sys.argv:
|
||||
verbose = 1
|
||||
sys.argv.remove('verbose')
|
||||
|
||||
if 'silent' in sys.argv: # take care of old flag, just in case
|
||||
verbose = 0
|
||||
sys.argv.remove('silent')
|
||||
|
||||
|
||||
def print_versions():
|
||||
from _bc import mpw
|
||||
print
|
||||
print '-=' * 38
|
||||
print 'python version: %s' % sys.version
|
||||
print 'My pid: %s' % os.getpid()
|
||||
print '-=' * 38
|
||||
|
||||
|
||||
class PrintInfoFakeTest(unittest.TestCase):
|
||||
def testPrintVersions(self):
|
||||
print_versions()
|
||||
|
||||
|
||||
# This little hack is for when this module is run as main and all the
|
||||
# other modules import it so they will still be able to get the right
|
||||
# verbose setting. It's confusing but it works.
|
||||
import test_all
|
||||
test_all.verbose = verbose
|
||||
|
||||
|
||||
def suite():
|
||||
test_modules = [
|
||||
'test_methods',
|
||||
]
|
||||
|
||||
alltests = unittest.TestSuite()
|
||||
for name in test_modules:
|
||||
module = __import__(name)
|
||||
alltests.addTest(module.test_suite())
|
||||
return alltests
|
||||
|
||||
|
||||
def test_suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(PrintInfoFakeTest))
|
||||
return suite
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print_versions()
|
||||
unittest.main(defaultTest='suite')
|
|
@ -0,0 +1,322 @@
|
|||
"""
|
||||
Basic TestCases for BTree and hash DBs, with and without a DBEnv, with
|
||||
various DB flags, etc.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
|
||||
from _bc import mpw
|
||||
|
||||
from test_all import verbose
|
||||
|
||||
DASH = '-'
|
||||
|
||||
Methods = ( '__add__', '__sub__', '__mul__', '__div__', '__mod__', '__lshift__', '__rshift__', '__and__', '__xor__', '__or__')
|
||||
|
||||
class Factory(object):
|
||||
def __init__(self, false_self, method_name):
|
||||
self.false_self = false_self
|
||||
self.method_name = method_name
|
||||
|
||||
def __call__(self, val):
|
||||
xself = long(self.false_self)
|
||||
yself = int(self.false_self)
|
||||
xm = long.__getattribute__(xself, self.method_name)
|
||||
ym = mpw.__getattribute__(yself, self.method_name)
|
||||
xa = xm(long(val))
|
||||
ya = ym(int(val))
|
||||
print " Comparing", xa, ya
|
||||
assert xa == ya
|
||||
return xa
|
||||
|
||||
class Long(long):
|
||||
def __getattribute__(self, name):
|
||||
print "__getattribute__ ~%s~" % name
|
||||
if name not in ('__add__', '__sub__'):
|
||||
return long.getattr(self, name)
|
||||
return Factory(self, name)
|
||||
|
||||
#a1 = Bar(1)
|
||||
#a2 = Bar(2)
|
||||
#print a1.__add__(a2)
|
||||
#print "Done"
|
||||
#print a1 + a2
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
class BasicTestCase(unittest.TestCase):
|
||||
a = 0x0000000987654321L
|
||||
b = 0x0000000000000010L
|
||||
c = 0x0fedcba000000000L
|
||||
lo = 2
|
||||
hi = 200
|
||||
t = 10
|
||||
|
||||
def setUp(self):
|
||||
mpw().Debug(0)
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
mpw().Debug(0)
|
||||
pass
|
||||
|
||||
#----------------------------------------
|
||||
|
||||
def test01_SimpleMethods(self):
|
||||
if verbose:
|
||||
print '\n', '-=' * 30
|
||||
print "Running %s.test01_SimpleMethods..." % \
|
||||
self.__class__.__name__
|
||||
print "\ta:\t%s\t%s\t0x%x" % (type(self.a), self.a, self.a)
|
||||
print "\tb:\t%s\t%s\t0x%x" % (type(self.b), self.b, self.b)
|
||||
print "\tc:\t%s\t%s\t0x%x" % (type(self.c), self.c, self.c)
|
||||
|
||||
wa = mpw(self.a)
|
||||
wb = mpw(self.b)
|
||||
wc = mpw(self.c)
|
||||
# xa - Long(self.a)
|
||||
# xb = Long(self.b)
|
||||
# xc = Long(self.c)
|
||||
za = long(self.a)
|
||||
zb = long(self.b)
|
||||
zc = long(self.c)
|
||||
|
||||
print "__int__:\t", int(wb), "\t", int(zb)
|
||||
assert int(wb) == int(zb)
|
||||
print "__long__:\t", long(wa), "\t", long(za)
|
||||
assert long(wb) == long(zb)
|
||||
print "__float__:\t", float(wa), "\t", float(za)
|
||||
assert float(wb) == float(zb)
|
||||
|
||||
zs = hex(za)
|
||||
print "__hex__:\t", hex(wa), "\t", zs
|
||||
assert hex(wa) == zs
|
||||
zs = oct(za)
|
||||
print "__oct__:\t", oct(wa), "\t", zs
|
||||
assert oct(wa) == zs
|
||||
|
||||
print "__neg__:\t", (-wa), "\t", long(-za)
|
||||
print "__pos__:\t", (+wa), "\t", long(+za)
|
||||
print "__abs__:\t", abs(wa), "\t", long(abs(za))
|
||||
print "__invert__:\t", (~wa), "\t", long(~za)
|
||||
|
||||
print "__add__:\t", (wa + wb), "\t", long(za + zb)
|
||||
print "__sub__:\t", (wa - wb), "\t", long(za - zb)
|
||||
print "__mul__:\t", (wa * wb), "\t", long(za * zb)
|
||||
print "__div__:\t", (wa / wb), "\t", long(za / zb)
|
||||
print "__mod__:\t", (wa % wb), "\t", long(za % zb)
|
||||
|
||||
wq, wr = divmod(wa, wb)
|
||||
zq, zr = divmod(za, zb)
|
||||
print "__divmod__ q:\t", wq, "\t", long(zq)
|
||||
print "__divmod__ r:\t", wr, "\t", long(zr)
|
||||
|
||||
print "__pow__:\t", (wb ** wb), "\t", long(zb ** zb)
|
||||
|
||||
print "__lshift__:\t", (wa << wb), "\t", long(za << zb)
|
||||
print "__rshift__:\t", (wa >> wb), "\t", long(za >> zb)
|
||||
print "__and__:\t", (wa & wc), "\t", long(za & zc)
|
||||
print "__xor__:\t", (wa ^ wa), "\t", long(za ^ za)
|
||||
print "__or__:\t", (wa | wc), "\t", long(za | zc)
|
||||
|
||||
# print mpw.__complex__(b)
|
||||
# print mpw.__coerce__(b, i)
|
||||
|
||||
del wa
|
||||
del wb
|
||||
del wc
|
||||
del za
|
||||
del zb
|
||||
del zc
|
||||
pass
|
||||
|
||||
#----------------------------------------
|
||||
def test02_CarryBorrow(self):
|
||||
if verbose:
|
||||
print '\n', '-=' * 30
|
||||
print "Running %s.test02_CarryBorrow..." % \
|
||||
self.__class__.__name__
|
||||
a = 0x7fffffff
|
||||
wa = -mpw(a); wa = wa+wa
|
||||
za = -long(a); za = za+za
|
||||
wb = -mpw(1)
|
||||
zb = -long(1)
|
||||
wc = mpw(1)
|
||||
zc = long(1)
|
||||
wd = mpw(a); wd = wd+wd
|
||||
zd = long(a); zd = zd+zd
|
||||
print "add --:\t", (wa+wa), "\t", (za+za)
|
||||
print "add -+:\t", (wb+wd), "\t", (zb+zd)
|
||||
print "add +-:\t", (wc+wa), "\t", (zc+za)
|
||||
print "add ++:\t", (wd+wd), "\t", (zd+zd)
|
||||
print "sub --:\t", (wb-wa), "\t", (zb-za)
|
||||
# print "sub -+:\t", (wb-wd), "\t", (zb-zd)
|
||||
# print "sub +-:\t", (wc-wa), "\t", (zc-za)
|
||||
print "sub ++:\t", (wc-wd), "\t", (zc-zd)
|
||||
pass
|
||||
|
||||
#----------------------------------------
|
||||
def test03_Signs(self):
|
||||
if verbose:
|
||||
print '\n', '-=' * 30
|
||||
print "Running %s.test03_Signs..." % \
|
||||
self.__class__.__name__
|
||||
wpa = mpw(13)
|
||||
wma = -wpa
|
||||
wpb = wpa - 3
|
||||
wmb = -wpb
|
||||
zpa = long(13)
|
||||
zma = -zpa
|
||||
zpb = zpa - 3
|
||||
zmb = -zpb
|
||||
print "add --:\t", (wma+wmb), "\t", (zma+zmb)
|
||||
print "add -+:\t", (wma+wpb), "\t", (zma+zpb)
|
||||
print "add +-:\t", (wpa+wmb), "\t", (zpa+zmb)
|
||||
print "add ++:\t", (wpa+wpb), "\t", (zpa+zpb)
|
||||
|
||||
print "sub --:\t", (wma-wmb), "\t", (zma-zmb)
|
||||
print "sub -+:\t", (wma-wpb), "\t", (zma-zpb)
|
||||
print "sub +-:\t", (wpa-wmb), "\t", (zpa-zmb)
|
||||
print "sub ++:\t", (wpa-wpb), "\t", (zpa-zpb)
|
||||
print "sub --:\t", (wmb-wma), "\t", (zmb-zma)
|
||||
print "sub -+:\t", (wmb-wpa), "\t", (zmb-zpa)
|
||||
print "sub +-:\t", (wpb-wma), "\t", (zpb-zma)
|
||||
print "sub ++:\t", (wpb-wpa), "\t", (zpb-zpa)
|
||||
|
||||
print "mul --:\t", (wma*wmb), "\t", (zma*zmb)
|
||||
print "mul -+:\t", (wma*wpb), "\t", (zma*zpb)
|
||||
print "mul +-:\t", (wpa*wmb), "\t", (zpa*zmb)
|
||||
print "mul ++:\t", (wpa*wpb), "\t", (zpa*zpb)
|
||||
|
||||
print "div --:\t", (wma/wmb), "\t", (zma/zmb)
|
||||
print "div -+:\t", (wma/wpb), "\t", (zma/zpb)
|
||||
print "div +-:\t", (wpa/wmb), "\t", (zpa/zmb)
|
||||
print "div ++:\t", (wpa/wpb), "\t", (zpa/zpb)
|
||||
print "div --:\t", (wmb/wma), "\t", (zmb/zma)
|
||||
print "div -+:\t", (wmb/wpa), "\t", (zmb/zpa)
|
||||
print "div +-:\t", (wpb/wma), "\t", (zpb/zma)
|
||||
print "div ++:\t", (wpb/wpa), "\t", (zpb/zpa)
|
||||
|
||||
print "pow --:\t", (wma**wmb), "\t", (zma**zmb)
|
||||
print "pow -+:\t", (wma**wpb), "\t", (zma**zpb)
|
||||
print "pow +-:\t", (wpa**wmb), "\t", (zpa**zmb)
|
||||
print "pow ++:\t", (wpa**wpb), "\t", (zpa**zpb)
|
||||
print "pow --:\t", (wmb**wma), "\t", (zmb**zma)
|
||||
print "pow -+:\t", (wmb**wpa), "\t", (zmb**zpa)
|
||||
print "pow +-:\t", (wpb**wma), "\t", (zpb**zma)
|
||||
print "pow ++:\t", (wpb**wpa), "\t", (zpb**zpa)
|
||||
|
||||
# wpa = mpw(13)
|
||||
# wma = -wpa
|
||||
# wpb = wpa - 3
|
||||
# wmb = -wpb
|
||||
# zpa = long(13)
|
||||
# zma = -zpa
|
||||
# zpb = zpa - 3
|
||||
# zmb = -zpb
|
||||
print "mod --:\t", (wma%wmb), "\t", (zma%zmb)
|
||||
print "mod -+:\t", (wma%wpb), "\t", (zma%zpb)
|
||||
print "mod +-:\t", (wpa%wmb), "\t", (zpa%zmb)
|
||||
print "mod ++:\t", (wpa%wpb), "\t", (zpa%zpb)
|
||||
print "mod --:\t", (wmb%wma), "\t", (zmb%zma)
|
||||
print "mod -+:\t", (wmb%wpa), "\t", (zmb%zpa)
|
||||
print "mod +-:\t", (wpb%wma), "\t", (zpb%zma)
|
||||
print "mod ++:\t", (wpb%wpa), "\t", (zpb%zpa)
|
||||
|
||||
print "rem --:\t", divmod(wma, wmb), "\t", divmod(zma, zmb)
|
||||
print "rem -+:\t", divmod(wma, wpb), "\t", divmod(zma, zpb)
|
||||
print "rem +-:\t", divmod(wpa, wmb), "\t", divmod(zpa, zmb)
|
||||
print "rem ++:\t", divmod(wpa, wpb), "\t", divmod(zpa, zpb)
|
||||
print "rem --:\t", divmod(wmb, wma), "\t", divmod(zmb, zma)
|
||||
print "rem -+:\t", divmod(wmb, wpa), "\t", divmod(zmb, zpa)
|
||||
print "rem +-:\t", divmod(wpb, wma), "\t", divmod(zpb, zma)
|
||||
print "rem ++:\t", divmod(wpb, wpa), "\t", divmod(zpb, zpa)
|
||||
pass
|
||||
|
||||
#----------------------------------------
|
||||
def test04_KnuthPoly(self):
|
||||
self.t = 8
|
||||
tfmt = "%o"
|
||||
if verbose:
|
||||
print '\n', '-=' * 30
|
||||
print "Running %s.test04_KnuthPoly..." % \
|
||||
self.__class__.__name__
|
||||
print "\t(%d**m - 1) * (%d**n - 1), m,n in [%d,%d)" % (self.t,self.t,self.lo,self.hi)
|
||||
tm1 = tfmt % (self.t - 1)
|
||||
tm2 = tfmt % (self.t - 2)
|
||||
for m in range(self.lo,self.hi):
|
||||
for n in range(m+1,self.hi+1):
|
||||
wt = mpw(self.t)
|
||||
wa = (wt**m - 1) * (wt**n - 1)
|
||||
ws = tfmt % long(wa)
|
||||
zs = tm1 * (m - 1) + tm2 + tm1 * (n - m) + "0" * (m - 1) + "1"
|
||||
if ws != zs:
|
||||
print "(%d**%d - 1) * (%d**%d - 1)\t%s" % (self.t,m,self.t,n,ws)
|
||||
assert ws == zs
|
||||
|
||||
self.t = 10
|
||||
tfmt = "%d"
|
||||
if verbose:
|
||||
print "\t(%d**m - 1) * (%d**n - 1), m,n in [%d,%d)" % (self.t,self.t,self.lo,self.hi)
|
||||
tm1 = tfmt % (self.t - 1)
|
||||
tm2 = tfmt % (self.t - 2)
|
||||
for m in range(self.lo,self.hi):
|
||||
for n in range(m+1,self.hi+1):
|
||||
wt = mpw(self.t)
|
||||
wa = (wt**m - 1) * (wt**n - 1)
|
||||
ws = tfmt % long(wa)
|
||||
zs = tm1 * (m - 1) + tm2 + tm1 * (n - m) + "0" * (m - 1) + "1"
|
||||
if ws != zs:
|
||||
print "(%d**%d - 1) * (%d**%d - 1)\t%s" % (self.t,m,self.t,n,ws)
|
||||
assert ws == zs
|
||||
|
||||
self.t = 16
|
||||
tfmt = "%x"
|
||||
if verbose:
|
||||
print "\t(%d**m - 1) * (%d**n - 1), m,n in [%d,%d)" % (self.t,self.t,self.lo,self.hi)
|
||||
tm1 = tfmt % (self.t - 1)
|
||||
tm2 = tfmt % (self.t - 2)
|
||||
for m in range(self.lo,self.hi):
|
||||
for n in range(m+1,self.hi+1):
|
||||
wt = mpw(self.t)
|
||||
wa = (wt**m - 1) * (wt**n - 1)
|
||||
ws = tfmt % long(wa)
|
||||
zs = tm1 * (m - 1) + tm2 + tm1 * (n - m) + "0" * (m - 1) + "1"
|
||||
if ws != zs:
|
||||
print "(%d**%d - 1) * (%d**%d - 1)\t%s" % (self.t,m,self.t,n,ws)
|
||||
assert ws == zs
|
||||
pass
|
||||
|
||||
#----------------------------------------
|
||||
def test05_IterativePowers(self):
|
||||
if verbose:
|
||||
print '\n', '-=' * 30
|
||||
print "Running %s.test05_IterativePowers..." % \
|
||||
self.__class__.__name__
|
||||
print "\t(m**n)/(m**(n-1)) == m for m,n in [%d,%d)" % (self.lo,self.hi)
|
||||
for m in range(self.lo,self.hi):
|
||||
wa = mpw(m)
|
||||
wd = wa
|
||||
for n in range(self.lo,self.hi):
|
||||
wc = wa**n
|
||||
we = wc/wd
|
||||
if we != m:
|
||||
print m, '^', n, '=', we
|
||||
assert we == m
|
||||
if wc != 0:
|
||||
wd = wc
|
||||
pass
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
def test_suite():
|
||||
suite = unittest.TestSuite()
|
||||
|
||||
suite.addTest(unittest.makeSuite(BasicTestCase))
|
||||
|
||||
return suite
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(defaultTest='test_suite')
|
|
@ -0,0 +1,759 @@
|
|||
#!/usr/bin/env python
|
||||
'''
|
||||
Python unit testing framework, based on Erich Gamma's JUnit and Kent Beck's
|
||||
Smalltalk testing framework.
|
||||
|
||||
This module contains the core framework classes that form the basis of
|
||||
specific test cases and suites (TestCase, TestSuite etc.), and also a
|
||||
text-based utility class for running the tests and reporting the results
|
||||
(TextTestRunner).
|
||||
|
||||
Simple usage:
|
||||
|
||||
import unittest
|
||||
|
||||
class IntegerArithmenticTestCase(unittest.TestCase):
|
||||
def testAdd(self): ## test method names begin 'test*'
|
||||
self.assertEquals((1 + 2), 3)
|
||||
self.assertEquals(0 + 1, 1)
|
||||
def testMultiply(self):
|
||||
self.assertEquals((0 * 10), 0)
|
||||
self.assertEquals((5 * 8), 40)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
Further information is available in the bundled documentation, and from
|
||||
|
||||
http://pyunit.sourceforge.net/
|
||||
|
||||
Copyright (c) 1999, 2000, 2001 Steve Purcell
|
||||
This module is free software, and you may redistribute it and/or modify
|
||||
it under the same terms as Python itself, so long as this copyright message
|
||||
and disclaimer are retained in their original form.
|
||||
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
|
||||
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
|
||||
THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
||||
THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
|
||||
AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
|
||||
SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
'''
|
||||
|
||||
__author__ = "Steve Purcell"
|
||||
__email__ = "stephen_purcell at yahoo dot com"
|
||||
__version__ = "#Revision: 1.46 $"[11:-2]
|
||||
|
||||
import time
|
||||
import sys
|
||||
import traceback
|
||||
import string
|
||||
import os
|
||||
import types
|
||||
|
||||
##############################################################################
|
||||
# Test framework core
|
||||
##############################################################################
|
||||
|
||||
# All classes defined herein are 'new-style' classes, allowing use of 'super()'
|
||||
__metaclass__ = type
|
||||
|
||||
def _strclass(cls):
|
||||
return "%s.%s" % (cls.__module__, cls.__name__)
|
||||
|
||||
class TestResult:
|
||||
"""Holder for test result information.
|
||||
|
||||
Test results are automatically managed by the TestCase and TestSuite
|
||||
classes, and do not need to be explicitly manipulated by writers of tests.
|
||||
|
||||
Each instance holds the total number of tests run, and collections of
|
||||
failures and errors that occurred among those test runs. The collections
|
||||
contain tuples of (testcase, exceptioninfo), where exceptioninfo is the
|
||||
formatted traceback of the error that occurred.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.failures = []
|
||||
self.errors = []
|
||||
self.testsRun = 0
|
||||
self.shouldStop = 0
|
||||
|
||||
def startTest(self, test):
|
||||
"Called when the given test is about to be run"
|
||||
self.testsRun = self.testsRun + 1
|
||||
|
||||
def stopTest(self, test):
|
||||
"Called when the given test has been run"
|
||||
pass
|
||||
|
||||
def addError(self, test, err):
|
||||
"""Called when an error has occurred. 'err' is a tuple of values as
|
||||
returned by sys.exc_info().
|
||||
"""
|
||||
self.errors.append((test, self._exc_info_to_string(err)))
|
||||
|
||||
def addFailure(self, test, err):
|
||||
"""Called when an error has occurred. 'err' is a tuple of values as
|
||||
returned by sys.exc_info()."""
|
||||
self.failures.append((test, self._exc_info_to_string(err)))
|
||||
|
||||
def addSuccess(self, test):
|
||||
"Called when a test has completed successfully"
|
||||
pass
|
||||
|
||||
def wasSuccessful(self):
|
||||
"Tells whether or not this result was a success"
|
||||
return len(self.failures) == len(self.errors) == 0
|
||||
|
||||
def stop(self):
|
||||
"Indicates that the tests should be aborted"
|
||||
self.shouldStop = 1
|
||||
|
||||
def _exc_info_to_string(self, err):
|
||||
"""Converts a sys.exc_info()-style tuple of values into a string."""
|
||||
return string.join(traceback.format_exception(*err), '')
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s run=%i errors=%i failures=%i>" % \
|
||||
(_strclass(self.__class__), self.testsRun, len(self.errors),
|
||||
len(self.failures))
|
||||
|
||||
|
||||
class TestCase:
|
||||
"""A class whose instances are single test cases.
|
||||
|
||||
By default, the test code itself should be placed in a method named
|
||||
'runTest'.
|
||||
|
||||
If the fixture may be used for many test cases, create as
|
||||
many test methods as are needed. When instantiating such a TestCase
|
||||
subclass, specify in the constructor arguments the name of the test method
|
||||
that the instance is to execute.
|
||||
|
||||
Test authors should subclass TestCase for their own tests. Construction
|
||||
and deconstruction of the test's environment ('fixture') can be
|
||||
implemented by overriding the 'setUp' and 'tearDown' methods respectively.
|
||||
|
||||
If it is necessary to override the __init__ method, the base class
|
||||
__init__ method must always be called. It is important that subclasses
|
||||
should not change the signature of their __init__ method, since instances
|
||||
of the classes are instantiated automatically by parts of the framework
|
||||
in order to be run.
|
||||
"""
|
||||
|
||||
# This attribute determines which exception will be raised when
|
||||
# the instance's assertion methods fail; test methods raising this
|
||||
# exception will be deemed to have 'failed' rather than 'errored'
|
||||
|
||||
failureException = AssertionError
|
||||
|
||||
def __init__(self, methodName='runTest'):
|
||||
"""Create an instance of the class that will use the named test
|
||||
method when executed. Raises a ValueError if the instance does
|
||||
not have a method with the specified name.
|
||||
"""
|
||||
try:
|
||||
self.__testMethodName = methodName
|
||||
testMethod = getattr(self, methodName)
|
||||
self.__testMethodDoc = testMethod.__doc__
|
||||
except AttributeError:
|
||||
raise ValueError, "no such test method in %s: %s" % \
|
||||
(self.__class__, methodName)
|
||||
|
||||
def setUp(self):
|
||||
"Hook method for setting up the test fixture before exercising it."
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
"Hook method for deconstructing the test fixture after testing it."
|
||||
pass
|
||||
|
||||
def countTestCases(self):
|
||||
return 1
|
||||
|
||||
def defaultTestResult(self):
|
||||
return TestResult()
|
||||
|
||||
def shortDescription(self):
|
||||
"""Returns a one-line description of the test, or None if no
|
||||
description has been provided.
|
||||
|
||||
The default implementation of this method returns the first line of
|
||||
the specified test method's docstring.
|
||||
"""
|
||||
doc = self.__testMethodDoc
|
||||
return doc and string.strip(string.split(doc, "\n")[0]) or None
|
||||
|
||||
def id(self):
|
||||
return "%s.%s" % (_strclass(self.__class__), self.__testMethodName)
|
||||
|
||||
def __str__(self):
|
||||
return "%s (%s)" % (self.__testMethodName, _strclass(self.__class__))
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s testMethod=%s>" % \
|
||||
(_strclass(self.__class__), self.__testMethodName)
|
||||
|
||||
def run(self, result=None):
|
||||
return self(result)
|
||||
|
||||
def __call__(self, result=None):
|
||||
if result is None: result = self.defaultTestResult()
|
||||
result.startTest(self)
|
||||
testMethod = getattr(self, self.__testMethodName)
|
||||
try:
|
||||
try:
|
||||
self.setUp()
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except:
|
||||
result.addError(self, self.__exc_info())
|
||||
return
|
||||
|
||||
ok = 0
|
||||
try:
|
||||
testMethod()
|
||||
ok = 1
|
||||
except self.failureException, e:
|
||||
result.addFailure(self, self.__exc_info())
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except:
|
||||
result.addError(self, self.__exc_info())
|
||||
|
||||
try:
|
||||
self.tearDown()
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except:
|
||||
result.addError(self, self.__exc_info())
|
||||
ok = 0
|
||||
if ok: result.addSuccess(self)
|
||||
finally:
|
||||
result.stopTest(self)
|
||||
|
||||
def debug(self):
|
||||
"""Run the test without collecting errors in a TestResult"""
|
||||
self.setUp()
|
||||
getattr(self, self.__testMethodName)()
|
||||
self.tearDown()
|
||||
|
||||
def __exc_info(self):
|
||||
"""Return a version of sys.exc_info() with the traceback frame
|
||||
minimised; usually the top level of the traceback frame is not
|
||||
needed.
|
||||
"""
|
||||
exctype, excvalue, tb = sys.exc_info()
|
||||
if sys.platform[:4] == 'java': ## tracebacks look different in Jython
|
||||
return (exctype, excvalue, tb)
|
||||
newtb = tb.tb_next
|
||||
if newtb is None:
|
||||
return (exctype, excvalue, tb)
|
||||
return (exctype, excvalue, newtb)
|
||||
|
||||
def fail(self, msg=None):
|
||||
"""Fail immediately, with the given message."""
|
||||
raise self.failureException, msg
|
||||
|
||||
def failIf(self, expr, msg=None):
|
||||
"Fail the test if the expression is true."
|
||||
if expr: raise self.failureException, msg
|
||||
|
||||
def failUnless(self, expr, msg=None):
|
||||
"""Fail the test unless the expression is true."""
|
||||
if not expr: raise self.failureException, msg
|
||||
|
||||
def failUnlessRaises(self, excClass, callableObj, *args, **kwargs):
|
||||
"""Fail unless an exception of class excClass is thrown
|
||||
by callableObj when invoked with arguments args and keyword
|
||||
arguments kwargs. If a different type of exception is
|
||||
thrown, it will not be caught, and the test case will be
|
||||
deemed to have suffered an error, exactly as for an
|
||||
unexpected exception.
|
||||
"""
|
||||
try:
|
||||
callableObj(*args, **kwargs)
|
||||
except excClass:
|
||||
return
|
||||
else:
|
||||
if hasattr(excClass,'__name__'): excName = excClass.__name__
|
||||
else: excName = str(excClass)
|
||||
raise self.failureException, excName
|
||||
|
||||
def failUnlessEqual(self, first, second, msg=None):
|
||||
"""Fail if the two objects are unequal as determined by the '=='
|
||||
operator.
|
||||
"""
|
||||
if not first == second:
|
||||
raise self.failureException, \
|
||||
(msg or '%s != %s' % (`first`, `second`))
|
||||
|
||||
def failIfEqual(self, first, second, msg=None):
|
||||
"""Fail if the two objects are equal as determined by the '=='
|
||||
operator.
|
||||
"""
|
||||
if first == second:
|
||||
raise self.failureException, \
|
||||
(msg or '%s == %s' % (`first`, `second`))
|
||||
|
||||
def failUnlessAlmostEqual(self, first, second, places=7, msg=None):
|
||||
"""Fail if the two objects are unequal as determined by their
|
||||
difference rounded to the given number of decimal places
|
||||
(default 7) and comparing to zero.
|
||||
|
||||
Note that decimal places (from zero) is usually not the same
|
||||
as significant digits (measured from the most signficant digit).
|
||||
"""
|
||||
if round(second-first, places) != 0:
|
||||
raise self.failureException, \
|
||||
(msg or '%s != %s within %s places' % (`first`, `second`, `places` ))
|
||||
|
||||
def failIfAlmostEqual(self, first, second, places=7, msg=None):
|
||||
"""Fail if the two objects are equal as determined by their
|
||||
difference rounded to the given number of decimal places
|
||||
(default 7) and comparing to zero.
|
||||
|
||||
Note that decimal places (from zero) is usually not the same
|
||||
as significant digits (measured from the most signficant digit).
|
||||
"""
|
||||
if round(second-first, places) == 0:
|
||||
raise self.failureException, \
|
||||
(msg or '%s == %s within %s places' % (`first`, `second`, `places`))
|
||||
|
||||
assertEqual = assertEquals = failUnlessEqual
|
||||
|
||||
assertNotEqual = assertNotEquals = failIfEqual
|
||||
|
||||
assertAlmostEqual = assertAlmostEquals = failUnlessAlmostEqual
|
||||
|
||||
assertNotAlmostEqual = assertNotAlmostEquals = failIfAlmostEqual
|
||||
|
||||
assertRaises = failUnlessRaises
|
||||
|
||||
assert_ = failUnless
|
||||
|
||||
|
||||
|
||||
class TestSuite:
|
||||
"""A test suite is a composite test consisting of a number of TestCases.
|
||||
|
||||
For use, create an instance of TestSuite, then add test case instances.
|
||||
When all tests have been added, the suite can be passed to a test
|
||||
runner, such as TextTestRunner. It will run the individual test cases
|
||||
in the order in which they were added, aggregating the results. When
|
||||
subclassing, do not forget to call the base class constructor.
|
||||
"""
|
||||
def __init__(self, tests=()):
|
||||
self._tests = []
|
||||
self.addTests(tests)
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s tests=%s>" % (_strclass(self.__class__), self._tests)
|
||||
|
||||
__str__ = __repr__
|
||||
|
||||
def countTestCases(self):
|
||||
cases = 0
|
||||
for test in self._tests:
|
||||
cases = cases + test.countTestCases()
|
||||
return cases
|
||||
|
||||
def addTest(self, test):
|
||||
self._tests.append(test)
|
||||
|
||||
def addTests(self, tests):
|
||||
for test in tests:
|
||||
self.addTest(test)
|
||||
|
||||
def run(self, result):
|
||||
return self(result)
|
||||
|
||||
def __call__(self, result):
|
||||
for test in self._tests:
|
||||
if result.shouldStop:
|
||||
break
|
||||
test(result)
|
||||
return result
|
||||
|
||||
def debug(self):
|
||||
"""Run the tests without collecting errors in a TestResult"""
|
||||
for test in self._tests: test.debug()
|
||||
|
||||
|
||||
class FunctionTestCase(TestCase):
|
||||
"""A test case that wraps a test function.
|
||||
|
||||
This is useful for slipping pre-existing test functions into the
|
||||
PyUnit framework. Optionally, set-up and tidy-up functions can be
|
||||
supplied. As with TestCase, the tidy-up ('tearDown') function will
|
||||
always be called if the set-up ('setUp') function ran successfully.
|
||||
"""
|
||||
|
||||
def __init__(self, testFunc, setUp=None, tearDown=None,
|
||||
description=None):
|
||||
TestCase.__init__(self)
|
||||
self.__setUpFunc = setUp
|
||||
self.__tearDownFunc = tearDown
|
||||
self.__testFunc = testFunc
|
||||
self.__description = description
|
||||
|
||||
def setUp(self):
|
||||
if self.__setUpFunc is not None:
|
||||
self.__setUpFunc()
|
||||
|
||||
def tearDown(self):
|
||||
if self.__tearDownFunc is not None:
|
||||
self.__tearDownFunc()
|
||||
|
||||
def runTest(self):
|
||||
self.__testFunc()
|
||||
|
||||
def id(self):
|
||||
return self.__testFunc.__name__
|
||||
|
||||
def __str__(self):
|
||||
return "%s (%s)" % (_strclass(self.__class__), self.__testFunc.__name__)
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s testFunc=%s>" % (_strclass(self.__class__), self.__testFunc)
|
||||
|
||||
def shortDescription(self):
|
||||
if self.__description is not None: return self.__description
|
||||
doc = self.__testFunc.__doc__
|
||||
return doc and string.strip(string.split(doc, "\n")[0]) or None
|
||||
|
||||
|
||||
|
||||
##############################################################################
|
||||
# Locating and loading tests
|
||||
##############################################################################
|
||||
|
||||
class TestLoader:
|
||||
"""This class is responsible for loading tests according to various
|
||||
criteria and returning them wrapped in a Test
|
||||
"""
|
||||
testMethodPrefix = 'test'
|
||||
sortTestMethodsUsing = cmp
|
||||
suiteClass = TestSuite
|
||||
|
||||
def loadTestsFromTestCase(self, testCaseClass):
|
||||
"""Return a suite of all tests cases contained in testCaseClass"""
|
||||
return self.suiteClass(map(testCaseClass,
|
||||
self.getTestCaseNames(testCaseClass)))
|
||||
|
||||
def loadTestsFromModule(self, module):
|
||||
"""Return a suite of all tests cases contained in the given module"""
|
||||
tests = []
|
||||
for name in dir(module):
|
||||
obj = getattr(module, name)
|
||||
if (isinstance(obj, (type, types.ClassType)) and
|
||||
issubclass(obj, TestCase)):
|
||||
tests.append(self.loadTestsFromTestCase(obj))
|
||||
return self.suiteClass(tests)
|
||||
|
||||
def loadTestsFromName(self, name, module=None):
|
||||
"""Return a suite of all tests cases given a string specifier.
|
||||
|
||||
The name may resolve either to a module, a test case class, a
|
||||
test method within a test case class, or a callable object which
|
||||
returns a TestCase or TestSuite instance.
|
||||
|
||||
The method optionally resolves the names relative to a given module.
|
||||
"""
|
||||
parts = string.split(name, '.')
|
||||
if module is None:
|
||||
if not parts:
|
||||
raise ValueError, "incomplete test name: %s" % name
|
||||
else:
|
||||
parts_copy = parts[:]
|
||||
while parts_copy:
|
||||
try:
|
||||
module = __import__(string.join(parts_copy,'.'))
|
||||
break
|
||||
except ImportError:
|
||||
del parts_copy[-1]
|
||||
if not parts_copy: raise
|
||||
parts = parts[1:]
|
||||
obj = module
|
||||
for part in parts:
|
||||
obj = getattr(obj, part)
|
||||
|
||||
import unittest
|
||||
if type(obj) == types.ModuleType:
|
||||
return self.loadTestsFromModule(obj)
|
||||
elif (isinstance(obj, (type, types.ClassType)) and
|
||||
issubclass(obj, unittest.TestCase)):
|
||||
return self.loadTestsFromTestCase(obj)
|
||||
elif type(obj) == types.UnboundMethodType:
|
||||
return obj.im_class(obj.__name__)
|
||||
elif callable(obj):
|
||||
test = obj()
|
||||
if not isinstance(test, unittest.TestCase) and \
|
||||
not isinstance(test, unittest.TestSuite):
|
||||
raise ValueError, \
|
||||
"calling %s returned %s, not a test" % (obj,test)
|
||||
return test
|
||||
else:
|
||||
raise ValueError, "don't know how to make test from: %s" % obj
|
||||
|
||||
def loadTestsFromNames(self, names, module=None):
|
||||
"""Return a suite of all tests cases found using the given sequence
|
||||
of string specifiers. See 'loadTestsFromName()'.
|
||||
"""
|
||||
suites = []
|
||||
for name in names:
|
||||
suites.append(self.loadTestsFromName(name, module))
|
||||
return self.suiteClass(suites)
|
||||
|
||||
def getTestCaseNames(self, testCaseClass):
|
||||
"""Return a sorted sequence of method names found within testCaseClass
|
||||
"""
|
||||
testFnNames = filter(lambda n,p=self.testMethodPrefix: n[:len(p)] == p,
|
||||
dir(testCaseClass))
|
||||
for baseclass in testCaseClass.__bases__:
|
||||
for testFnName in self.getTestCaseNames(baseclass):
|
||||
if testFnName not in testFnNames: # handle overridden methods
|
||||
testFnNames.append(testFnName)
|
||||
if self.sortTestMethodsUsing:
|
||||
testFnNames.sort(self.sortTestMethodsUsing)
|
||||
return testFnNames
|
||||
|
||||
|
||||
|
||||
defaultTestLoader = TestLoader()
|
||||
|
||||
|
||||
##############################################################################
|
||||
# Patches for old functions: these functions should be considered obsolete
|
||||
##############################################################################
|
||||
|
||||
def _makeLoader(prefix, sortUsing, suiteClass=None):
|
||||
loader = TestLoader()
|
||||
loader.sortTestMethodsUsing = sortUsing
|
||||
loader.testMethodPrefix = prefix
|
||||
if suiteClass: loader.suiteClass = suiteClass
|
||||
return loader
|
||||
|
||||
def getTestCaseNames(testCaseClass, prefix, sortUsing=cmp):
|
||||
return _makeLoader(prefix, sortUsing).getTestCaseNames(testCaseClass)
|
||||
|
||||
def makeSuite(testCaseClass, prefix='test', sortUsing=cmp, suiteClass=TestSuite):
|
||||
return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(testCaseClass)
|
||||
|
||||
def findTestCases(module, prefix='test', sortUsing=cmp, suiteClass=TestSuite):
|
||||
return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(module)
|
||||
|
||||
|
||||
##############################################################################
|
||||
# Text UI
|
||||
##############################################################################
|
||||
|
||||
class _WritelnDecorator:
|
||||
"""Used to decorate file-like objects with a handy 'writeln' method"""
|
||||
def __init__(self,stream):
|
||||
self.stream = stream
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self.stream,attr)
|
||||
|
||||
def writeln(self, *args):
|
||||
if args: self.write(*args)
|
||||
self.write('\n') # text-mode streams translate to \r\n if needed
|
||||
|
||||
|
||||
class _TextTestResult(TestResult):
|
||||
"""A test result class that can print formatted text results to a stream.
|
||||
|
||||
Used by TextTestRunner.
|
||||
"""
|
||||
separator1 = '=' * 70
|
||||
separator2 = '-' * 70
|
||||
|
||||
def __init__(self, stream, descriptions, verbosity):
|
||||
TestResult.__init__(self)
|
||||
self.stream = stream
|
||||
self.showAll = verbosity > 1
|
||||
self.dots = verbosity == 1
|
||||
self.descriptions = descriptions
|
||||
|
||||
def getDescription(self, test):
|
||||
if self.descriptions:
|
||||
return test.shortDescription() or str(test)
|
||||
else:
|
||||
return str(test)
|
||||
|
||||
def startTest(self, test):
|
||||
TestResult.startTest(self, test)
|
||||
if self.showAll:
|
||||
self.stream.write(self.getDescription(test))
|
||||
self.stream.write(" ... ")
|
||||
|
||||
def addSuccess(self, test):
|
||||
TestResult.addSuccess(self, test)
|
||||
if self.showAll:
|
||||
self.stream.writeln("ok")
|
||||
elif self.dots:
|
||||
self.stream.write('.')
|
||||
|
||||
def addError(self, test, err):
|
||||
TestResult.addError(self, test, err)
|
||||
if self.showAll:
|
||||
self.stream.writeln("ERROR")
|
||||
elif self.dots:
|
||||
self.stream.write('E')
|
||||
|
||||
def addFailure(self, test, err):
|
||||
TestResult.addFailure(self, test, err)
|
||||
if self.showAll:
|
||||
self.stream.writeln("FAIL")
|
||||
elif self.dots:
|
||||
self.stream.write('F')
|
||||
|
||||
def printErrors(self):
|
||||
if self.dots or self.showAll:
|
||||
self.stream.writeln()
|
||||
self.printErrorList('ERROR', self.errors)
|
||||
self.printErrorList('FAIL', self.failures)
|
||||
|
||||
def printErrorList(self, flavour, errors):
|
||||
for test, err in errors:
|
||||
self.stream.writeln(self.separator1)
|
||||
self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
|
||||
self.stream.writeln(self.separator2)
|
||||
self.stream.writeln("%s" % err)
|
||||
|
||||
|
||||
class TextTestRunner:
|
||||
"""A test runner class that displays results in textual form.
|
||||
|
||||
It prints out the names of tests as they are run, errors as they
|
||||
occur, and a summary of the results at the end of the test run.
|
||||
"""
|
||||
def __init__(self, stream=sys.stderr, descriptions=1, verbosity=1):
|
||||
self.stream = _WritelnDecorator(stream)
|
||||
self.descriptions = descriptions
|
||||
self.verbosity = verbosity
|
||||
|
||||
def _makeResult(self):
|
||||
return _TextTestResult(self.stream, self.descriptions, self.verbosity)
|
||||
|
||||
def run(self, test):
|
||||
"Run the given test case or test suite."
|
||||
result = self._makeResult()
|
||||
startTime = time.time()
|
||||
test(result)
|
||||
stopTime = time.time()
|
||||
timeTaken = float(stopTime - startTime)
|
||||
result.printErrors()
|
||||
self.stream.writeln(result.separator2)
|
||||
run = result.testsRun
|
||||
self.stream.writeln("Ran %d test%s in %.3fs" %
|
||||
(run, run != 1 and "s" or "", timeTaken))
|
||||
self.stream.writeln()
|
||||
if not result.wasSuccessful():
|
||||
self.stream.write("FAILED (")
|
||||
failed, errored = map(len, (result.failures, result.errors))
|
||||
if failed:
|
||||
self.stream.write("failures=%d" % failed)
|
||||
if errored:
|
||||
if failed: self.stream.write(", ")
|
||||
self.stream.write("errors=%d" % errored)
|
||||
self.stream.writeln(")")
|
||||
else:
|
||||
self.stream.writeln("OK")
|
||||
return result
|
||||
|
||||
|
||||
|
||||
##############################################################################
|
||||
# Facilities for running tests from the command line
|
||||
##############################################################################
|
||||
|
||||
class TestProgram:
|
||||
"""A command-line program that runs a set of tests; this is primarily
|
||||
for making test modules conveniently executable.
|
||||
"""
|
||||
USAGE = """\
|
||||
Usage: %(progName)s [options] [test] [...]
|
||||
|
||||
Options:
|
||||
-h, --help Show this message
|
||||
-v, --verbose Verbose output
|
||||
-q, --quiet Minimal output
|
||||
|
||||
Examples:
|
||||
%(progName)s - run default set of tests
|
||||
%(progName)s MyTestSuite - run suite 'MyTestSuite'
|
||||
%(progName)s MyTestCase.testSomething - run MyTestCase.testSomething
|
||||
%(progName)s MyTestCase - run all 'test*' test methods
|
||||
in MyTestCase
|
||||
"""
|
||||
def __init__(self, module='__main__', defaultTest=None,
|
||||
argv=None, testRunner=None, testLoader=defaultTestLoader):
|
||||
if type(module) == type(''):
|
||||
self.module = __import__(module)
|
||||
for part in string.split(module,'.')[1:]:
|
||||
self.module = getattr(self.module, part)
|
||||
else:
|
||||
self.module = module
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
self.verbosity = 1
|
||||
self.defaultTest = defaultTest
|
||||
self.testRunner = testRunner
|
||||
self.testLoader = testLoader
|
||||
self.progName = os.path.basename(argv[0])
|
||||
self.parseArgs(argv)
|
||||
self.runTests()
|
||||
|
||||
def usageExit(self, msg=None):
|
||||
if msg: print msg
|
||||
print self.USAGE % self.__dict__
|
||||
sys.exit(2)
|
||||
|
||||
def parseArgs(self, argv):
|
||||
import getopt
|
||||
try:
|
||||
options, args = getopt.getopt(argv[1:], 'hHvq',
|
||||
['help','verbose','quiet'])
|
||||
for opt, value in options:
|
||||
if opt in ('-h','-H','--help'):
|
||||
self.usageExit()
|
||||
if opt in ('-q','--quiet'):
|
||||
self.verbosity = 0
|
||||
if opt in ('-v','--verbose'):
|
||||
self.verbosity = 2
|
||||
if len(args) == 0 and self.defaultTest is None:
|
||||
self.test = self.testLoader.loadTestsFromModule(self.module)
|
||||
return
|
||||
if len(args) > 0:
|
||||
self.testNames = args
|
||||
else:
|
||||
self.testNames = (self.defaultTest,)
|
||||
self.createTests()
|
||||
except getopt.error, msg:
|
||||
self.usageExit(msg)
|
||||
|
||||
def createTests(self):
|
||||
self.test = self.testLoader.loadTestsFromNames(self.testNames,
|
||||
self.module)
|
||||
|
||||
def runTests(self):
|
||||
if self.testRunner is None:
|
||||
self.testRunner = TextTestRunner(verbosity=self.verbosity)
|
||||
result = self.testRunner.run(self.test)
|
||||
sys.exit(not result.wasSuccessful())
|
||||
|
||||
main = TestProgram
|
||||
|
||||
|
||||
##############################################################################
|
||||
# Executing this module from the command line
|
||||
##############################################################################
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(module=None)
|
Loading…
Reference in New Issue