Commits

Ronald Oussoren committed 9034588

Test for opaque pointers to structures (e.g. the NSModalSession mess).

Comments (0)

Files changed (6)

 Test suite
 ..........
 
-XXX: It might be a good idea to move the unittests to a seperate python
-package (e.g. ``PyObjCTest``) that is not installed. I'd be surprised if anyone
-ever runs the unittests outside of the build tree.
-
 The test suite needs to be enhanced. 
 
 * Somehow find a way to check code-coverage of the unittests.
 
-* Tests that exercise Key-Value Observing in a way that crashes older versions
-  of PyObjC.
+* Tests in the AppKit and Foundation packages that test functionality in
+  the objc package should be moved to the objc package.
+
+* Enhance KVO/KVC tests
 
 * tests for all functions in ``Modules/*/*Mapping*.m``
   (including IMPs)
   rather than descriptors, so that they can be used more easily with tools
   such as PyProtocols dispatch.
 
+  XXX(Ronald): that's only possible for methods with a python implementation,
+  and should result in less code as well. A disadvantage is that this would
+  probably be a backward-incomptable change, but that should not be a problem.
+
 Support for GNUstep
 ...................
 

Lib/objc/test/test_structpointer.py

+import unittest
+import objc
+from objc.test.structpointer2 import *
+from objc.test.structpointer1 import *
+
+class TestOpaqueStructPointer (unittest.TestCase):
+    def testPointer(self):
+
+        # Check that the TestPointerStructPtr has a signature that is 
+        # different from the one in the method definition. The latter contains
+        # more information.
+        retval = objc.splitSignature(
+                OC_TestStructPointer.returnPointerToStruct.signature)[0]
+        self.assertNotEquals(TestStructPointerStructPtr.__typestr__, retval)
+
+        # And then check that the correct pointer wrapper is created
+        v = OC_TestStructPointer.returnPointerToStruct()
+        self.assert_(isinstance(v, TestStructPointerStructPtr))
+
+if __name__ == "__main__":
+    unittest.main()

Modules/objc/objc-class.m

 	 * NOTE: This method should be rewritten, copy the version of type()
 	 *       and modify as needed, that would avoid unnecessary rescans
 	 * 	 of superclasses. The same strategy is used in object_getattro.
+	 *
+	 * NOTE2: That rewrite should also cause this method to prefer class
+	 *       methods over instance methods (and documentation should be 
+	 *       added that you shouldn't look up instance methods through the
+	 *       class).
+	 *       
 	 */
 	if (PyString_Check(name) 
 			&& strncmp(PyString_AS_STRING(name), "__", 2) == 0 

Modules/objc/pointer-support.m

 static struct wrapper* items = 0;
 static int item_count = 0;
 
-static int find_offset(const char* signature) {
+/*
+ * If signature is a pointer to a structure return the index of the character
+ * just beyond the end of the struct name. This information is needed because
+ * @encode(struct foo*) can return two different strings:
+ * 1) ^{foo} if the compiler has not yet seen a full definition of struct foo
+ * 2) ^{foo=...} if the compiler has ssen a full definition of the struct
+ * We want to treat those two pointer as the same type, therefore we need to
+ * ignore everything beyond the end of the struct name.
+ */
+static int find_end_of_structname(const char* signature) {
 	if (signature[1] == _C_STRUCT_B) {
 		int o1, o2;
 
 
 	for (i = 0; i < item_count; i++) {
 		if (strncmp(signature, items[i].signature, items[i].offset) == 0) {
-			return &items[i];
-			if (signature[1] != _C_STRUCT_B || signature[items[i].offset] == '=' || signature[items[i].offset] == _C_STRUCT_E) {
-				return &items[i];
+			/* See comment just above find_end_of_structname */
+			if (signature[1] != _C_STRUCT_B) {
+				if (signature[items[i].offset] == '\0') {
+					return items + i;
+				}
+			} else {
+				char ch = signature[items[i].offset];
+				if (ch == '=' || ch == _C_STRUCT_E) {
+					return items + i;
+				}
 			}
 		}
 	}
 	value = items + (item_count-1);
 
 	value->signature = signature;
-	value->offset = find_offset(signature);
+	value->offset = find_end_of_structname(signature);
 
 	value->pythonify = pythonify;
 	value->depythonify = depythonify;

Modules/objc/test/structpointer1.m

+/*
+ * This module is used in the unittests for object initialize.
+ */
+#include "Python.h"
+#include "pyobjc-api.h"
+
+#import <Foundation/Foundation.h>
+
+static int numUninitialized = 0;
+
+struct TestStructPointerStruct {
+	int i1;
+};
+
+static struct TestStructPointerStruct myGlobal = { 1 };
+
+@interface OC_TestStructPointer : NSObject
+{
+}
++(struct TestStructPointerStruct*)returnPointerToStruct;
+@end
+
+@implementation OC_TestStructPointer
++(struct TestStructPointerStruct*)returnPointerToStruct
+{
+	return &myGlobal;
+}
+@end
+
+
+static PyMethodDef initialize_methods[] = {
+	{ NULL, NULL, NULL, NULL }
+};
+
+void initstructpointer1(void);
+void initstructpointer1(void)
+{
+	PyObject* m;
+
+	m = Py_InitModule4("structpointer1", initialize_methods, 
+			NULL, NULL, PYTHON_API_VERSION);
+
+	PyObjC_ImportAPI(m);
+	PyModule_AddObject(m, "OC_TestStructPointer", 
+		PyObjCClass_New([OC_TestStructPointer class]));
+}

Modules/objc/test/structpointer2.m

+/*
+ * This module is used in the unittests for object initialize.
+ */
+#include "Python.h"
+#include "pyobjc-api.h"
+
+#import <Foundation/Foundation.h>
+
+
+static PyMethodDef initialize_methods[] = {
+	{ NULL, NULL, NULL, NULL }
+};
+
+typedef struct TestStructPointerStruct* Foo;
+
+void initstructpointer2(void);
+void initstructpointer2(void)
+{
+	PyObject* m;
+	PyObject* v;
+
+	m = Py_InitModule4("structpointer2", initialize_methods, 
+			NULL, NULL, PYTHON_API_VERSION);
+
+	PyObjC_ImportAPI(m);
+	v = PyObjCCreateOpaquePointerType("TestStructPointerStructPtr",
+			@encode(Foo), NULL);
+	if (v == NULL) return;
+	PyDict_SetItemString(PyModule_GetDict(m), "TestStructPointerStructPtr",
+			v);
+}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.