test encoding of special values
diff --git a/skeletons/tests/check-REAL.c b/skeletons/tests/check-REAL.c
index 46b1a95..07918ef 100644
--- a/skeletons/tests/check-REAL.c
+++ b/skeletons/tests/check-REAL.c
@@ -39,26 +39,29 @@
  * is as given in the (sample) and (canonical_sample) arguments.
  */
 static void
-check_str_repr(double d, const char *sample, const char *canonical_sample) {
+check_str_representation(double d, const char *sample, const char *canonical_sample) {
 	char *s0, *s1;
 
 	s0 = d2s(d, 0, sample);
 	s1 = d2s(d, 1, canonical_sample);
 
 	if(sample) {
-		printf("Checking %f->[%s] against [%s]%s\n",
+		printf("Checking %f->[\"%s\"] against [\"%s\"]%s\n",
 			d, s0, sample,
 			canonical_sample ? " (canonical follows...)" : ""
 		);
 		assert(!strcmp(s0, sample));
 	}
 	if(canonical_sample) {
-		printf("Checking %f->[%s] against [%s] (canonical)\n",
+		printf("Checking %f->[\"%s\"] against [\"%s\"] (canonical)\n",
 			d, s1, canonical_sample);
 		assert(!strcmp(s1, canonical_sample));
 	}
 }
 
+#define	check(rn, d, str1, str2)	\
+	check_impl(rn, d, str1, str2, __LINE__)
+
 static void
 check_impl(REAL_t *rn, double orig_dbl, const char *sample, const char *canonical_sample, int line) {
 	double val;
@@ -96,57 +99,8 @@
 	assert((isnan(orig_dbl) && isnan(val)) || val == orig_dbl);
 	printf("OK\n");
 
-	check_str_repr(val, sample, canonical_sample);
+	check_str_representation(val, sample, canonical_sample);
 }
-
-uint8_t buf_1_0[]  = { 0x80, 0xcc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-uint8_t buf_1_1[]  = { 0x80, 0xcc, 0x11, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a };
-uint8_t buf_3_14[] = { 0x80, 0xcd, 0x19, 0x1e, 0xb8, 0x51, 0xeb, 0x85, 0x1f };
-/* These ones are very interesting! They check mantissa overflow! */
-uint8_t buf_mo1[]  = { 0xC0, 0xc5, 0x19, 0x1e, 0xb8, 0x51, 0xeb, 0x85, 0x1f,3};
-uint8_t buf_mo2[]  = { 0x80, 0xbd, 0x19, 0x1e, 0xb8, 0x51, 0xeb, 0x85, 0x1f,3,2};
-
-static void
-check_buf(uint8_t *buf, size_t bufsize, double verify, const char *sample, const char *canonical_sample) {
-	REAL_t rn;
-	double val;
-	uint8_t *p, *end;
-	int ret;
-
-	printf("verify double value %.12f [", verify);
-	for(p = (uint8_t *)&verify, end = p + sizeof(double); p < end ; p++)
-		printf("%02x", *p);
-	printf("] (ilogb %d)\n", ilogb(verify));
-
-	rn.buf = 0;
-	rn.size = 0;
-
-	ret = asn_double2REAL(&rn, verify);
-	assert(ret == 0);
-
-	printf("canonical DER: [");
-	for(p = rn.buf, end = p + rn.size; p < end; p++)
-		printf("%02x", *p);
-	printf("]\n");
-
-	rn.buf = buf;
-	rn.size = bufsize;
-
-	printf("received as:   [");
-	for(p = rn.buf, end = p + rn.size; p < end; p++)
-		printf("%02x", *p);
-	printf("]\n");
-
-	ret = asn_REAL2double(&rn, &val);
-	assert(ret == 0);
-
-	printf("%.12f vs %.12f\n", verify, val);
-
-	assert(val == verify);
-
-	check_str_repr(val, sample, canonical_sample);
-}
-
 static void
 check_xer(int fuzzy, double orig_value) {
 	asn_enc_rval_t er;
@@ -207,16 +161,167 @@
 	assert(memcmp(newst1->buf, st.buf, st.size) == 0);
 }
 
-#define	check(rn, d, str1, str2)	\
-	check_impl(rn, d, str1, str2, __LINE__)
+static void
+check_ber_buffer_twoway(double d, const char *sample, const char *canonical_sample, uint8_t *inbuf, size_t insize, uint8_t *outbuf, size_t outsize) {
+	REAL_t rn;
+	double val;
+	int ret;
+
+	/*
+	 * Decode our expected buffer and check that it matches the given (d).
+	 */
+	rn.buf = inbuf;
+	rn.size = insize;
+	asn_REAL2double(&rn, &val);
+	if(isnan(val)) assert(isnan(d));
+	if(isnan(d)) assert(isnan(val));
+	if(!isnan(val) && !isnan(d)) {
+        assert(copysign(1.0, d) == copysign(1.0, val));
+        assert(d == val);
+    }
+
+	/*
+	 * Encode value and check that it matches our expected buffer.
+	 */
+	memset(&rn, 0, sizeof(rn));
+	ret = asn_double2REAL(&rn, d);
+	assert(ret == 0);
+    uint8_t *p, *end;
+	printf("received as:   [");
+	for(p = rn.buf, end = p + rn.size; p < end; p++)
+		printf("%02x", *p);
+	printf("]\n");
+	printf("received as:   [");
+	for(p = outbuf, end = p + outsize; p < end; p++)
+		printf("%02x", *p);
+	printf("]\n");
+	if(rn.size != outsize) {
+		printf("Encoded %f into %d expected %ld\n",
+			d, (int)rn.size, outsize);
+		assert(rn.size == outsize);
+	}
+	assert(memcmp(rn.buf, outbuf, rn.size) == 0);
+
+	check_str_representation(d, sample, canonical_sample);
+}
+
+static void
+check_ber_buffer_oneway(double d, const char *sample, const char *canonical_sample, uint8_t *buf, size_t bufsize) {
+	REAL_t rn;
+	double val;
+	uint8_t *p, *end;
+	int ret;
+
+	memset(&rn, 0, sizeof(rn));
+
+	printf("verify double value %.12f [", d);
+	for(p = (uint8_t *)&d, end = p + sizeof(double); p < end ; p++)
+		printf("%02x", *p);
+	printf("] (ilogb %d)\n", ilogb(d));
+
+
+	ret = asn_double2REAL(&rn, d);
+	assert(ret == 0);
+
+	printf("canonical DER: [");
+	for(p = rn.buf, end = p + rn.size; p < end; p++)
+		printf("%02x", *p);
+	printf("]\n");
+
+	rn.buf = buf;
+	rn.size = bufsize;
+
+	printf("received as:   [");
+	for(p = rn.buf, end = p + rn.size; p < end; p++)
+		printf("%02x", *p);
+	printf("]\n");
+
+	ret = asn_REAL2double(&rn, &val);
+	assert(ret == 0);
+
+	printf("%.12f vs %.12f\n", d, val);
+
+	assert(val == d);
+
+	check_str_representation(val, sample, canonical_sample);
+}
+
+
+static void
+check_ber_encoding() {
+	static const double zero = 0.0;
+
+#define CHECK_BER_STRICT(v, nocan, can, inbuf, outbuf)	\
+	check_ber_buffer_twoway(v, nocan, can, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf))
+
+#define CHECK_BER_NONSTRICT(v, nocan, can, buf)	\
+	check_ber_buffer_oneway(v, nocan, can, buf, sizeof(buf))
+
+	/*
+	 * X.690 8.4 Encoding of an enumerated value.
+	 */
+
+	/* 8.5.2 If the real value is the value plus zero,
+	 * there shall be no contents octet in the encoding */
+	{ uint8_t b_0[] = {};
+	  CHECK_BER_STRICT(0, "0", "0", b_0, b_0);
+    }
+
+	/* 8.5.3 When -0 is to be encoded, there shall be only one contents octet */
+	{ uint8_t b_m0[] = { 0x43 };
+	  CHECK_BER_STRICT(-0.0, "-0", "-0", b_m0, b_m0);
+    }
+
+    /* Old way of encoding -0.0: 8.5.6 a) */
+	{ uint8_t b_m0[] = { 0x43 };
+	  uint8_t b_m0_856a[]   = { 0xC0, 0x00 };  /* #8.5.6 a) */
+	  uint8_t b_m0_856a_1[] = { 0xC0, 0x00, 0x00 };
+	  uint8_t b_m0_856a_2[] = { 0xC0, 0x00, 0x00, 0x00 };
+	  uint8_t b_m0_856a_3[] = { 0xC0, 0x00, 0x00, 0x00, 0x00 };
+	  CHECK_BER_STRICT(-0.0, "-0", "-0", b_m0_856a, b_m0);
+	  CHECK_BER_STRICT(-0.0, "-0", "-0", b_m0_856a_1, b_m0);
+	  CHECK_BER_STRICT(-0.0, "-0", "-0", b_m0_856a_2, b_m0);
+	  CHECK_BER_STRICT(-0.0, "-0", "-0", b_m0_856a_3, b_m0);
+    }
+
+	/* 8.5.6 c) => 8.5.9 SpecialRealValue */
+	{ uint8_t b_pinf[] = { 0x40 };
+	  uint8_t b_minf[] = { 0x41 };
+	  uint8_t b_nan[]  = { 0x42 };
+	  CHECK_BER_STRICT(1.0/zero, "<PLUS-INFINITY/>", "<PLUS-INFINITY/>", b_pinf, b_pinf);
+	  CHECK_BER_STRICT(-1.0/zero, "<MINUS-INFINITY/>", "<MINUS-INFINITY/>", b_minf, b_minf);
+	  CHECK_BER_STRICT(zero/zero, "<NOT-A-NUMBER/>", "<NOT-A-NUMBER/>", b_nan, b_nan);
+    }
+
+	{
+	uint8_t b_1_0[] =
+		{ 0x80, 0xcc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+	uint8_t b_1_1[] =
+		{ 0x80, 0xcc, 0x11, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a };
+	uint8_t b_3_14[] =
+		{ 0x80, 0xcd, 0x19, 0x1e, 0xb8, 0x51, 0xeb, 0x85, 0x1f };
+	uint8_t b_3_14_mo1[] =
+		{ 0xC0, 0xc5, 0x19, 0x1e, 0xb8, 0x51, 0xeb, 0x85, 0x1f,3};
+	uint8_t b_3_14_mo2[] =
+		{ 0x80, 0xbd, 0x19, 0x1e, 0xb8, 0x51, 0xeb, 0x85, 0x1f,3,2};
+
+	CHECK_BER_NONSTRICT(1.0, "1.0", "1.0E0", b_1_0);
+	CHECK_BER_NONSTRICT(1.1, "1.1", "1.1E0", b_1_1);
+	CHECK_BER_NONSTRICT(3.14, "3.14", "3.14E0", b_3_14);
+	/* These two are very interesting! They check mantissa overflow! */
+	CHECK_BER_NONSTRICT(-3.14, "-3.14", "-3.14E0", b_3_14_mo1);
+	CHECK_BER_NONSTRICT(3.14, "3.14", "3.14E0", b_3_14_mo2);
+	}
+}
 
 int
 main() {
 	REAL_t rn;
 	static const double zero = 0.0;
-
 	memset(&rn, 0, sizeof(rn));
 
+	check_ber_encoding();
+
 	check(&rn, 0.0, "0", "0");
 	check(&rn, -0.0, "-0", "-0");	/* minus-zero */
 	check(&rn, zero/zero, "<NOT-A-NUMBER/>", "<NOT-A-NUMBER/>");
@@ -260,12 +365,6 @@
 	check(&rn, 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000033333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333, 0, 0);
 	check(&rn, -0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001, 0, 0);
 
-	check_buf(buf_1_0, sizeof(buf_1_0),	1.0, "1.0", "1.0E0");
-	check_buf(buf_1_1, sizeof(buf_1_1),	1.1, "1.1", "1.1E0");
-	check_buf(buf_3_14, sizeof(buf_3_14),	3.14, "3.14", "3.14E0");
-	check_buf(buf_mo1, sizeof(buf_mo1),	-3.14, "-3.14", "-3.14E0");
-	check_buf(buf_mo2, sizeof(buf_mo2),	3.14, "3.14", "3.14E0");
-
 
 #ifdef	NAN
 	check_xer(0, NAN);	/* "<NOT-A-NUMBER/>" */