Commits

marcus  committed 2c7afa3

Fixed C doc string creator.
Fixed Mask.convolve() method argument checks.
Fixed base C API and SDL C API NULL arguments.
Added Mask.convolve() tests from trunk.

  • Participants
  • Parent commits a2ec942
  • Branches pgreloaded

Comments (0)

Files changed (5)

File doc/create_cref.py

 except ImportError:
     import io as stringio
 
-def prepare_text (text):
+def prepare_text (text, stripbefore=False):
     newtext = ""
     tmptext = ""
+    if stripbefore:
+        text = text.strip ("\n")
     text = text.replace ("\"", "\\\"")
     lines = text.split ("\n")
-    nn = "normalize" in text
+    
         
     for l in lines:
         l = l.strip ().replace ("::", "")
             l = l.replace (":const:", "       ")
             l = l.replace (":class:", "       ")
             l = l.replace (":meth:", "      ")
+            l = l.replace (":attr:", "      ")
             l = l.replace (":ref:", "     ")
             l = l.replace (":exc:", "     ")
             l = l.replace ("`", " ")
             l = l.replace (":const:", "")
             l = l.replace (":class:", "")
             l = l.replace (":meth:", "")
+            l = l.replace (":attr:", "")
             l = l.replace (":ref:", "")
             l = l.replace (":exc:", "")
             l = l.replace ("`", "")
         l = l.replace (".. note::", "NOTE:")
 
         tmptext += l + "\\n"
-    tmptext = tmptext.replace ("\\n", "")
+    tmptext = tmptext.strip ("\\n")
     while len (tmptext) > 1900:
         # Split after 2000 characters to avoid problems with the Visual
         # C++ 2048 character limit.
     node = module.getElementsByTagName ("desc")
     if node and node[0].firstChild:
         desc = node[0].firstChild.nodeValue
-        desc = prepare_text (desc)
+        desc = prepare_text (desc, True)
     
     buf.write ("#ifndef _PYGAME2_DOC%s_H_\n" % headname)
     buf.write ("#define _PYGAME2_DOC%s_H_\n\n" % headname)
         call = ""
         node = func.getElementsByTagName ("call")
         if node and node[0].firstChild:
-            call = node[0].firstChild.nodeValue + "\n"
+            call = node[0].firstChild.nodeValue
         node = func.getElementsByTagName ("desc")
-        desc = call
+        desc = ""
         if node and node[0].firstChild:
             desc += node[0].firstChild.nodeValue
         desc = prepare_text (desc)
-        buf.write ("#define %s \"%s\"\n" % (docprefix + name, desc))
+        call = prepare_text (call, True)
+        buf.write ("#define %s \"%s\\n\\n%s\"\n" % \
+                   (docprefix + name, call, desc))
     
 def create_class_refs (module, docprefix, buf):
     classes = module.getElementsByTagName ("class")
         node = cls.getElementsByTagName ("constructor")
         constructor = "TODO\n"
         if node and node[0].firstChild:
-            constructor = node[0].firstChild.nodeValue + "\n"
-        desc = constructor
+            constructor = node[0].firstChild.nodeValue
+            constructor = prepare_text (constructor, True)
+        desc = ""
         node = cls.getElementsByTagName ("desc")
         if node and node[0].firstChild:
             desc += node[0].firstChild.nodeValue
         desc = prepare_text (desc)
-        buf.write ("#define %s \"%s\"\n" % (docprefix + name, desc))
+        constructor
+        buf.write ("#define %s \"%s\\n\\n%s\"\n" % \
+                   (docprefix + name, constructor, desc))
 
         attrs = cls.getElementsByTagName ("attr")
         attrprefix = docprefix + name + "_"
     desc = ""
     node = method.getElementsByTagName ("call")
     if node and node[0].firstChild:
-        call = node[0].firstChild.nodeValue + "\n"
+        call = node[0].firstChild.nodeValue
     node = method.getElementsByTagName ("desc")
     if node and node[0].firstChild:
         desc += node[0].firstChild.nodeValue
     desc = prepare_text (desc)
