bug-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC] Method List Manipulation API


From: David Ayers
Subject: [RFC] Method List Manipulation API
Date: Fri, 04 Jun 2004 23:13:01 +0200
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040514

Hello,

Here is proposed patch to provide a method list manipulation API:
I hope the documentation speaks for itself. If not I open for suggestions. Here's an overview of the functions:

typedef struct objc_method      *GSMethod;

GSMethodList
GSAllocMethodList (unsigned int count);

void
GSAppendMethodToList (GSMethodList list,
                      SEL sel,
                      const char *types,
                      IMP imp,
                      BOOL isFree);

BOOL
GSRemoveMethodFromList (GSMethodList list,
                        SEL sel,
                        BOOL isFree);
GSMethod
GSMethodFromList(GSMethodList list,
                 SEL sel,
                 BOOL isFree);

void
GSAddMethodList(Class class,
                GSMethodList list,
                BOOL toInstanceMethods);

void
GSRemoveMethodList(Class class,
                   GSMethodList list,
                   BOOL fromInstanceMethods);

Note that this patch merely introduces the new functions. I'll have a follow up to use the new functions within the
GSObjCAddMethods, GSObjCAddClassBehavior and some of the internal methods.

Comments welcome.

Cheers,
David
Index: Headers/Additions/GNUstepBase/GSObjCRuntime.h
===================================================================
RCS file: 
/cvsroot/gnustep/gnustep/core/base/Headers/Additions/GNUstepBase/GSObjCRuntime.h,v
retrieving revision 1.6
diff -u -r1.6 GSObjCRuntime.h
--- Headers/Additions/GNUstepBase/GSObjCRuntime.h       9 May 2004 19:29:14 
-0000       1.6
+++ Headers/Additions/GNUstepBase/GSObjCRuntime.h       4 Jun 2004 17:40:15 
-0000
@@ -357,12 +357,14 @@
 
 
 /*
- * Unfortunately the definition of the symbol 'Method' "IVar(_t)"
- * is incompatible between the GNU and NeXT/Apple runtimes.
- * We introduce GSMethod and GSIVar to allow portability.
+ * Unfortunately the definition of the symbols
+ * 'Method(_t)', 'MethodList(_t)'  and 'IVar(_t)'
+ * are incompatible between the GNU and NeXT/Apple runtimes.
+ * We introduce GSMethod, GSMethodList and GSIVar to allow portability.
  */
-typedef struct objc_method *GSMethod;
-typedef struct objc_ivar   *GSIVar;
+typedef struct objc_method      *GSMethod;
+typedef struct objc_method_list *GSMethodList;
+typedef struct objc_ivar        *GSIVar;
 
 /**
  * Returns the pointer to the instance method structure
@@ -475,6 +477,158 @@
  */
 GS_EXPORT GSIVar
 GSObjCGetInstanceVariableDefinition(Class class, NSString *name);
