int test_curve(int c) { spiro_cp spiro[16]; int nextknot[17]; spiro_seg *segs = NULL; bezctx *bc; int i; /* Load sample data so that we can see if library is callable */ load_test_curve(spiro,nextknot,c); /* Check if run_spiro works okay */ printf("testing run_spiro() using data=path%d[].\n",c); if ( (segs=run_spiro(spiro,cl[c]))==0 ) { printf("error with run_spiro() using data=path%d[].\n",c); return -1; } /* Quick visual check shows X,Y knots match with each pathN[] */ for (i=0; i < cl[c]; i++) { printf("curve %d, line %d, x=%f y=%f t=%c bend=%f ch=%f th=%f l=%f \n",c,i,segs[i].x,segs[i].y,segs[i].ty,segs[i].bend_th,segs[i].seg_ch,segs[i].seg_th,segs[i].l); } /* Quick visual check shows X,Y knots match with each pathN[] */ printf("testing spiro_to_bpath() using data from run_spiro(data=path%d[],len=%d).\n",c,cl[c]); bc = new_bezctx_test(); spiro_to_bpath(segs,cl[c],bc); free(segs); /* Check if TaggedSpiroCPsToBezier0() works okay */ printf("---\ntesting TaggedSpiroCPsToBezier0() using data=path%d[].\n",c); if ( TaggedSpiroCPsToBezier0(spiro,bc)!=1 ) { printf("error with TaggedSpiroCPsToBezier0() using data=path%d[].\n",c); return -1; } /* Check if SpiroCPsToBezier0() works okay */ printf("---\ntesting SpiroCPsToBezier0() using data=path%d[].\n",c); if ( SpiroCPsToBezier0(spiro,cl[c],(c==0 ? 1 : 0),bc)!=1 ) { printf("error with SpiroCPsToBezier0() using data=path%d[].\n",c); return -1; } free(bc); return 0; }
int test_multi_curves(void) { spiro_cp **spiro = NULL; int *pk, **nextknot = NULL; int *scl = NULL; test_bezctx **bc; int i, j, k, ret; #if HAVE_PTHREADS printf("---\nMulti-thread testing of libspiro.\n"); /* pthread default limit is currently about 380 without mods. */ #define S_TESTS 300 #else printf("---\nSequential tests of libspiro.\n"); #define S_TESTS 3000 #endif ret = -1; /* return error if out of memory */ /* Expect lots of results */ if ( (bc=(test_bezctx**)calloc(S_TESTS,sizeof(test_bezctx*)))==NULL ) goto test_multi_curves_exit; for (i=0; i < S_TESTS; i++) { if ( (bc[i]=(test_bezctx*)malloc(sizeof(test_bezctx)))==NULL ) goto test_multi_curves_exit; bc[i]->base.moveto = test_s_moveto; bc[i]->base.lineto = test_s_lineto; bc[i]->base.quadto = test_s_quadto; bc[i]->base.curveto = test_s_curveto; bc[i]->base.mark_knot = test_s_mark_knot; if ( (bc[i]->my_curve=(my_curve_data*)calloc(S_RESULTS,sizeof(my_curve_data)))==NULL ) goto test_multi_curves_exit; bc[i]->len = 0; /* no curve yet, len=0 */ bc[i]->is_open = 0; bc[i]->c_id = i; /* identify each curve */ } if ( (scl=(int*)malloc(S_TESTS*sizeof(int)))==NULL || \ (spiro=(spiro_cp**)calloc(S_TESTS,sizeof(spiro_cp*)))==NULL || \ (nextknot=(int**)calloc(S_TESTS,sizeof(int*)))==NULL ) goto test_multi_curves_exit; for (i=0; i < S_TESTS; ) { /* NOTE: S_TESTS has to be multiple of 3 here. */ if ( (spiro[i]=malloc(cl[0]*sizeof(spiro_cp)))==NULL || \ (nextknot[i]=calloc(cl[0]+1,sizeof(int)))==NULL ) goto test_multi_curves_exit; load_test_curve(spiro[i], nextknot[i], 0); scl[i++]=cl[0]; if ( (spiro[i]=malloc(cl[1]*sizeof(spiro_cp)))==NULL || \ (nextknot[i]=calloc(cl[1],sizeof(int)))==NULL ) goto test_multi_curves_exit; load_test_curve(spiro[i], nextknot[i], 1); scl[i++]=cl[1]; if ( (spiro[i]=malloc(cl[2]*sizeof(spiro_cp)))==NULL || \ (nextknot[i]=calloc(cl[2],sizeof(int)))==NULL ) goto test_multi_curves_exit; load_test_curve(spiro[i], nextknot[i], 2); scl[i++]=cl[2]; } /* Change to different sizes to make sure no duplicates */ for (i=0; i < S_TESTS; i++) { spiro_cp *temp; temp = spiro[i]; for (j=0; j < scl[i]; j++) { temp[j].x = temp[j].x * ((i+1.0)/100); temp[j].y = temp[j].y * ((i+1.0)/100); } } #if HAVE_PTHREADS /* Test all curves - all at same time, wait for all to finish */ pthread_t curve_test[S_TESTS]; pthread_pcurve pdata[S_TESTS]; for (i=0; i < S_TESTS; i++) { pdata[i].spiro = spiro[i]; pdata[i].bc = (bezctx*)(bc[i]); pdata[i].ret = i; } j=0; for (i=0; i < S_TESTS; i++) /* all values passed are joined at "->" (should be okay). */ if ( pthread_create(&curve_test[i],NULL,test_a_curve,(void *)&pdata[i]) ) { printf("bad pthread_create[%d]\n",i); j=-1; break; } while (--i >= 0) if ( pthread_join(curve_test[i],NULL) ) { printf("bad pthread_join[%d]\n",i); j=-1; } if (j) goto test_multi_curves_exit; for (i=0; i < S_TESTS; i++) if ( pdata[i].ret!=1 ) { printf("error with TaggedSpiroCPsToBezier0() using data=%d.\n",i); goto test_multi_curves_exit; } #else /* No pthreads.h, test all curves sequentially, one at a time */ for (i=0; i < S_TESTS; i++) { if ( TaggedSpiroCPsToBezier0(spiro[i],(bezctx*)(bc[i]))!=1 ) { printf("error with TaggedSpiroCPsToBezier0() using data=%d.\n",i); goto test_multi_curves_exit; } } #endif /* Check ending x,y points versus input spiro knot locations. */ for (i=0; i < S_TESTS; i++) { spiro_cp *temp; double x, y; char ty; temp = spiro[i]; pk = nextknot[i]; k=0; for (j=0; j < scl[i] && temp[j].ty!='z'; j++) { ty = bc[i]->my_curve[k].ty; x = bc[i]->my_curve[k].x1; y = bc[i]->my_curve[k].y1; if ( ty=='q' ) { x = bc[i]->my_curve[k].x2; y = bc[i]->my_curve[k].y2; } if ( ty=='c' ) { x = bc[i]->my_curve[k].x3; y = bc[i]->my_curve[k].y3; } #ifdef VERBOSE printf("len=%d s[%d].ty=%c x=%g y=%g, len=%d pk=%d mc[%d] x=%g y=%g\n", \ scl[i],j,temp[j].ty,temp[j].x,temp[j].y, bc[i]->len,pk[j],k,x,y); #endif if ( (fabs(temp[j].x - x) > 1e-8) || (fabs(temp[j].y - y) > 1e-8) ) { printf("error with test_multi_curves() using data %d\n",i); goto test_multi_curves_exit; } k += pk[j]+1; } } #if HAVE_PTHREADS printf("Multi-thread testing of libspiro passed.\n"); #else printf("Sequential tests of libspiro passed.\n"); #endif ret = 0; test_multi_curves_exit: if ( nextknot!=NULL ) for (i=0; i < S_TESTS; i++) free(nextknot[i]); if ( spiro!=NULL ) for (i=0; i < S_TESTS; i++) free(spiro[i]); free(nextknot); free(spiro); free(scl); if ( bc!=NULL ) for (i=0; i < S_TESTS; i++) { free(bc[i]->my_curve); free(bc[i]); } free(bc); return ret; }
int test_multi_curves(void) { spiro_cp **spiro = NULL; spiro_cp *temp; int *pk, **nextknot = NULL; int *scl = NULL; test_bezctx **bc; int i, j, k, l, ret; double x, y; char ty; /* our simple curve test-check breaks-down if we go more than */ /* 10x larger curves due to rounding errors on double values, */ /* so, we either need a more complex curve test-check at end, */ /* or we can cleverly do stepping-up 0.01 one thousand times. */ #define S_TESTS 3000 #ifdef HAVE_PTHREADS pthread_attr_t tattr; pthread_t curve_test[S_TESTS]; pthread_pcurve pdata[S_TESTS]; printf("---\nMulti-thread testing of libspiro.\n"); /* pthread default limit is currently about 380 without mods. */ #else printf("---\nSequential tests of libspiro.\n"); #endif ret = -1; /* return error if out of memory */ /* Expect lots of results, therefore create available memory. */ /* This way, we won't be wasting time doing malloc because we */ /* really want to shoot a whole bunch of pthreads all at once.*/ if ( (bc=(test_bezctx**)calloc(S_TESTS,sizeof(test_bezctx*)))==NULL ) goto test_multi_curves_exit; for (i=0; i < S_TESTS; i++) { if ( (bc[i]=(test_bezctx*)malloc(sizeof(test_bezctx)))==NULL ) goto test_multi_curves_exit; bc[i]->base.moveto = test_s_moveto; bc[i]->base.lineto = test_s_lineto; bc[i]->base.quadto = test_s_quadto; bc[i]->base.curveto = test_s_curveto; bc[i]->base.mark_knot = test_s_mark_knot; if ( (bc[i]->my_curve=(my_curve_data*)calloc(S_RESULTS,sizeof(my_curve_data)))==NULL ) goto test_multi_curves_exit; bc[i]->len = 0; /* no curve yet, len=0 */ bc[i]->is_open = 0; bc[i]->c_id = i; /* identify each curve */ } if ( (scl=(int*)malloc(S_TESTS*sizeof(int)))==NULL || \ (spiro=(spiro_cp**)calloc(S_TESTS,sizeof(spiro_cp*)))==NULL || \ (nextknot=(int**)calloc(S_TESTS,sizeof(int*)))==NULL ) goto test_multi_curves_exit; for (i=0; i < S_TESTS; ) { /* NOTE: S_TESTS has to be multiple of 3 here. */ /* ...because we test using path[0/1/2]tables, */ /* ...and path[3] is used to test NOT success. */ if ( (spiro[i]=malloc(cl[0]*sizeof(spiro_cp)))==NULL || \ (nextknot[i]=calloc(cl[0]+1,sizeof(int)))==NULL ) goto test_multi_curves_exit; load_test_curve(spiro[i], nextknot[i], 0); scl[i++]=cl[0]; if ( (spiro[i]=malloc(cl[1]*sizeof(spiro_cp)))==NULL || \ (nextknot[i]=calloc(cl[1],sizeof(int)))==NULL ) goto test_multi_curves_exit; load_test_curve(spiro[i], nextknot[i], 1); scl[i++]=cl[1]; if ( (spiro[i]=malloc(cl[2]*sizeof(spiro_cp)))==NULL || \ (nextknot[i]=calloc(cl[2],sizeof(int)))==NULL ) goto test_multi_curves_exit; load_test_curve(spiro[i], nextknot[i], 2); scl[i++]=cl[2]; } /* Change to different sizes to make sure no duplicates */ /* ...to verify we do not overwrite different user data */ /* while running multiple threads all at the same time. */ for (i=0; i < S_TESTS; i++) { temp = spiro[i]; for (j=0; j < scl[i]; j++) { temp[j].x = temp[j].x * ((i+1.0)/100); temp[j].y = temp[j].y * ((i+1.0)/100); } } --ret; #ifdef HAVE_PTHREADS /* Data and memory prepared before Pthreads. Ready? Set? GO! */ /* Test all curves, all at same time, wait for all to finish. */ /* This test could fail if we had globally set variables that */ /* could affect other functions, eg: static n=4 was moved out */ /* into passed variable so that one user won't affect others. */ /* GEGL is a good example of multiple users all at same time. */ for (i=0; i < S_TESTS; i++) { pdata[i].spiro = spiro[i]; pdata[i].bc = (bezctx*)(bc[i]); pdata[i].ret = i; } j=0; for (k=0; k < S_TESTS;) { /* Initialize and set thread joinable attribute */ pthread_attr_init(&tattr); pthread_attr_setdetachstate(&tattr,PTHREAD_CREATE_JOINABLE); /* Some processors can't do too many pthreads at once so then */ /* we need to run threads in batches until completing S_TESTS */ for (i=k; i < S_TESTS-1; i++) { /* all values passed are joined at "->" (should be okay). */ if ( pthread_create(&curve_test[i],&tattr,test_a_curve,(void *)&pdata[i]) ) { if ( i-k < 20 ) { printf("bad pthread_create[%d]\n",i); /* not many */ j=-1; } break; } } pthread_attr_destroy(&tattr); /* Free thread attribute */ if ( j!=-1 ) { /* Test another curve while waiting for threads to finish */ pdata[i].ret = TaggedSpiroCPsToBezier0(pdata[i].spiro,pdata[i].bc); printf("running simultaneous threads[%d..%d]\n",k,i); } l=i; while (--i >= k) if ( pthread_join(curve_test[i],NULL) ) { printf("bad pthread_join[%d]\n",i); j=-1; } k=++l; if (j) goto test_multi_curves_exit; } for (i=0; i < S_TESTS; i++) if ( pdata[i].ret!=1 ) { printf("error with TaggedSpiroCPsToBezier0() using data=%d.\n",i); ret=ret-i; goto test_multi_curves_exit; } /* All threads returned okay, Now, go check all data is good. */ #else /* No pthreads.h, test all curves sequentially, one at a time */ /* Just do a math check and leave the pthread check for other */ /* operating systems to verify libspiro has no static values. */ for (i=0; i < S_TESTS; i++) { if ( TaggedSpiroCPsToBezier0(spiro[i],(bezctx*)(bc[i]))!=1 ) { printf("error with TaggedSpiroCPsToBezier0() using data=%d.\n",i); ret=ret-i; goto test_multi_curves_exit; } } #endif ret=ret-S_TESTS; /* Check ending x,y points versus input spiro knot locations. */ for (i=0; i < S_TESTS; i++) { temp = spiro[i]; pk = nextknot[i]; k=0; for (j=0; j < scl[i] && temp[j].ty!='z'; j++) { ty = bc[i]->my_curve[k].ty; x = bc[i]->my_curve[k].x1; y = bc[i]->my_curve[k].y1; if ( ty=='q' ) { x = bc[i]->my_curve[k].x2; y = bc[i]->my_curve[k].y2; } if ( ty=='c' ) { x = bc[i]->my_curve[k].x3; y = bc[i]->my_curve[k].y3; } #ifdef VERBOSE printf("len=%d s[%d].ty=%c x=%g y=%g, len=%d pk=%d mc[%d] x=%g y=%g\n", \ scl[i],j,temp[j].ty,temp[j].x,temp[j].y, bc[i]->len,pk[j],k,x,y); #endif if ( (fabs(temp[j].x - x) > 1e-8) || (fabs(temp[j].y - y) > 1e-8) ) { /* close-enough for testing 10x range of doubles. */ printf("error with test_multi_curves() using data %d\n",i); ret=ret-i; goto test_multi_curves_exit; } k += pk[j]+1; } } #ifdef HAVE_PTHREADS printf("Multi-thread testing of libspiro passed.\n"); #else printf("Sequential tests of libspiro passed.\n"); #endif ret = 0; test_multi_curves_exit: if ( nextknot!=NULL ) for (i=0; i < S_TESTS; i++) free(nextknot[i]); if ( spiro!=NULL ) for (i=0; i < S_TESTS; i++) free(spiro[i]); free(nextknot); free(spiro); free(scl); if ( bc!=NULL ) for (i=0; i < S_TESTS; i++) { free(bc[i]->my_curve); free(bc[i]); } free(bc); return ret; }