GTMDebugSelectorValidation.h 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. //
  2. // GTMDebugSelectorValidation.h
  3. //
  4. // This file should only be included within an implimation file. In any
  5. // function that takes an object and selector to invoke, you should call:
  6. //
  7. // GTMAssertSelectorNilOrImplementedWithArguments(obj, sel, @encode(arg1type), ..., NULL)
  8. // or
  9. // GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(obj, sel, @encode(returnType), @encode(arg1type), ..., NULL)
  10. //
  11. // This will then validate that the selector is defined and using the right
  12. // type(s), this can help catch errors much earlier then waiting for the
  13. // selector to actually fire (and in the case of error selectors, might never
  14. // really be tested until in the field).
  15. //
  16. // Copyright 2007-2008 Google Inc.
  17. //
  18. // Licensed under the Apache License, Version 2.0 (the "License"); you may not
  19. // use this file except in compliance with the License. You may obtain a copy
  20. // of the License at
  21. //
  22. // http://www.apache.org/licenses/LICENSE-2.0
  23. //
  24. // Unless required by applicable law or agreed to in writing, software
  25. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  26. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  27. // License for the specific language governing permissions and limitations under
  28. // the License.
  29. //
  30. #if DEBUG
  31. #import <stdarg.h>
  32. #import "GTMDefines.h"
  33. static void GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(id obj, SEL sel, const char *retType, ...) {
  34. // verify that the object's selector is implemented with the proper
  35. // number and type of arguments
  36. va_list argList;
  37. va_start(argList, retType);
  38. if (obj && sel) {
  39. // check that the selector is implemented
  40. _GTMDevAssert([obj respondsToSelector:sel],
  41. @"\"%@\" selector \"%@\" is unimplemented or misnamed",
  42. NSStringFromClass([obj class]),
  43. NSStringFromSelector(sel));
  44. const char *expectedArgType;
  45. NSUInteger argCount = 2; // skip self and _cmd
  46. NSMethodSignature *sig = [obj methodSignatureForSelector:sel];
  47. // check that each expected argument is present and of the correct type
  48. while ((expectedArgType = va_arg(argList, const char*)) != 0) {
  49. if ([sig numberOfArguments] > argCount) {
  50. const char *foundArgType = [sig getArgumentTypeAtIndex:argCount];
  51. _GTMDevAssert(0 == strncmp(foundArgType, expectedArgType, strlen(expectedArgType)),
  52. @"\"%@\" selector \"%@\" argument %u should be type %s",
  53. NSStringFromClass([obj class]),
  54. NSStringFromSelector(sel),
  55. (uint32_t)(argCount - 2),
  56. expectedArgType);
  57. }
  58. argCount++;
  59. }
  60. // check that the proper number of arguments are present in the selector
  61. _GTMDevAssert(argCount == [sig numberOfArguments],
  62. @"\"%@\" selector \"%@\" should have %u arguments",
  63. NSStringFromClass([obj class]),
  64. NSStringFromSelector(sel),
  65. (uint32_t)(argCount - 2));
  66. // if asked, validate the return type
  67. if (retType && (strcmp("gtm_skip_return_test", retType) != 0)) {
  68. const char *foundRetType = [sig methodReturnType];
  69. _GTMDevAssert(0 == strncmp(foundRetType, retType, strlen(retType)),
  70. @"\"%@\" selector \"%@\" return type should be type %s",
  71. NSStringFromClass([obj class]),
  72. NSStringFromSelector(sel),
  73. retType);
  74. }
  75. }
  76. va_end(argList);
  77. }
  78. #define GTMAssertSelectorNilOrImplementedWithArguments(obj, sel, ...) \
  79. GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments((obj), (sel), "gtm_skip_return_test", __VA_ARGS__)
  80. #else // DEBUG
  81. // make it go away if not debug
  82. #define GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(obj, sel, retType, ...) do { } while (0)
  83. #define GTMAssertSelectorNilOrImplementedWithArguments(obj, sel, ...) do { } while (0)
  84. #endif // DEBUG