+
+/**
+ * <p>Returns a pointer to objc_malloc'ed memory large enough
+ * to hold a struct objc_method_list with 'count' number of
+ * struct objc_method entries.  The memory returned is
+ * initialized with 0, including the method count and
+ * next method list fields.  </p>
+ * <p> This function is intended for use in conjunction with
+ * GSAppendMethodToList() to fill the memory and GSAddMethodList()
+ * to activate the method list.  </p>
+ * <p>After method list manipulation you should call
+ * GSFlushMethodCacheForClass() for the changes to take effect.</p>
+ * <p><em>WARNING:</em> Manipulating the runtime structures
+ * can be hazardous!</p>
+ * <p>This function should currently (June 2004) be considered WIP.
+ * Please follow potential changes (Name, parameters, ...) closely until
+ * it stabilizes.</p>
+ */
+GSMethodList
+GSAllocMethodList (unsigned int count);
+
+/**
+ * <p>Inserts the method described by sel, types amd imp
+ * into the slot of the list's method_count incremented by 1.
+ * This function does not and cannot check whether
+ * the list provided has the necessary capacity.</p>
+ * <p>The GNU runtime makes a difference between method lists
+ * that are "free standing" and those that "attached" to classes.
+ * For "free standing" method lists (e.g. created with GSAllocMethodList()
+ * that have not been added to a class or those which have been removed
+ * via GSRemoveMethodList()) isFree must be passed YES.
+ * When manipulating "attached" method lists, specify NO.</p>
+ * <p>This function is intended for use in conjunction with
+ * GSAllocMethodList() to allocate the list and GSAddMethodList()
+ * to activate the method list. </p>
+ * <p>After method list manipulation you should call
+ * GSFlushMethodCacheForClass() for the changes to take effect.</p>
+ * <p><em>WARNING:</em> Manipulating the runtime structures
+ * can be hazardous!</p>
+ * <p>This function should currently (June 2004) be considered WIP.
+ * Please follow potential changes (Name, parameters, ...) closely until
+ * it stabilizes.</p>
+ */
+void
+GSAppendMethodToList (GSMethodList list,
+                     SEL sel,
+                     const char *types,
+                     IMP imp,
+                     BOOL isFree);
+
+/**
+ * <p>Removes the method identified by sel
+ * from the method list moving the following methods up in the list,
+ * leaving the last entry blank.</p>
+ * <p)Returns YES if the a matching method was found a removed,
+ * NO otherwise.</p>
+ * <p>The GNU runtime makes a difference between method lists
+ * that are "free standing" and those that "attached" to classes.
+ * For "free standing" method lists (e.g. created with GSAllocMethodList()
+ * that have not been added to a class or those which have been removed
+ * via GSRemoveMethodList()) isFree must be passed YES.
+ * When manipulating "attached" method lists, specify NO.</p>
+ * <p>After method list manipulation you should call
+ * GSFlushMethodCacheForClass() for the changes to take effect.</p>
+ * <p><em>WARNING:</em> Manipulating the runtime structures
+ * can be hazardous!</p>
+ * <p>This function should currently (June 2004) be considered WIP.
+ * Please follow potential changes (Name, parameters, ...) closely until
+ * it stabilizes.</p>
+ */
+BOOL
+GSRemoveMethodFromList (GSMethodList list,
+                       SEL sel,
+                       BOOL isFree);
+
+/**
+ * <p>Returns a method list of the class that contains the selector.
+ * Depeding on searchInstanceMethods either instance or class methods
+ * are searched.
+ * Returns NULL if none are found.
+ * This function does not search the superclasses method lists.
+ * Call this method with the address of a <code>void *</code>
+ * pointing to NULL to obtain the first (active) method list
+ * containing the selector.
+ * Subsequent calls will return further method lists which contain the
+ * selector.  If none are found, it returns NULL.
+ * You may instead pass NULL as the iterator in which case the first
+ * method list containing the selecetor will be returned.
+ * Do not call it with an uninitialized iterator.
+ * If either class or selector are NULL the function returns NULL.
+ * If subsequent calls to this function with the same non-NULL iterator yet
+ * different searchInstanceMethods value are called, the behavior
+ * is undefined.</p>
+ * <p>This function should currently (June 2004) be considered WIP.
+ * Please follow potential changes (Name, parameters, ...) closely until
+ * it stabilizes.</p>
+ */
+GSMethodList
+GSMethodListForSelector(Class class,
+                       SEL selector,
+                       void **iterator,
+                       BOOL searchInstanceMethods);
+
+/**
+ * <p>Returns the (first) GSMethod contained in the supplied list
+ * that cooresponds to sel.
+ * Returns NULL if none is found.<p/>
+ * <p>The GNU runtime makes a difference between method lists
+ * that are "free standing" and those that "attached" to classes.
+ * For "free standing" method lists (e.g. created with GSAllocMethodList()
+ * that have not been added to a class or those which have been removed
+ * via GSRemoveMethodList()) isFree must be passed YES.
+ * When manipulating "attached" method lists, specify NO.</p>
+ */
+GSMethod
+GSMethodFromList(GSMethodList list,
+                SEL sel,
+                BOOL isFree);
+
+/**
+ * <p>Add the method list to the class as the first list to be
+ * searched during method invocation for the given class.
+ * Depending on toInstanceMethods, this list will be added as 
+ * an instance or a class method list.
+ * If the list is in use by another class, behavior is undefined.
+ * Create a new list with GSAllocMethodList() or use GSRemoveMethodList()
+ * to remove a list before inserting it in a class.</p>
+ * <p>After method list manipulation you should call
+ * GSFlushMethodCacheForClass() for the changes to take effect.</p>
+ * <p>This function should currently (June 2004) be considered WIP.
+ * Please follow potential changes (Name, parameters, ...) closely until
+ * it stabilizes.</p>
+ */
+void
+GSAddMethodList(Class class,
+               GSMethodList list,
+               BOOL toInstanceMethods);
+
+/**
+ * <p>Removes the method list from the classes instance or class method
+ * lists depending on fromInstanceMethods.
+ * If the list is not part of the class, behavior is undefined.</p>
+ * <p>After method list manipulation you should call
+ * GSFlushMethodCacheForClass() for the changes to take effect.</p>
+ * <p>This function should currently (June 2004) be considered WIP.
+ * Please follow potential changes (Name, parameters, ...) closely until
+ * it stabilizes.</p>
+ */
+void
+GSRemoveMethodList(Class class,
+                  GSMethodList list,
+                  BOOL fromInstanceMethods);
 
 
 /**
Index: Source/Additions/GSObjCRuntime.m
===================================================================
RCS file: /cvsroot/gnustep/gnustep/core/base/Source/Additions/GSObjCRuntime.m,v
retrieving revision 1.37
diff -u -r1.37 GSObjCRuntime.m
--- Source/Additions/GSObjCRuntime.m    4 Jun 2004 13:58:36 -0000       1.37
+++ Source/Additions/GSObjCRuntime.m    4 Jun 2004 17:40:16 -0000
@@ -816,6 +816,256 @@
 }
 
 /* See header for documentation. */