-    call = prepare_text (call)
+    call = prepare_text (call, True)
     buf.write ("#define %s \"%s\\n\\n%s\"\n" % (prefix + name, call, desc))
 
 def create_c_header (infile, outfile):

File src/base/basemod.c

     PyObject* floatobj;
     double tmp;
 
+    if (!obj || !val)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
+
     if (PyNumber_Check (obj))
     {
         if (!(floatobj = PyNumber_Float (obj)))
 {
     PyObject* intobj;
     long tmp;
+
+    if (!obj || !val)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
     
     if (PyNumber_Check (obj))
     {
     PyObject* intobj;
     long tmp;
     
+    if (!obj || !val)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
+
     if (PyNumber_Check (obj))
     {
         if (!(intobj = PyNumber_Int (obj)))
 {
     int result = 0;
     PyObject* item;
+
+    if (!obj || !val)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
+
     item = PySequence_GetItem (obj, _index);
     if (item)
     {
 {
     int result = 0;
     PyObject* item;
+
+    if (!obj || !val)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
+
     item = PySequence_GetItem (obj, _index);
     if (item)
     {
 {
     int result = 0;
     PyObject* item;
+
+    if (!obj || !val)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
+
     item = PySequence_GetItem (obj, _index);
     if (item)
     {
 int
 PointFromObject (PyObject *obj, int *x, int *y)
 {
+    if (!obj || !x || !y)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
+
     if (PyRect_Check (obj))
     {
         *x = (int) ((PyRect*)obj)->x;
 int
 FPointFromObject (PyObject *obj, double *x, double *y)
 {
+    if (!obj || !x || !y)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
+
     if (PyRect_Check (obj))
     {
         *x = (double) ((PyRect*)obj)->x;
 int
 SizeFromObject (PyObject *obj, pgint32 *w, pgint32 *h)
 {
+    if (!obj || !w || !h)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
+
     if (PyRect_Check (obj))
     {
         *w = (pgint32) ((PyRect*)obj)->w;
 int
 FSizeFromObject (PyObject *obj, double *w, double *h)
 {
+    if (!obj || !w || !h)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
+
     if (PyRect_Check (obj))
     {
         *w = (double) ((PyRect*)obj)->w;
 int
 ASCIIFromObject (PyObject *obj, char **text, PyObject **freeme)
 {
+    if (!obj || !text || !freeme)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
+
     *freeme = NULL;
     *text = NULL;
 
 int
 UTF8FromObject (PyObject *obj, char **text, PyObject **freeme)
 {
+    if (!obj || !text || !freeme)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
+
     *freeme = NULL;
     *text = NULL;
 

File src/mask/mask.c

 static PyObject*
 _mask_convolve (PyObject* self, PyObject* args)
 {
-    PyObject *pt, *cmask, *outmask = NULL;
+    PyObject *pt = NULL, *cmask, *outmask = NULL;
     bitmask_t *a, *b, *o;
     int x = 0, y = 0;
 
-    if (!PyArg_ParseTuple (args, "O!|OO", &PyMask_Type, &cmask, &outmask, &pt))
+    if (!PyArg_ParseTuple (args, "O|OO", &cmask, &outmask, &pt))
     {
         PyErr_Clear ();
         if (!PyArg_ParseTuple (args, "O|Oii", &cmask, &outmask, &x, &y))
             return NULL;
     }
-    else
+    else if (pt)
     {
         if (!PointFromObject (pt, &x, &y))
             return NULL;
     }
     
-    if (outmask && !PyMask_Check (outmask))
+    if (cmask && !PyMask_Check (cmask))
     {
-        PyErr_SetString (PyExc_TypeError, "outmask must be a Mask");
+        PyErr_SetString (PyExc_TypeError, "mask must be a Mask");
         return NULL;
     }
+
+    if (outmask && outmask != Py_None && !PyMask_Check (outmask))
+    {
+        PyErr_SetString (PyExc_TypeError, "outputmask must be a Mask");
+        return NULL;
+    }
+
     a = PyMask_AsBitmask (self);
     b = PyMask_AsBitmask (cmask);
 
     /* outmask->w < a->w + b->w - 1 && outmask->h < a->h + b->h - 1 is
      * automatically handled by the convolve/bitmask_draw functions */
-    if (!outmask)
+    if (!outmask || outmask == Py_None)
     {
         outmask = PyMask_New (a->w + b->w - 1, a->h + b->h  - 1);
         if (!outmask)
         Py_INCREF (outmask);
 
     o = PyMask_AsBitmask (outmask);
-    
+
     bitmask_convolve(a, b, o, x, y);
 
     return outmask;

File src/sdl/sdlmod.c

     PyObject* intobj;
     long tmp;
     
+    if (!item || !val)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
+
     if (PyNumber_Check (item))
     {
         if (!(intobj = PyNumber_Int (item)))
     PyObject* intobj;
     long tmp;
     
+    if (!item || !val)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
+
     if (PyNumber_Check (item))
     {
         if (!(intobj = PyNumber_Int (item)))
     PyObject* intobj;
     long tmp;
     
+    if (!item || !val)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
+
     if (PyNumber_Check (item))
     {
         if (!(intobj = PyNumber_Int (item)))
     PyObject* longobj;
     unsigned long tmp;
     
+    if (!item || !val)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
+
     if (PyNumber_Check (item))
     {
         if (!(longobj = PyNumber_Long (item)))
 {
     int result = 0;
     PyObject* item;
+
+    if (!obj || !val)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
+
     item = PySequence_GetItem (obj, _index);
     if (item)
     {
 {
     int result = 0;
     PyObject* item;
+
+    if (!obj || !val)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
+
     item = PySequence_GetItem (obj, _index);
     if (item)
     {
 {
     int result = 0;
     PyObject* item;
+
+    if (!obj || !val)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
+
     item = PySequence_GetItem (obj, _index);
     if (item)
     {
 {
     int result = 0;
     PyObject* item;
+
+    if (!obj || !val)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
+
     item = PySequence_GetItem (obj, _index);
     if (item)
     {
 static int
 IsValidRect (PyObject* rect)
 {
+    if (!rect)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
+    
     if (PyRect_Check (rect) || PyFRect_Check (rect))
         return 1;
     else if (PySequence_Check (rect) && PySequence_Size (rect) == 4)
 static int
 SDLRect_FromRect (PyObject* rect, SDL_Rect *sdlrect)
 {
+    if (!rect || !sdlrect)
+    {
+        PyErr_SetString (PyExc_TypeError, "argument is NULL");
+        return 0;
+    }
+
     if (PyRect_Check (rect))
     {
         sdlrect->x = (Sint16) ((PyRect*)rect)->x;

File test/mask_test.py

 except:
     import pgunittest as unittest
 
+import random
 import pygame2
 import pygame2.mask
 from pygame2.mask import Mask
 import pygame2.sdl.video as video
 import pygame2.sdl.constants as sdlconst
 
+
+def random_mask(size = (100,100)):
+    """random_mask(size=(100,100)): return Mask
+    Create a mask of the given size, with roughly half the bits set at
+    random."""
+    m = Mask(size)
+    for i in range(size[0] * size[1] // 2):
+        x, y = random.randint(0,size[0] - 1), random.randint(0, size[1] - 1)
+        m.set_at((x,y))
+    return m
+
 class MaskTest (unittest.TestCase):
+
+    def assertMaskEquals(self, m1, m2):
+        self.assertEquals(m1.size, m2.size)
+        for i in range(m1.size[0]):
+            for j in range(m1.size[1]):
+                self.assertEquals(m1.get_at((i,j)), m2.get_at((i,j)))
+
     def todo_test_pygame2_mask_Mask_angle(self):
 
         # __doc__ (as of 2008-11-03) for pygame2.mask.Mask.angle:
         self.assertEquals(len(comps2), 1)
         self.assertEquals(len(comps3), 0)
 
+
     def todo_test_pygame2_mask_Mask_count(self):
 
         # __doc__ (as of 2008-11-03) for pygame2.mask.Mask.count:
 
         self.fail() 
 
+    def test_pygame2_mask_Mask_convolve(self):
+
+        # __doc__ (as of 2009-05-11) for pygame2.mask.Mask.convolve:
+
+        # Mask.convolve (mask[, outputmask, point]) -> Mask
+        #
+        # Return the convolution with another Mask.Returns a Mask with
+        # the [x-offset[0], y-offset[1]] bitset if shifting *mask* so
+        # that it's lower right corner pixel isat (x, y) would cause it
+        # to overlap with self.If an *outputmask* is specified, the
+        # output is drawn onto*outputmask* and *outputmask* is
+        # returned. Otherwise a mask ofsize size + *mask*.size - (1, 1)
+        # is created.
+        m1 = random_mask((100,100))
+        m2 = random_mask((100,100))
+        conv = m1.convolve(m2)
+        for i in range(conv.size[0]):
+            for j in range(conv.size[1]):
+                self.assertEquals(conv.get_at((i,j)) == 0,
+                                  m1.overlap(m2, (i - 99, j - 99)) is None)
+
     def test_pygame2_mask_Mask_draw(self):
 
         # __doc__ (as of 2008-11-03) for pygame2.mask.Mask.draw:
 
         self.fail() 
 
-    def todo_test_pygame2_mask_Mask_fill(self):
+    def test_pygame2_mask_Mask_fill(self):
 
         # __doc__ (as of 2008-11-03) for pygame2.mask.Mask.fill:
 
         # Mask.fill () -> None
         # 
         # Sets all bits to 1 within the Mask.
-
-        self.fail() 
+        m = Mask((100,100))
+        self.assertEqual(m.count, 0)
+        
+        m.fill()
+        self.assertEqual(m.count, 10000)
 
     def todo_test_pygame2_mask_Mask_get_at(self):
 
             self.assertEqual (mask.get_bounding_rects(),
                               [pygame2.Rect (40, 40, 10, 10)])
 
+    def test_drawing (self):
+        """ Test fill, clear, invert, draw, erase
+        """
+        m = Mask((100,100))
+        self.assertEqual(m.count, 0)
+        
+        m.fill()
+        self.assertEqual(m.count, 10000)
+
+        m2 = Mask((10,10))
+        m2.fill()
+        m.erase(m2, (50,50))
+        self.assertEqual(m.count, 9900)
+        
+        m.invert()
+        self.assertEqual(m.count, 100)
+        
+        m.draw(m2, (0,0))
+        self.assertEqual(m.count, 200)    
+        
+        m.clear()
+        self.assertEqual(m.count, 0)
+
+
+    def test_convolve__size(self):
+        sizes = [(1,1), (31,31), (32,32), (100,100)]
+        for s1 in sizes:
+            m1 = Mask(s1)
+            for s2 in sizes:
+                m2 = Mask(s2)
+                o = m1.convolve(m2)
+                for i in (0,1):
+                    self.assertEquals(o.size[i], m1.size[i] + m2.size[i] - 1)
+
+    def test_convolve__point_identities(self):
+        """Convolving with a single point is the identity, while
+        convolving a point with something flips it."""
+        m = random_mask((100,100))
+        k = Mask((1,1))
+        k.set_at((0,0))
+
+        self.assertMaskEquals(m,m.convolve(k))
+        self.assertMaskEquals(m,k.convolve(k.convolve(m)))
+
+    def test_convolve__with_output(self):
+        """checks that convolution modifies only the correct portion of
+        the output"""
+        m = random_mask((10,10))
+        k = Mask((2,2))
+        k.set_at((0,0))
+
+        o = Mask((50,50))
+        test = Mask((50,50))
+
+        m.convolve(k,o)
+        test.draw(m,(1,1))
+        self.assertMaskEquals(o, test)
+
+        o.clear()
+        test.clear()
+
+        m.convolve(k,o, (10,10))
+        test.draw(m,(11,11))
+        self.assertMaskEquals(o, test)
+
+    def test_convolve__out_of_range(self):
+        full = Mask((2,2))
+        full.fill()
+
+        self.assertEquals(full.convolve(full, None, ( 0,  3)).count, 0)
+        self.assertEquals(full.convolve(full, None, ( 0,  2)).count, 3)
+        self.assertEquals(full.convolve(full, None, (-2, -2)).count, 1)
+        self.assertEquals(full.convolve(full, None, (-3, -3)).count, 0)
+
 if __name__ == "__main__":
     unittest.main ()