MOAB: Mesh Oriented datABase  (version 5.5.0)
TestUtil.hpp
Go to the documentation of this file.
1 #ifndef TEST_UTIL_HPP
2 #define TEST_UTIL_HPP
3 
4 #ifdef __cplusplus
5 #include <string>
6 #include <fstream>
7 #endif
8 #include "moab/MOABConfig.h"
9 #ifdef MOAB_HAVE_MPI
10 #include "moab_mpi.h"
11 #endif
12 
13 /* Define these here because they are used by many tests
14  * to find the add directory for input files */
15 #define STRINGIFY_( X ) #X
16 #define STRINGIFY( X ) STRINGIFY_( X )
17 
18 #ifdef MOAB_MESH_DIR
19 #ifdef __cplusplus
20 const std::string TestDir( MOAB_MESH_DIR );
21 #else
22 const char* TestDir = MOAB_MESH_DIR;
23 #endif
24 #else
25 #error Specify MOAB_MESH_DIR to compile test
26 #endif
27 
28 /* How to use this test suite utility:
29  * 1) Write tests that use the CHECK and CHECK_* macros defined below to assert test conditions.
30  * 2) Write a main routine that invokes each test through the RUN_TEST macro
31  * 3) RUN_TEST evaluates to 1 if test failed, zero otherwize. Count failures and print summary.
32  */
33 
34 /** Check that A is MB_SUCCESS */
35 #define CHECK_ERR( A ) check_equal( MB_SUCCESS, ( A ), "MB_SUCCESS", #A, __LINE__, __FILE__ )
36 /** Ensure that A is true */
37 #define CHECK( A ) check_true( ( A ), #A, __LINE__, __FILE__ )
38 /** Check that two values are equal */
39 #define CHECK_EQUAL( EXP, ACT ) check_equal( ( EXP ), ( ACT ), #EXP, #ACT, __LINE__, __FILE__ )
40 /** Check that two real (float or double) values are equal within EPS */
41 #define CHECK_REAL_EQUAL( EXP, ACT, EPS ) check_equal( ( EXP ), ( ACT ), ( EPS ), #EXP, #ACT, __LINE__, __FILE__ )
42 /** Check that two arrays contain the same values in the same order */
43 #define CHECK_ARRAYS_EQUAL( EXP, EXP_LEN, ACT, ACT_LEN ) \
44  check_array_equal( ( EXP ), ( EXP_LEN ), ( ACT ), ( ACT_LEN ), #EXP, #ACT, __LINE__, __FILE__ )
45 /** Check that two CartVect objects contain same values */
46 #define CHECK_VECREAL_EQUAL( EXP, ACT, EPS ) \
47  check_equal_cartvect( ( EXP ), ( ACT ), ( EPS ), #EXP, #ACT, __LINE__, __FILE__ )
48 /** Run a test
49  * Argument should be a function with the signature: void func(void)
50  * Evaluates to zero if test is successful, one otherwise.
51  */
52 #define RUN_TEST( FUNC ) run_test( &( ( ( ( FUNC ) ) ) ), #FUNC )
53 
54 // Use C++ exceptions to return error state to test runner
55 // Portable, but whole test suite stops if any test segfaults, asserts, etc.
56 #define EXCEPTION_MODE 1
57 
58 // Test runner forks separate process for each test.
59 // Difficult to debug tests (with debugger). Not portable to Windows.
60 // Very robust (no test can distrub test running code)
61 #define FORK_MODE 2
62 
63 // Use signal handler and long jumps to return error state to test runner.
64 // Might be portable to Windows (not sure). Possibly undefined behavior (e.g. continuing
65 // with next test after catching segfault is technically undefined behavior.)
66 // Also, tests can corrupt heap memory management, interferring with later tests.
67 // Leaks memory on test failure (no stack unwind). This is actually a feature, as
68 // we don't care too much about tests leaking memory and trying to reconver memory
69 // might make things worse, depending on why the test failed.
70 #define LONGJMP_MODE 3
71 
72 // If test application hasn't set MODE, set to default
73 #ifndef MODE
74 #if defined( _MSC_VER ) || defined( __MINGW32__ )
75 #define MODE EXCEPTION_MODE
76 #else
77 #define MODE LONGJMP_MODE
78 #endif
79 #endif
80 
81 /***************************************************************************************
82  * NOTE: The remainder of this file contains the implementation of the above macros.
83  * The above macros constitute the entire intended API.
84  ***************************************************************************************/
85 
86 #include <cmath>
87 #include <cstdio>
88 #include <cstdlib>
89 #include <cstring>
90 #ifdef __cplusplus
91 #include <iostream>
92 #include <vector>
93 #include <algorithm>
94 #include <map>
95 #endif
96 
97 /***************************************************************************************
98  * Define What to do when a test fails.
99  ***************************************************************************************/
100 
101 // For EXCEPTION_MODE, throw an exception when a test fails.
102 // This will unwind stack, recover memory, etc.
103 #if MODE == EXCEPTION_MODE
104 struct ErrorExcept
105 {
106 };
107 #define FLAG_ERROR throw ErrorExcept()
108 // For FORK_MODE, the test is running in its own processs. Just
109 // terminate the process with a non-zero exit code when the test
110 // fails.
111 #elif MODE == FORK_MODE
112 #include <sys/types.h>
113 #include <sys/wait.h>
114 #include <unistd.h>
115 #include <errno.h>
116 #define FLAG_ERROR exit( 1 )
117 // For LONGJMP_MODE, we do a long jump to just before the test is
118 // run, with a return value of -1 to indicate failures (positive
119 // return codes are used if the test caused a segfault or other
120 // signal.)
121 #elif MODE == LONGJMP_MODE
122 #include <csignal>
123 #include <csetjmp>
124 #define FLAG_ERROR siglongjmp( jmpenv, -1 )
125 #else
126 #error "MODE not set"
127 #endif
128 
129 /***************************************************************************************
130  * Setup for LONGJMP_MODE
131  ***************************************************************************************/
132 
133 #if MODE == LONGJMP_MODE
134 
135 // Variable to hold stack state for longjmp
136 sigjmp_buf jmpenv;
137 
138 // Define signal handler used to catch errors such as segfaults.
139 // Signal handler does longjmp with the signal number as the
140 // return value.
141 extern "C" {
142 void sighandler( int sig )
143 {
144  signal( sig, sighandler );
145  siglongjmp( jmpenv, sig );
146  // should never return from longjmp
147  exit( 1 );
148 }
149 typedef void ( *sigfunc_t )( int );
150 } // extern "C"
151 
152 // Helper function to register signal handlers.
153 int sethandler( int sig )
154 {
155  sigfunc_t h = signal( sig, &sighandler );
156  if( h == SIG_ERR ) return 1;
157  // If user-defined signal handler (or signal is ignored),
158  // than unregister our handler.
159  else if( h != SIG_DFL )
160  signal( sig, h );
161  return 0;
162 }
163 
164 // Register signal handlers for all defined signals that typicall result
165 // in process termination.
167 {
168  int result = 0;
169  /* Don't trap these. It is unlikely that a test would ever generate such
170  a signal on its own and trapping them interfers with a user's ability
171  to stop a test. SIGHUP implies that the controlling terminal was closed.
172  If the user does ctrl-C or ctrl-\ (SIGINT and SIGQUIT, respectively) and
173  we trap these then just the current test stops. If we leave the default
174  behavior for them then the whole test suite stops. The latter is likely
175  the desired behavior. SIGTERM is the default signal sent by the 'kill'
176  command.
177  #ifdef SIGHUP
178  result += sethandler( SIGHUP );
179  #endif
180  #ifdef SIGINT
181  result += sethandler( SIGINT );
182  #endif
183  #ifdef SIGQUIT
184  result += sethandler( SIGQUIT );
185  #endif
186  #ifdef SIGTERM
187  result += sethandler( SIGTERM );
188  #endif
189  */
190 
191 #ifdef SIGILL
192  result += sethandler( SIGILL );
193 #endif
194 #ifdef SIGTRAP
195  result += sethandler( SIGTRAP );
196 #endif
197 #ifdef SIGABRT
198  result += sethandler( SIGABRT );
199 #endif
200 #ifdef SIGBUS
201  result += sethandler( SIGBUS );
202 #endif
203 #ifdef SIGFPE
204  result += sethandler( SIGFPE );
205 #endif
206 #ifdef SIGSEGV
207  result += sethandler( SIGSEGV );
208 #endif
209 
210  /* Catching these causes problems with mpich2 1.3.1p1 and a
211  test should never receive such a signal anyway.
212  #ifdef SIGUSR1
213  result += sethandler( SIGUSR1 );
214  #endif
215  #ifdef SIGUSR2
216  result += sethandler( SIGUSR2 );
217  #endif
218  */
219 
220  /* Don't trap SIGCHLD. The only way a test should receive
221  such a signal is if it actually forked a child process.
222  That is unlikely, but if it does happen the test probably
223  wants to handle the signal itself.
224  #ifdef SIGCHLD
225  result += sethandler( SIGCHLD );
226  #endif
227  */
228 
229 #ifdef SIGPIPE
230  result += sethandler( SIGPIPE );
231 #endif
232 #ifdef SIGIO
233  result += sethandler( SIGIO );
234 #endif
235 #ifdef SIGSYS
236  result += sethandler( SIGSYS );
237 #endif
238  return result;
239 }
240 
241 // Declare a garbage global variable. Use variable initialization to
242 // force call to init_signal_handlers().
244 
245 #endif // LONGJMP_MODE
246 
247 /***************************************************************************************
248  * Function to handle failed tests
249  ***************************************************************************************/
250 
251 // use a function rather than substituting FLAG_ERROR directly
252 // so we have a convenient place to set a break point
253 inline void flag_error()
254 {
255  FLAG_ERROR;
256 }
257 
258 /***************************************************************************************
259  * The Code to Run Tests
260  ***************************************************************************************/
261 
262 /* Make sure IS_BUILDING_MB is defined so we can include MBInternals.hpp */
263 #include "moab/Types.hpp"
264 #ifndef IS_BUILDING_MB
265 #define IS_BUILDING_MB
266 #include "Internals.hpp"
267 #undef IS_BUILDING_MB
268 #else
269 #include "Internals.hpp"
270 #endif
271 
272 #ifndef TEST_USES_ERR_CODES
273 typedef void ( *test_func )( void );
274 int run_test( test_func test, const char* func_name )
275 #else
276 typedef moab::ErrorCode ( *test_func_err )( void );
277 int run_test( test_func_err test, const char* func_name )
278 #endif
279 {
280  // check if we are running parallel MPI tests
281  int rank = 0;
282 #ifdef MOAB_HAVE_MPI
283  int isInit;
284  MPI_Initialized( &isInit );
285  if( isInit )
286  {
287  MPI_Comm_rank( MPI_COMM_WORLD, &rank );
288  }
289 #endif
290 
291  if( rank == 0 ) printf( "Running %s ...\n", func_name );
292 
293 #if MODE == EXCEPTION_MODE
294  /* On Windows, run all tests in same process.
295  Flag errors by throwing an exception.
296  */
297  try
298  {
299  ( *test )();
300  return 0;
301  }
302  catch( ErrorExcept )
303  {
304  printf( "[%d] %s: FAILED\n", rank, func_name );
305  return 1;
306  }
307  catch( ... )
308  {
309  printf( "[%d] %s: UNCAUGHT EXCEPTION\n", rank, func_name );
310  return 1;
311  }
312 
313 #elif MODE == FORK_MODE
314  /* For non-Windows OSs, fork() and run test in child process. */
315  pid_t pid = fork();
316  int status;
317 
318  /* Fork failed? */
319  if( pid == -1 )
320  {
321  perror( "fork()" );
322  abort(); /* abort all tests (can't fork child processes) */
323  }
324 
325  /* If child process*/
326  if( pid == 0 )
327  {
328  ( *test )(); /* call test function */
329  exit( 0 ); /* if function returned, then it succeeded */
330  }
331 
332  /* If here, then parent process */
333 
334  /* Wait until child process exits */
335  waitpid( pid, &status, 0 );
336 
337  /* Check child exit status */
338  if( WIFSIGNALED( status ) )
339  {
340  if( WTERMSIG( status ) ) printf( " %s: TERMINATED (signal %d)\n", func_name, (int)WTERMSIG( status ) );
341  if( WCOREDUMP( status ) ) printf( " %s: CORE DUMP\n", func_name );
342  return 1;
343  }
344  else if( WEXITSTATUS( status ) )
345  {
346  printf( " %s: FAILED\n", func_name );
347  return 1;
348  }
349  else
350  {
351  return 0;
352  }
353 
354 #elif MODE == LONGJMP_MODE
355  // Save stack state at this location.
356  int rval = sigsetjmp( jmpenv, 1 );
357  // If rval is zero, then we haven't run the test yet.
358  // If rval is non-zero then
359  // a) we ran the test
360  // b) the test failed
361  // c) we did a longjmp back to the location where we called setsigjmp.
362 
363  // run test
364  if( !rval )
365  {
366  ( *test )();
367  return 0;
368  }
369  // some check failed
370  else if( rval == -1 )
371  {
372  printf( " %s: FAILED\n", func_name );
373  return 1;
374  }
375  // a signal was raised (e.g. segfault)
376  else
377  {
378  printf( " %s: TERMINATED (signal %d)\n", func_name, rval );
379  return 1;
380  }
381 #else
382 #error "MODE not set"
383 #endif // MODE
384 }
385 
386 /***************************************************************************************
387  * CHECK_EQUAL implementations
388  ***************************************************************************************/
389 
390 // Common implementatation for most types
391 #define EQUAL_TEST_IMPL( TEST, TYPE ) \
392  if( !( TEST ) ) \
393  { \
394  printf( "Equality Test Failed: %s == %s\n", sA, sB ); \
395  printf( " at line %d of '%s'\n", line, file ); \
396  printf( " Expected value: %" #TYPE "\n", A ); \
397  printf( " Actual value: %" #TYPE "\n", B ); \
398  printf( "\n" ); \
399  flag_error(); \
400  }
401 
402 void check_equal( int A, int B, const char* sA, const char* sB, int line, const char* file )
403 {
404  EQUAL_TEST_IMPL( A == B, d )
405 }
406 
407 void check_equal( unsigned A, unsigned B, const char* sA, const char* sB, int line, const char* file )
408 {
409  EQUAL_TEST_IMPL( A == B, u )
410 }
411 
412 void check_equal( long A, long B, const char* sA, const char* sB, int line, const char* file )
413 {
414  EQUAL_TEST_IMPL( A == B, ld )
415 }
416 
417 void check_equal( unsigned long A, unsigned long B, const char* sA, const char* sB, int line, const char* file )
418 {
419  EQUAL_TEST_IMPL( A == B, lu )
420 }
421 
422 void check_equal( unsigned long long A,
423  unsigned long long B,
424  const char* sA,
425  const char* sB,
426  int line,
427  const char* file )
428 {
429  EQUAL_TEST_IMPL( A == B, llu )
430 }
431 
432 void check_equal( long long A, long long B, const char* sA, const char* sB, int line, const char* file )
433 {
434  EQUAL_TEST_IMPL( A == B, lld )
435 }
436 
437 void check_equal( void* A, void* B, const char* sA, const char* sB, int line, const char* file )
438 {
439  EQUAL_TEST_IMPL( A == B, p )
440 }
441 
442 void check_equal( const char* A, const char* B, const char* sA, const char* sB, int line, const char* file )
443 {
444  EQUAL_TEST_IMPL( !strcmp( ( A ), ( B ) ), s )
445 }
446 
447 void check_equal( const std::string& A,
448  const std::string& B,
449  const char* sA,
450  const char* sB,
451  int line,
452  const char* file )
453 {
454  check_equal( A.c_str(), B.c_str(), sA, sB, line, file );
455 }
456 
457 void check_equal( float A, float B, float eps, const char* sA, const char* sB, int line, const char* file )
458 {
459  EQUAL_TEST_IMPL( fabsf( A - B ) <= eps, f )
460 }
461 
462 void check_equal( double A, double B, double eps, const char* sA, const char* sB, int line, const char* file )
463 {
464  EQUAL_TEST_IMPL( fabs( A - B ) <= eps, f )
465 }
466 
467 const char* mb_error_str( moab::ErrorCode err )
468 {
469  switch( err )
470  {
471  case moab::MB_SUCCESS:
472  return "Success";
474  return "Index Out of Range";
476  return "Type Out of Range";
478  return "Memory Alloc. Failed";
480  return "Entity Not Found";
482  return "Multiple Entities Found";
484  return "Tag Not Found";
486  return "File Not Found";
488  return "File Write Error";
490  return "Not Implemented";
492  return "Already Allocated";
494  return "Variable Data Length";
496  return "Invalid Size";
498  return "Unsupported Operation";
500  return "Unhandled Option";
502  return "Structured Mesh";
503  case moab::MB_FAILURE:
504  return "Failure";
505  default:
506  return "(unknown)";
507  }
508 }
509 
510 // Special case for MBErrorCode, use mb_error_str() to print the
511 // string name of the error code.
512 void check_equal( moab::ErrorCode A, moab::ErrorCode B, const char* sA, const char* sB, int line, const char* file )
513 {
514  if( A == B ) return;
515 
516  printf( "ErrorCode Test Failed: %s == %s\n", sA, sB );
517  printf( " at line %d of '%s'\n", line, file );
518  printf( " Expected value: %s (%d)\n", mb_error_str( A ), (int)A );
519  printf( " Actual value: %s (%d)\n", mb_error_str( B ), (int)B );
520  printf( "\n" );
521  flag_error();
522 }
523 
524 const char* mb_type_str( moab::EntityType type )
525 {
526  switch( type )
527  {
528  case moab::MBVERTEX:
529  return "Vertex";
530  case moab::MBEDGE:
531  return "Edge";
532  case moab::MBTRI:
533  return "Triangle";
534  case moab::MBQUAD:
535  return "Quadrilateral";
536  case moab::MBPOLYGON:
537  return "Polygon";
538  case moab::MBTET:
539  return "Tetrahedron";
540  case moab::MBPYRAMID:
541  return "Pyramid";
542  case moab::MBPRISM:
543  return "Prism (wedge)";
544  case moab::MBKNIFE:
545  return "Knife";
546  case moab::MBHEX:
547  return "Hexahedron";
548  case moab::MBPOLYHEDRON:
549  return "Polyhedron";
550  case moab::MBENTITYSET:
551  return "Entity (Mesh) Set";
552  case moab::MBMAXTYPE:
553  return "(max type)";
554  default:
555  return "(unknown)";
556  }
557 }
558 
560 {
561  return mb_type_str( moab::TYPE_FROM_HANDLE( a ) );
562 }
563 /*
564 void check_equal( moab::EntityHandle A, moab::EntityHandle B, const char* sA, const char* sB, int line, const char* file
565 )
566 {
567  if (A == B)
568  return;
569 
570  printf( "Entity handles not equal: %s == %s\n", sA, sB );
571  printf( " at line %d of '%s'\n", line, file );
572  if (A)
573  printf( " Expected value: %lx (%s %ld)\n", (unsigned long)A, mb_type_str( A ), (long)ID_FROM_HANDLE(A) );
574  else
575  printf( " Expected value: 0\n" );
576  if (B)
577  printf( " Actual value: %lx (%s %ld)\n", (unsigned long)B, mb_type_str( B ), (long)ID_FROM_HANDLE(B) );
578  else
579  printf( " Actual value: 0\n" );
580  printf( "\n" );
581  flag_error();
582 }
583 */
584 
585 void check_true( bool cond, const char* str, int line, const char* file )
586 {
587  if( !cond )
588  {
589  printf( "Test Failed: %s\n", str );
590  printf( " at line %d of '%s'\n", line, file );
591  printf( "\n" );
592  flag_error();
593  }
594 }
595 
596 #ifdef MB_CART_VECT_HPP
597 
598 void check_equal_cartvect( const moab::CartVect& A,
599  const moab::CartVect& B,
600  double eps,
601  const char* sA,
602  const char* sB,
603  int line,
604  const char* file )
605 {
606  check_equal( A.length(), B.length(), eps, sA, sB, line, file );
607 
608  if( fabs( A[0] - B[0] ) <= eps && fabs( A[1] - B[1] ) <= eps && fabs( A[2] - B[2] ) <= eps ) return;
609 
610  std::cout << "Equality Test Failed: " << sA << " == " << sB << std::endl;
611  std::cout << " at line " << line << " of '" << file << "'" << std::endl;
612 
613  std::cout << " Expected: ";
614  std::cout << A << std::endl;
615 
616  std::cout << " Actual: ";
617  std::cout << B << std::endl;
618 
619  flag_error();
620 }
621 
622 #endif // #ifdef MB_CART_VECT_HPP
623 
624 #ifdef __cplusplus
625 
626 template < typename T >
627 void check_array_equal( const T* A,
628  size_t A_size,
629  const T* B,
630  size_t B_size,
631  const char* sA,
632  const char* sB,
633  int line,
634  const char* file )
635 {
636  size_t i = 0;
637  for( ;; )
638  {
639  if( i == A_size && i == B_size )
640  return; // equal
641  else if( i == A_size || i == B_size )
642  break; // differene lengths
643  else if( A[i] != B[i] )
644  break;
645  ++i;
646  }
647 
648  std::cout << "Equality Test Failed: " << sA << " == " << sB << std::endl;
649  std::cout << " at line " << line << " of '" << file << "'" << std::endl;
650  std::cout << " Vectors differ at position " << i << std::endl;
651 
652  // print at most 10 values, roughly centered on the unequal one
653  size_t count = 10, num_front_values = std::min( count / 2, i );
654  size_t max_len = std::max( A_size, B_size );
655  if( i + count - num_front_values > max_len )
656  {
657  if( count > max_len )
658  {
659  num_front_values = i;
660  count = max_len;
661  }
662  else
663  {
664  num_front_values = count - ( max_len - i );
665  }
666  }
667 
668  std::cout << " Expected: ";
669  if( !A_size )
670  {
671  std::cout << "(empty)" << std::endl;
672  }
673  else
674  {
675  size_t j = i - num_front_values;
676  size_t end = std::min( j + count, A_size );
677  if( j ) std::cout << "... ";
678  for( ; j < end; ++j )
679  {
680  if( j == i )
681  std::cout << '>' << A[j] << "< ";
682  else
683  std::cout << A[j] << " ";
684  }
685  if( end != A_size ) std::cout << "...";
686  std::cout << std::endl;
687  }
688 
689  std::cout << " Actual: ";
690  if( !B_size )
691  {
692  std::cout << "(empty)" << std::endl;
693  }
694  else
695  {
696  size_t j = i - num_front_values;
697  size_t end = std::min( j + count, B_size );
698  if( j ) std::cout << "... ";
699  for( ; j < end; ++j )
700  {
701  if( j == i )
702  std::cout << '>' << B[j] << "< ";
703  else
704  std::cout << B[j] << " ";
705  }
706  if( end != B_size ) std::cout << ", ...";
707  std::cout << std::endl;
708  }
709 
710  flag_error();
711 }
712 
713 template < typename T >
714 void check_equal( const std::vector< T >& A,
715  const std::vector< T >& B,
716  const char* sA,
717  const char* sB,
718  int line,
719  const char* file )
720 {
721  if( A.empty() || B.empty() )
722  {
723  if( A.size() != B.size() )
724  {
725  std::cout << "Equality Test Failed: " << sA << " == " << sB << std::endl;
726  std::cout << " at line " << line << " of '" << file << "'" << std::endl;
727  std::cout << " Both are not empty " << std::endl;
728  }
729  return;
730  }
731  check_array_equal( &A[0], A.size(), &B[0], B.size(), sA, sB, line, file );
732 }
733 
734 #ifdef MOAB_RANGE_HPP
735 
736 void check_equal( const moab::Range& A,
737  const moab::Range& B,
738  const char* sA,
739  const char* sB,
740  int line,
741  const char* file )
742 {
743  if( A == B ) return;
744 
745  std::cout << "moab::ErrorCode Test Failed: " << sA << " == " << sB << std::endl;
746  std::cout << " at line " << line << " of '" << file << "'" << std::endl;
747  std::cout << " Expected: " << A << std::endl;
748  std::cout << " Actual : " << B << std::endl;
749  std::cout << std::endl;
750  flag_error();
751 }
752 
753 #endif // #ifdef MOAB_RANGE_HPP
754 
755 void check_baseline_file( std::string basefile,
756  std::vector< int >& gids,
757  std::vector< double >& vals,
758  double eps,
759  int& err_code )
760 {
761  err_code = 1;
762  std::fstream fs;
763  fs.open( basefile.c_str(), std::fstream::in );
764  if( !fs.is_open() )
765  {
766  std::cout << " error opening base file " << basefile << "\n";
767  flag_error();
768  return;
769  }
770  std::map< int, double > mapVals;
771  int id = 0;
772  double val = 0;
773  while( !fs.eof() )
774  {
775  fs >> id >> val;
776  mapVals[id] = val;
777  }
778  for( size_t i = 0; i < gids.size(); i++ )
779  {
780  std::map< int, double >::iterator it = mapVals.find( gids[i] );
781  if( it == mapVals.end() )
782  {
783  std::cout << "id - value not found:" << gids[i] << "\n";
784  flag_error();
785  return;
786  }
787  if( fabs( it->second - vals[i] ) > eps )
788  {
789  std::cout << " value out of range: index i=" << i << " id: " << gids[i] << " value:" << vals[i]
790  << " expected : " << it->second << "\n";
791  flag_error();
792  return;
793  }
794  }
795  err_code = 0; // no error
796 }
797 #endif /* ifdef __cplusplus */
798 
799 #endif