text: #undef	NDEBUG
  #include <stdio.h>
  #include <stdlib.h>
  #include <sys/types.h>
  #include <string.h>
  #include <assert.h>
  
  #include <T.h>
  
  
  /*
   * Test that the optional member (c) is really optional.
   */
  uint8_t buf1[] = {
  	32 | 17,		/* [UNIVERSAL 17], constructed */
  	8,	/* L */
  
  	/* a INTEGER */
  	64 | 3,			/* [APPLICATION 3] */
  	1,	/* L */
    96,
  
  	/* b IA5String */
  	22,			/* [UNIVERSAL 22] */
  	3,	/* L */
  	'x',
  	'y',
  	'z'
  };
  
  /*
   * This buffer aims at checking the duplication.
   */
  uint8_t buf2[] = {
  	32 | 17,		/* [UNIVERSAL 17], constructed */
  	8,	/* L */
  
  	/* a INTEGER */
  	64 | 3,			/* [APPLICATION 3] */
  	1,	/* L */
    96,
  
  	/* a INTEGER _again_ */
  	64 | 3,			/* [APPLICATION 3] */
  	1,	/* L */
    97,
  };
  
  /*
   * This buffer checks that an unexpected member may be properly ignored.
   */
  uint8_t buf3[] = {
  	32 | 17,		/* [UNIVERSAL 17], constructed */
  	14,	/* L */
  
  	/* INTEGER */
  	64 | 3,			/* [APPLICATION 3] */
  	1,	/* L */
    96,
  
  	/* IA5String */
  	22,			/* [UNIVERSAL 22] */
  	3,	/* L */
  	'x',
  	'y',
  	'z',
  
  	/* unexpected INTEGER */
  	64 | 4,			/* [APPLICATION 4] */
  	1,	/* L */
    96,
  
  	/* [2] BOOLEAN */
  	((2 << 6) + 2),			/* [2] */
  	1,	/* L */
  	0xff
  };
  
  /*
   * This buffer checks that an unexpected member may be properly ignored.
   * This time, with indefinite length encoding.
   */
  uint8_t buf4[] = {
  	32 | 17,		/* [UNIVERSAL 17], constructed */
  	16,	/* L */
  
  	/* a INTEGER */
  	64 | 3,			/* [APPLICATION 3] */
  	1,	/* L */
    96,
  
  	/* b IA5String */
  	22,			/* [UNIVERSAL 22] */
  	3,	/* L */
  	'x',
  	'y',
  	'z',
  
  	/* unexpected data structure */
  	32 | 64 | 4,			/* [APPLICATION 4] */
  	0x80,	/* indefinite L */
  	64 | 1,			/* [APPLICATION 1] */
  	2,	/* L */
  	'a', 'b',
  
  	0x00,
  	0x00
  };
  
  /*
   * This buffer checks that an unexpected member may be properly ignored.
   * This time, with indefinite length encoding at the outer level too.
   */
  uint8_t buf5[] = {
  	32 | 17,		/* [UNIVERSAL 17], constructed */
  	0x80,	/* indefinite L */
  
  	/* INTEGER */
  	64 | 3,			/* [APPLICATION 3] */
  	1,	/* L */
    96,
  
  	/* IA5String */
  	22,			/* [UNIVERSAL 22] */
  	3,	/* L */
  	'x',
  	'y',
  	'z',
  
  	/* unexpected data structure */
  	32 | 64 | 4,			/* [APPLICATION 4] */
  	0x80,	/* indefinite L */
  	64 | 1,			/* [APPLICATION 1] */
  	2,	/* L */
  	'a', 'b',
  
  	0x00,
  	0x00,
  
  	0x00,
  	0x00
  };
  
  static void
  check(int is_ok, uint8_t *buf, size_t size, size_t consumed) {
  	T_t t, *tp;
  	asn_dec_rval_t rval;
  
  	fprintf(stderr, "\nMust %s:\n", is_ok?"succeed":"fail");
  
  	tp = memset(&t, 0, sizeof(t));
  
  	fprintf(stderr, "Buf %p\n", buf);
  	rval = ber_decode(0, &asn_DEF_T, (void **)&tp, buf, size);
  	fprintf(stderr, "Returned code %d, consumed %zd (out of %zd)\n",
  		(int)rval.code, rval.consumed, size);
  
  	if(is_ok) {
  		assert(rval.code == RC_OK);
  		assert(rval.consumed == consumed);
  
  		assert(t.i.size == 1);
  		assert(t.i.buf[0] == 96);
  		assert(t.s.size == 3);
  		assert(strcmp((char *)t.s.buf, "xyz") == 0);
  		if(buf == buf3) {
  			assert(t.b);
  		} else {
  			assert(t.b == 0);
  		}
  	} else {
  		if(rval.code == RC_OK) {
  			assert(t.i.size != 1
  			|| t.s.size != 3
  			|| !t.b
  			);
  		}
  		assert(rval.consumed <= consumed);
  	}
  	ASN_STRUCT_RESET(asn_DEF_T, tp);
  }
  
  
  static char xer_buf[128];
  static int xer_off;
  
  static int
  xer_cb(const void *buffer, size_t size, void *key) {
  	(void)key;
  	assert(xer_off + size < sizeof(xer_buf));
  	memcpy(xer_buf + xer_off, buffer, size);
  	xer_off += size;
  	return 0;
  }
  
  static void
  check_xer(uint8_t *buf, uint8_t size, char *xer_sample) {
  	T_t *tp = 0;
  	asn_dec_rval_t rval;
  	asn_enc_rval_t er;
  	int xer_sample_len = strlen(xer_sample);
  
  	rval = ber_decode(0, &asn_DEF_T, (void **)&tp, buf, size);
  	assert(rval.code == RC_OK);
  	assert(rval.consumed == size);
  	assert(tp);
  
  	xer_off = 0;
  	er = xer_encode(&asn_DEF_T, tp, XER_F_CANONICAL, xer_cb, 0);
  	assert(er.encoded == xer_off);
  	assert(xer_off);
  	xer_buf[xer_off] = 0;
  	printf("[%s] vs [%s]\n", xer_buf, xer_sample);
  	assert(xer_off == xer_sample_len);
  	assert(memcmp(xer_buf, xer_sample, xer_off) == 0);
  
  	ASN_STRUCT_FREE(asn_DEF_T, tp);
  }
  
  static void
  try_corrupt(uint8_t *buf, size_t size) {
  	uint8_t tmp[size];
  
  	fprintf(stderr, "\nCorrupting...\n");
  
  	for(int i = 0; i < 1000; i++) {
  		int loc;
  		memcpy(tmp, buf, size);
  
  		/* Corrupt random _non-value_ location. */
  		do { loc = random() % size; } while(tmp[loc] >= 70);
  		do { tmp[loc] = buf[loc] ^ random(); } while(
  			(tmp[loc] == buf[loc])
  			|| (buf[loc] == 0 && tmp[loc] == 0x80));
  
  		fprintf(stderr, "\nTry %d: corrupting byte %d (%d->%d)\n",
  			i, loc, buf[loc], tmp[loc]);
  
  		check(0, tmp, size, size);
  	}
  }
  
  int
  main(int ac, char **av) {
  
  	(void)ac;	/* Unused argument */
  	(void)av;	/* Unused argument */
  
  	check(1, buf1, sizeof(buf1) + 20, sizeof(buf1));
  	check(0, buf2, sizeof(buf2) + 1, 5);
  	check(1, buf3, sizeof(buf3) + 1, sizeof(buf3));
  	check(1, buf4, sizeof(buf4), sizeof(buf4));
  	check(1, buf5, sizeof(buf5), sizeof(buf5));
  	check(1, buf5, sizeof(buf5) + 1, sizeof(buf5));
  	check(0, buf5, sizeof(buf5) - 1, sizeof(buf5));
  
  	check_xer(buf1, sizeof(buf1), "<T><s>xyz</s><i>96</i></T>");
  	check_xer(buf3, sizeof(buf3), "<T><s>xyz</s><i>96</i><b><true/></b></T>");
  
  	fprintf(stderr, "\nPseudo-random buffer corruptions must fail\n");
  	try_corrupt(buf1, sizeof(buf1));
  
  	return 0;
  }
  