+GSMethodList
+GSAllocMethodList (unsigned int count)
+{
+  GSMethodList list;
+  size_t size;
+
+  size = (sizeof (struct objc_method_list) +
+          sizeof (struct objc_method[count]));
+  list = objc_malloc (size);
+  memset(list, 0, size);
+
+  return list;
+}
+
+/* See header for documentation. */
+void
+GSAppendMethodToList (GSMethodList list,
+                      SEL sel,
+                      const char *types,
+                      IMP imp,
+                      BOOL isFree)
+{
+  unsigned int num;
+
+  num = (list->method_count)++;
+
+#ifdef GNU_RUNTIME
+  /* 
+     Deal with typed selectors: No matter what kind of selector we get
+     convert it into a c-string.  Cache that c-string incase the 
+     selector isn't found, then search for cooresponding typed selector.
+     If none is found use the cached name to register an new selector
+     with the cooresponding types.
+   */
+  sel = (SEL)GSNameFromSelector (sel);
+
+  if (isFree == NO)
+    {
+      const char *sel_save = (const char *)sel;
+
+      sel = sel_get_typed_uid (sel_save, types);
+      if (sel == 0)
+        {
+          sel = sel_register_typed_name (sel_save, types);
+        }
+    }
+#endif
+
+  list->method_list[num].method_name = sel;
+  list->method_list[num].method_types = types;
+  list->method_list[num].method_imp = imp;
+}
+
+/* See header for documentation. */
+BOOL
+GSRemoveMethodFromList (GSMethodList list,
+                        SEL sel,
+                        BOOL isFree)
+{
+  int i;
+
+#ifdef GNU_RUNTIME
+  if (isFree == YES)
+    {
+      sel = (SEL)GSNameFromSelector (sel);
+    }
+#else
+  /* Insure that we always use sel_eq on non GNU Runtimes.  */
+  isFree = NO;
+#endif
+
+  for (i = 0; i < list->method_count; i++)
+    {
+      SEL  method_name = list->method_list[i].method_name;
+
+      /* For the GNU runtime we have use strcmp instead of sel_eq
+        for free standing method lists.  */
+      if ((isFree == YES && strcmp((char *)method_name, (char *)sel) == 0)
+          || (isFree == NO && sel_eq(method_name, sel)))
+        {
+         /* Found the list.  Now fill up the gap.  */
+          for ((list->method_count)--; i < list->method_count; i++)
+            {
+              list->method_list[i].method_name
+                = list->method_list[i+1].method_name;
+              list->method_list[i].method_types
+                = list->method_list[i+1].method_types;
+              list->method_list[i].method_imp
+                = list->method_list[i+1].method_imp;
+            }
+
+         /* Clear the last entry.  */
+          list->method_list[i].method_name = 0;
+          list->method_list[i].method_types = 0;
+          list->method_list[i].method_imp = 0;
+
+          return YES;
+        }
+    }
+  return NO;
+}
+
+/* See header for documentation. */
+GSMethodList
+GSMethodListForSelector(Class class,
+                        SEL selector,
+                        void **iterator,
+                        BOOL searchInstanceMethods)
+{
+  void *local_iterator = 0;
+
+  if (class == 0 || selector == 0)
+    {
+      return 0;
+    }
+
+  if (searchInstanceMethods == NO)
+    {
+      class = class->class_pointer;
+    }
+
+  if(sel_is_mapped(selector))
+    {
+      void **iterator_pointer;
+      GSMethodList method_list;
+
+      iterator_pointer = (iterator == 0 ? &local_iterator : iterator);
+      while((method_list = class_nextMethodList(class, iterator_pointer)))
+        {
+         /* Search the method in the current list.  */
+         if (GSMethodFromList(method_list, selector, NO) != 0)
+           {
+             return method_list;
+           }
+        }
+    }
+
+  return 0;
+}
+
+/* See header for documentation. */
+GSMethod
+GSMethodFromList(GSMethodList list,
+                 SEL sel, 
+                BOOL isFree)
+{
+  unsigned i;
+
+#ifdef GNU_RUNTIME
+  if (isFree)
+    {
+      sel = (SEL)GSNameFromSelector (sel);
+    }
+#else
+  isFree = NO;
+#endif
+
+  for(i = 0; i < list->method_count; ++i)
+    {
+      GSMethod method = &list->method_list[i];
+      SEL  method_name = method->method_name;
+
+      /* For the GNU runtime we have use strcmp instead of sel_eq
+        for free standing method lists.  */
+      if ((isFree == YES && strcmp((char *)method_name, (char *)sel) == 0)
+          || (isFree == NO && sel_eq(method_name, sel)))
+       {
+         return method;
+       }
+    }
+  return 0;
+}
+
+/* See header for documentation. */
+void
+GSAddMethodList(Class class,
+                GSMethodList list,
+                BOOL toInstanceMethods)
+{
+  if (class == 0 || list == 0)
+    {
+      return;
+    }
+
+  if (toInstanceMethods == NO)
+    {
+      class = class->class_pointer;
+    }
+
+  class_add_method_list(class, list);
+}
+
+/* See header for documentation. */
+void
+GSRemoveMethodList(Class class,
+                   GSMethodList list,
+                   BOOL fromInstanceMethods)
+{
+  if (class == 0 || list == 0)
+    {
+      return;
+    }
+
+  if (fromInstanceMethods == NO)
+    {
+      class = class->class_pointer;
+    }
+
+#ifdef NeXT_RUNTIME
+  class_removeMethods(class, list);
+#else
+  if (list == class->methods)
+    {
+      class->methods = list->method_next;
+      list->method_next = 0;
+    }
+  else
+    {
+      GSMethodList current_list;
+      for (current_list = class->methods;
+           current_list != 0;
+           current_list = current_list->method_next)
+        {
+          if (current_list->method_next == list)
+            {
+              int i;
+              current_list->method_next = list->method_next;
+              list->method_next = 0;
+
+              /*
+                 The list has become "free standing".
+                 Replace all selector references with selector names
+                 so the runtime can convert them again
+                 it the list gets reinserted.
+             */
+              for (i = 0; i < list->method_count; i++)
+                {
+                  const char *name;
+
+                  name  = GSNameFromSelector(list->method_list[i].method_name);
+                  list->method_list[i].method_name = (SEL)name;
+                }
+            }
+        }
+    }
+#endif /* NeXT_RUNTIME */
+}
+
+
+/* See header for documentation. */
 GSIVar
 GSCGetInstanceVariableDefinition(Class class, const char *name)
 {
Index: Testing/GNUmakefile
===================================================================
RCS file: /cvsroot/gnustep/gnustep/core/base/Testing/GNUmakefile,v
retrieving revision 1.35
diff -u -r1.35 GNUmakefile
--- Testing/GNUmakefile 18 Mar 2004 06:56:12 -0000      1.35
+++ Testing/GNUmakefile 4 Jun 2004 17:40:16 -0000
@@ -37,6 +37,7 @@
                containers \
                exported-strings \
                fref \
+               gsbehavior \
                gslock \
                nsarchiver \
                nsarray \
@@ -86,6 +87,7 @@
 diningPhilosophers_OBJC_FILES = diningPhilosophers.m
 exported-strings_OBJC_FILES = exported-strings.m
 fref_OBJC_FILES = fref.m
+gsbehavior_OBJC_FILES = gsbehavior.m
 gslock_OBJC_FILES = gslock.m
 gstcpport-client_OBJC_FILES = gstcpport-client.m
 gstcpport-server_OBJC_FILES = gstcpport-server.m
Index: Testing/gsbehavior.m
===================================================================
RCS file: Testing/gsbehavior.m
diff -N Testing/gsbehavior.m
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ Testing/gsbehavior.m        4 Jun 2004 17:40:16 -0000
@@ -0,0 +1,308 @@
+/** gsbehavior - Program to test GSObjCAddClassBehavior.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+
+   Written by:  David Ayers  <d.ayers@inode.at>
+
+   This file is part of the GNUstep Base Library.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+   
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
+*/
+
+
+#include <Foundation/NSAutoreleasePool.h>
+#include <Foundation/NSNotification.h>
+#include <Foundation/NSException.h>
+
+#include <GNUstepBase/GSObjCRuntime.h>
+
+/*------------------------------------*/
+@interface MyClass : NSObject
+-(const char *)text;
+@end
+@implementation MyClass
+-(void)myClassMain {};
+-(const char *)text
+{
+  return "class_main";
+}
+@end
+
+@interface  MyClass (Category1)
+-(void)myClassCategory1;
+@end
+@implementation MyClass (Category1)
+-(void)myClassCategory1 {};
+-(const char *)text
+{
+  return "class_category_1";
+}
+@end
+
+@interface  MyClass (Category2)
+-(void)myClassCategory2;
+@end
+@implementation MyClass (Category2)
+-(void)myClassCategory2 {};
+-(const char *)text
+{
+  return "class_category_2";
+}
+@end
+
+/*------------------------------------*/
+
+@interface MyTemplate1 : NSObject
+@end
+@implementation MyTemplate1
+@end
+
+/*------------------------------------*/
+/*------------------------------------*/
+
+@interface MyTemplate2 : NSObject
+-(const char *)text;
+@end
+@implementation MyTemplate2
+-(const char *)text
+{
+  return "template_main";
+}
+@end
+
+/*------------------------------------*/
+
+@interface MyBehavior : NSObject
+-(const char *)text;
+@end
+@implementation MyBehavior
+-(void)myBehaviorMain {};
+-(const char *)text
+{
+  return "behavior_main";
+}
+@end
+@interface  MyBehavior (Category1)
+-(void)myBehaviorCategory1;
+@end
+@implementation MyBehavior (Category1)
+-(void)myBehaviorCategory1 {};
+-(const char *)text
+{
+  return "behavior_category_1";
+}
+@end
+
+@interface  MyBehavior (Category2)
+-(void)myBehaviorCategory2;
+@end
+@implementation MyBehavior (Category2)
+-(void)myBehaviorCategory2 {};
+-(const char *)text
+{
+  return "behavior_category_2";
+}
+@end
+
+/*------------------------------------*/
+
+void
+test_basic(void)
+{
+  id myClass;
+  id myBehavior;
+
+  myClass = [MyClass new];
+  myBehavior = [MyBehavior new];
+
+  NSCAssert(strncmp([myClass text], "class_category", 14) == 0,
+           @"Default implementation isn't Category!");
+  NSCAssert(strncmp([myBehavior text], "behavior_category", 17) == 0,
+           @"Default implementation isn't Category!");
+
+  RELEASE(myClass);
+  RELEASE(myBehavior);
+}
+
+void
+test_create_list(void)
+{
+  GSMethodList myList;
+  GSMethod myMethod;
+  Class myClass;
+  void *it;
+  IMP imp_main;
+  IMP imp_1;
+  IMP imp_2;
+  const char *types;
+  id myObj;
+
+  it = 0;
+  myClass = [MyClass class];
+  myObj = [myClass new];
+  myList = GSMethodListForSelector(myClass, @selector(text), &it, YES);
+  NSCAssert(myList,@"List is NULL!");
+  myMethod = GSMethodFromList(myList, @selector(text), NO);
+  NSCAssert(myMethod,@"Method is NULL!");
+  imp_1 = myMethod->method_imp;
+
+  myList = GSMethodListForSelector(myClass, @selector(text), &it, YES);
+  NSCAssert(myList,@"List is NULL!");
+  myMethod = GSMethodFromList(myList, @selector(text), NO);
+  NSCAssert(myMethod,@"Method is NULL!");
+  imp_2 = myMethod->method_imp;
+
+  myList = GSMethodListForSelector(myClass, @selector(text), &it, YES);
+  NSCAssert(myList,@"List is NULL!");
+  myMethod = GSMethodFromList(myList, @selector(text), NO);
+  NSCAssert(myMethod,@"Method is NULL!");
+  imp_main = myMethod->method_imp;
+
+  types = myMethod->method_types;
+
+  myList = GSAllocMethodList(3);
+  GSAppendMethodToList(myList, @selector(text_main), types, imp_main, YES);
+  GSAppendMethodToList(myList, @selector(text_1), types, imp_1, YES);
+  GSAppendMethodToList(myList, @selector(text_2), types, imp_2, YES);
+
+  GSAddMethodList(myClass, myList, YES);
+  GSFlushMethodCacheForClass(myClass);
+  NSCAssert([myObj respondsToSelector:@selector(text_main)] == YES,
+           @"Add failed.");
+  NSCAssert([myObj respondsToSelector:@selector(text_1)] == YES,
+           @"Add failed.");
+  NSCAssert([myObj respondsToSelector:@selector(text_2)] == YES,
+           @"Add failed.");
+  NSCAssert(strncmp([myObj text_main], "class_main", 10) == 0,
+           @"Add failed to add correct implementation!");
+  NSCAssert(strncmp([myObj text_1], "class_category_1", 16) == 0
+           || strncmp([myObj text_1], "class__category_2", 16),
+           @"Add failed to add correct implementation!");
+  NSCAssert(strncmp([myObj text_2], "class__category_2", 16) == 0
+           || strncmp([myObj text_2], "class__category_1", 16),
+           @"Add failed to add correct implementation!");
+
+}
+
+void
+test_reorder(void)
+{
+  Class myClass;
+  id    myObj;
+  GSMethodList list;
+
+  myClass = [MyClass class];
+  myObj = [MyClass new];
+
+  list = GSMethodListForSelector(myClass, @selector(myClassMain), 0, YES);
+
+  /* Remove */
+  GSRemoveMethodList(myClass, list, YES);
+  GSFlushMethodCacheForClass(myClass);
+  NSCAssert([myObj respondsToSelector:@selector(myClassMain)] == NO,
+           @"Remove failed.");
+
+  /* Add */
+  GSAddMethodList(myClass, list, YES);
+  GSFlushMethodCacheForClass(myClass);
+
+  NSCAssert([myObj respondsToSelector:@selector(myClassMain)] == YES,
+           @"Add failed.");
+  NSCAssert(strncmp([myObj text], "class_main", 14) == 0,
+           @"Add failed to add correct implementation!");
+
+  RELEASE(myClass);
+}
+
+void
+test_behavior1(void)
+{
+  Class myTmplClass;
+  id myTmplObj;
+
+  myTmplClass = [MyTemplate1 class];
+  myTmplObj = [MyTemplate1 new];
+
+  NSCAssert([myTmplObj respondsToSelector:@selector(text)] == NO,
+           @"Initial state invalid");
+  GSObjCAddClassBehavior(myTmplClass, [MyClass class]);
+  NSCAssert([myTmplObj respondsToSelector:@selector(text)] == YES,
+           @"Behavior failed");
+  
+}
+
+
+void
+test_behavior2(void)
+{
+  Class myTmplClass;
+  id myTmplObj;
+
+  myTmplClass = [MyTemplate2 class];
+  myTmplObj = [MyTemplate2 new];
+
+  NSCAssert([myTmplObj respondsToSelector:@selector(myClassCategory1)] == NO,
+           @"Initial state invalid");
+  GSObjCAddClassBehavior(myTmplClass, [MyClass class]);
+  NSCAssert([myTmplObj respondsToSelector:@selector(myClassCategory1)] == YES,
+           @"Behavior failed");
+  
+  NSCAssert(strncmp([myTmplObj text], "template_main", 14) == 0,
+           @"Overwritten existing implementation!");
+}
+
+void
+test_methodnames(void)
+{
+  id obj = [NSNotificationCenter defaultCenter];
+  NSArray *names;
+
+  names = GSObjCMethodNames(obj);
+  NSDebugLog(@"obj:%@", names);
+  names = GSObjCMethodNames([obj class]);
+  NSDebugLog(@"class:%@", names);
+}
+
+int
+main(int argc, char *argv[])
+{
+  NSAutoreleasePool *pool;
+  //  [NSAutoreleasePool enableDoubleReleaseCheck:YES];
+  pool = [[NSAutoreleasePool alloc] init];
+
+  NS_DURING
+    {
+      test_methodnames();
+      test_basic();
+      test_create_list();
+      test_reorder();
+
+      NSLog(@"Behavior Test Succeeded.");
+    }
+  NS_HANDLER
+    {
+      NSLog(@"Behavior Test Failed:");
+      NSLog(@"%@ %@ %@",
+           [localException name],
+           [localException reason],
+           [localException userInfo]);
+      [localException raise];
+    }
+  NS_ENDHANDLER
+
+  [pool release];
+
+  exit(0);
+}
+

reply via email to

[Prev in Thread] Current Thread [Next in Thread]