diff test/callback_suite_aggrs/main.c @ 523:cd46e111bc4c

- new test/callback_suite_aggrs (currently ahead of checked-in dyncall code and won't compile, though, as with call_suite_aggrs; dc code will be checked in, soon)
author Tassilo Philipp
date Wed, 13 Apr 2022 14:59:57 +0200
parents
children 71c884e610f0
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/callback_suite_aggrs/main.c	Wed Apr 13 14:59:57 2022 +0200
@@ -0,0 +1,305 @@
+/*
+
+ Package: dyncall
+ Library: test
+ File: test/callback_suite_aggrs/main.c
+ Description:
+ License:
+
+   Copyright (c) 2022 Tassilo Philipp <tphilipp@potion-studios.com>
+
+   Permission to use, copy, modify, and distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include "dyncall_callback.h"
+#include "globals.h"
+#include "../common/platformInit.h"
+#include "../common/platformInit.c" /* Impl. for functions only used in this translation unit */
+
+
+
+
+static void print_usage(const char* appName)
+{
+  printf("usage:\n\
+%s [ from [to] ]\n\
+where\n\
+  from, to: test range (0-based, runs single test if \"to\" is omitted)\n\
+options\n\
+  -h        help on usage\n\
+\n\
+", appName);
+}
+
+
+static int find_agg_idx(int* len, const char* sig)
+{
+  int i;
+  for(i=0; i<G_naggs; ++i) {
+    const char* agg_sig = G_agg_sigs[i];
+    int l = strlen(agg_sig);
+    if(len)
+      *len = l;
+    if(strncmp(agg_sig, sig, l) == 0)
+      return i;
+  }
+  return -1;
+}
+
+
+static int cmp(const char* signature)
+{
+  char atype;
+  const char* sig = signature;
+  int pos = 0;
+  int s = 0;
+  while ( (atype = *sig) != '\0') {
+    switch(atype) {
+      case '_':  sig += 2; /* skip cconv prefix */    continue;
+      case ')':  ++sig; /* skip ret type separator */ continue;
+      case 'v':  s = (sig > signature) && sig[-1] == ')'; /* assure this was the return type */                            break; /*TODO:check that no return-arg was touched.*/
+      case 'B':  s = ( V_B[pos] == K_B[pos] ); if (!s) printf("'%c':%d: %d != %d ; ",     atype, pos, V_B[pos], K_B[pos]); break;
+      case 'c':  s = ( V_c[pos] == K_c[pos] ); if (!s) printf("'%c':%d: %d != %d ; ",     atype, pos, V_c[pos], K_c[pos]); break;
+      case 's':  s = ( V_s[pos] == K_s[pos] ); if (!s) printf("'%c':%d: %d != %d ; ",     atype, pos, V_s[pos], K_s[pos]); break;
+      case 'i':  s = ( V_i[pos] == K_i[pos] ); if (!s) printf("'%c':%d: %d != %d ; ",     atype, pos, V_i[pos], K_i[pos]); break;
+      case 'j':  s = ( V_j[pos] == K_j[pos] ); if (!s) printf("'%c':%d: %ld != %ld ; ",   atype, pos, V_j[pos], K_j[pos]); break;
+      case 'l':  s = ( V_l[pos] == K_l[pos] ); if (!s) printf("'%c':%d: %lld != %lld ; ", atype, pos, V_l[pos], K_l[pos]); break;
+      case 'C':  s = ( V_C[pos] == K_C[pos] ); if (!s) printf("'%c':%d: %u != %u ; ",     atype, pos, V_C[pos], K_C[pos]); break;
+      case 'S':  s = ( V_S[pos] == K_S[pos] ); if (!s) printf("'%c':%d: %u != %u ; ",     atype, pos, V_S[pos], K_S[pos]); break;
+      case 'I':  s = ( V_I[pos] == K_I[pos] ); if (!s) printf("'%c':%d: %u != %u ; ",     atype, pos, V_I[pos], K_I[pos]); break;
+      case 'J':  s = ( V_J[pos] == K_J[pos] ); if (!s) printf("'%c':%d: %lu != %lu ; ",   atype, pos, V_J[pos], K_J[pos]); break;
+      case 'L':  s = ( V_L[pos] == K_L[pos] ); if (!s) printf("'%c':%d: %llu != %llu ; ", atype, pos, V_L[pos], K_L[pos]); break;
+      case 'p':  s = ( V_p[pos] == K_p[pos] ); if (!s) printf("'%c':%d: %p != %p ; ",     atype, pos, V_p[pos], K_p[pos]); break;
+      case 'f':  s = ( V_f[pos] == K_f[pos] ); if (!s) printf("'%c':%d: %f != %f ; ",     atype, pos, V_f[pos], K_f[pos]); break;
+      case 'd':  s = ( V_d[pos] == K_d[pos] ); if (!s) printf("'%c':%d: %f != %f ; ",     atype, pos, V_d[pos], K_d[pos]); break;
+      case '<': /* union */
+      case '{': /* struct */
+      {
+        /* no check: guaranteed to exist, or invoke func would've exited when passing args, above */
+        int len;
+        int i = find_agg_idx(&len, sig);
+        s = ((int(*)(const void*,const void*))G_agg_cmpfuncs[i])(V_a[pos], K_a[pos]);
+        if (!s) printf("'%c':%d:  *%p != *%p ; ", atype, pos, V_a[pos], K_a[pos]);
+        sig += len-1; /* advance to next arg char; -1 to compensate for ++sig, below */
+        break;
+      }
+      default: printf("unknown atype '%c' ; ", atype); return 0;
+    }
+    if(!s) {
+      printf("arg mismatch at %d ; ", pos);
+      return 0;
+    }
+    ++sig;
+    ++pos;
+  }
+  return 1;
+}
+
+
+/* handler just copies all received args as well as return value into V_* */
+static char handler(DCCallback* that, DCArgs* input, DCValue* output, void* userdata)
+{
+  const char* signature = (const char*) userdata;
+  int pos = 0;
+  char ch;
+
+  for(;;) {
+    ch = *signature++;
+    if (!ch || ch == DC_SIGCHAR_ENDARG) break;
+    switch(ch) {
+      case DC_SIGCHAR_BOOL:      V_B[pos] = dcbArgBool     (input);           break;
+      case DC_SIGCHAR_CHAR:      V_c[pos] = dcbArgChar     (input);           break;
+      case DC_SIGCHAR_UCHAR:     V_C[pos] = dcbArgUChar    (input);           break;
+      case DC_SIGCHAR_SHORT:     V_s[pos] = dcbArgShort    (input);           break;
+      case DC_SIGCHAR_USHORT:    V_S[pos] = dcbArgUShort   (input);           break;
+      case DC_SIGCHAR_INT:       V_i[pos] = dcbArgInt      (input);           break;
+      case DC_SIGCHAR_UINT:      V_I[pos] = dcbArgUInt     (input);           break;
+      case DC_SIGCHAR_LONG:      V_j[pos] = dcbArgLong     (input);           break;
+      case DC_SIGCHAR_ULONG:     V_J[pos] = dcbArgULong    (input);           break;
+      case DC_SIGCHAR_LONGLONG:  V_l[pos] = dcbArgLongLong (input);           break;
+      case DC_SIGCHAR_ULONGLONG: V_L[pos] = dcbArgULongLong(input);           break;
+      case DC_SIGCHAR_FLOAT:     V_f[pos] = dcbArgFloat    (input);           break;
+      case DC_SIGCHAR_DOUBLE:    V_d[pos] = dcbArgDouble   (input);           break;
+      case DC_SIGCHAR_STRING:
+      case DC_SIGCHAR_POINTER:   V_p[pos] = dcbArgPointer  (input);           break;
+      case DC_SIGCHAR_AGGREGATE:            dcbArgAggr     (input, V_a[pos]); break;
+      case DC_SIGCHAR_CC_PREFIX: ++signature; /* skip cconv prefix */ continue;
+      default: assert(0);
+    }
+    ++pos;
+  }
+
+  if(ch == DC_SIGCHAR_ENDARG)
+    ch = *signature;
+
+  /* write retval */
+  switch(ch) {
+    case DC_SIGCHAR_VOID:      /* nothing to set */                    break;
+    case DC_SIGCHAR_BOOL:      output->B = K_B[pos];                   break;
+    case DC_SIGCHAR_CHAR:      output->c = K_c[pos];                   break;
+    case DC_SIGCHAR_UCHAR:     output->C = K_C[pos];                   break;
+    case DC_SIGCHAR_SHORT:     output->s = K_s[pos];                   break;
+    case DC_SIGCHAR_USHORT:    output->S = K_S[pos];                   break;
+    case DC_SIGCHAR_INT:       output->i = K_i[pos];                   break;
+    case DC_SIGCHAR_UINT:      output->I = K_I[pos];                   break;
+    case DC_SIGCHAR_LONG:      output->j = K_j[pos];                   break;
+    case DC_SIGCHAR_ULONG:     output->J = K_J[pos];                   break;
+    case DC_SIGCHAR_LONGLONG:  output->l = K_l[pos];                   break;
+    case DC_SIGCHAR_ULONGLONG: output->L = K_L[pos];                   break;
+    case DC_SIGCHAR_FLOAT:     output->f = K_f[pos];                   break;
+    case DC_SIGCHAR_DOUBLE:    output->d = K_d[pos];                   break;
+    case DC_SIGCHAR_STRING:
+    case DC_SIGCHAR_POINTER:   output->p = K_p[pos];                   break;
+    case DC_SIGCHAR_AGGREGATE: dcbReturnAggr(input, output, K_a[pos]); break;
+    default: assert(0);
+  }
+
+  /* return type info for dyncallback */
+  return ch;
+}
+
+
+
+
+static int run_test(int id)
+{
+  const char* signature;
+  DCCallback* pcb;
+  int result;
+  int len_sig;
+  char   *dc_sig;
+  DCaggr **dc_aggrs;
+  int n_aggrs = 0;
+
+  /* index range: [0,nsigs[ */
+  signature = G_sigtab[id];
+  printf("%d:%s", id, signature);
+
+  len_sig = strlen(signature);
+
+  /* prep dcbNewCallback() args: signature in dyncall format and array of
+   * DCaggr* descriptions; use len of verbose test-case sig, as always bigger
+   * than canonical/dyncall signature (where aggrs represented as single char)
+   * number of aggregates in sig and  */
+  dc_sig   = malloc(sizeof(char)   *len_sig);
+  dc_aggrs = malloc(sizeof(DCaggr*)*len_sig);
+
+  len_sig = 0; /* len of canonical/dyncall sig */
+  while(*signature != '\0') {
+    switch(*signature) {
+      case '_': signature += 2; /* skip cconv prefix */ break;
+      case '<': /* union */
+      case '{': /* struct */
+      {
+        /* find aggregate sig */
+        int len;
+        int i = find_agg_idx(&len, signature);
+        if(i == -1) {
+          printf("unknown aggr sig at '%s' ;", signature);
+          return 0;
+        }
+        dc_sig[len_sig++] = 'A';
+        dc_aggrs[n_aggrs++] = ((DCaggr*(*)())G_agg_touchAfuncs[i])();
+        signature += len; /* advance to next arg char */
+        break;
+      }
+      default:
+        dc_sig[len_sig++] = *signature;
+        ++signature;
+    }
+  }
+  dc_sig[len_sig] = '\0';
+
+
+  pcb = dcbNewCallback(dc_sig, handler, (void*)dc_sig, dc_aggrs);
+  assert(pcb != NULL);
+
+  clear_V();
+
+  /* invoke call */
+  G_funtab[id]((void*)pcb);
+
+  result = cmp(G_sigtab[id]);
+
+  free(dc_sig);
+  free(dc_aggrs);
+
+  printf(":%d\n", result);
+
+  dcbFreeCallback(pcb);
+
+  return result;
+}
+
+
+static int run_all(int from, int to)
+{
+  int i;
+  int failure = 0;
+  for(i=from; i<=to ;++i)
+      failure |= !( run_test(i) );
+
+  return !failure;
+}
+
+
+#define Error(X, Y, N) { fprintf(stderr, X, Y); print_usage(N); exit(1); }
+
+int main(int argc, char* argv[])
+{
+  int from = 0, to = G_ncases-1;
+  int i, pos = 0, total;
+
+  dcTest_initPlatform();
+
+
+  /* parse args */
+  for(i=1; i<argc; ++i)
+  {
+    if(argv[i][0] == '-')
+    {
+      switch(argv[i][1]) {
+        case 'h':
+        case '?':
+          print_usage(argv[0]);
+          return 0;
+        default:
+          Error("invalid option: %s\n\n", argv[i], argv[0]);
+      }
+    }
+    switch(pos++) {
+      case 0: from = to = atoi(argv[i]); break;
+      case 1:        to = atoi(argv[i]); break;
+      default: Error("too many arguments (%d given, 2 allowed)\n\n", pos, argv[0]);
+    }
+  }
+  if(from < 0 || to >= G_ncases || from > to)
+      Error("invalid arguments (provided from or to not in order or outside of range [0,%d])\n\n", G_ncases-1, argv[0]);
+
+
+  init_test_data();
+  total = run_all(from, to);
+  deinit_test_data();
+
+  printf("result: callback_suite_aggrs: %d\n", total);
+
+  dcTest_deInitPlatform();
+
+  return !total;
+}
+