From b191c221b1b464d73d35026e5ff38a33cb08829b Mon Sep 17 00:00:00 2001
From: Daniel Salzman <daniel.salzman@nic.cz>
Date: Mon, 18 Feb 2013 16:28:46 +0100
Subject: [PATCH] Improve RR descriptors

- Add missing descriptors.
- Extend descriptor structure with type name.
- Add conversion functions num<->str for types and classes.

refs @2138
---
 Knot.files                          |   2 +
 src/Makefile.am                     |   6 +-
 src/common/descriptor_new.c         | 243 +++++++++++++++++++++-------
 src/common/descriptor_new.h         | 125 ++++++++++++--
 src/tests/common/descriptor_tests.c | 234 +++++++++++++++++++++++++++
 src/tests/common/descriptor_tests.h |  25 +++
 src/tests/unittests_main.c          |   2 +
 7 files changed, 566 insertions(+), 71 deletions(-)
 create mode 100644 src/tests/common/descriptor_tests.c
 create mode 100644 src/tests/common/descriptor_tests.h

diff --git a/Knot.files b/Knot.files
index 20726fc0f..745e81781 100644
--- a/Knot.files
+++ b/Knot.files
@@ -177,6 +177,8 @@ src/tests/common/base64_tests.c
 src/tests/common/base64_tests.h
 src/tests/common/base32hex_tests.c
 src/tests/common/base32hex_tests.h
+src/tests/common/descriptor_tests.c
+src/tests/common/descriptor_tests.h
 src/tests/knot/dthreads_tests.c
 src/tests/knot/dthreads_tests.h
 src/tests/knot/conf_tests.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 6782eafe1..0dca9fb42 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -31,14 +31,16 @@ unittests_SOURCES =				\
 	tests/common/base32hex_tests.h		\
 	tests/common/base64_tests.c		\
 	tests/common/base64_tests.h		\
+	tests/common/descriptor_tests.h		\
+	tests/common/descriptor_tests.c		\
 	tests/common/events_tests.c		\
 	tests/common/events_tests.h		\
+	tests/common/fdset_tests.c		\
+	tests/common/fdset_tests.h		\
 	tests/common/skiplist_tests.c		\
 	tests/common/skiplist_tests.h		\
 	tests/common/slab_tests.c		\
 	tests/common/slab_tests.h		\
-	tests/common/fdset_tests.c		\
-	tests/common/fdset_tests.h		\
 	tests/knot/conf_tests.c			\
 	tests/knot/conf_tests.h			\
 	tests/knot/dthreads_tests.c		\
diff --git a/src/common/descriptor_new.c b/src/common/descriptor_new.c
index f3b1dd5ec..07b3779df 100644
--- a/src/common/descriptor_new.c
+++ b/src/common/descriptor_new.c
@@ -15,109 +15,240 @@
  */
 
 #include "common/descriptor_new.h"
+#include "libknot/util/utils.h"		// knot_lookup_table_t
+
+#include <stdio.h>			// snprintf
+#include <stdlib.h>			// strtoul
+
+/*! 
+ * \brief The last RR type number in the descriptors table.
+ */
+const int KNOT_RRTYPE_LAST = KNOT_RRTYPE_ANY;
+
+/*!
+ * \brief Table with DNS classes.
+ */
+static knot_lookup_table_t dns_classes[] = {
+	{ KNOT_CLASS_IN,   "IN" },
+	{ KNOT_CLASS_CH,   "CH" },
+	{ KNOT_CLASS_NONE, "NONE" },
+	{ KNOT_CLASS_ANY,  "ANY" },
+	{ 0, NULL }
+};
 
 /*!
  * \brief RR type descriptors.
  */
 static const rdata_descriptor_t rdata_descriptors[] = {
-	[0]			 = { { KNOT_RDATA_WF_REMAINDER,
-				       KNOT_RDATA_WF_END } },
-	[KNOT_RRTYPE_A]          = { { 4, KNOT_RDATA_WF_END } },
+	[0]                      = { { KNOT_RDATA_WF_REMAINDER,
+	                               KNOT_RDATA_WF_END } },
+	[KNOT_RRTYPE_A]          = { { 4, KNOT_RDATA_WF_END }, "A" },
 	[KNOT_RRTYPE_NS]         = { { KNOT_RDATA_WF_COMPRESSED_DNAME,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "NS" },
 	[KNOT_RRTYPE_CNAME]      = { { KNOT_RDATA_WF_COMPRESSED_DNAME,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "CNAME" },
 	[KNOT_RRTYPE_SOA]        = { { KNOT_RDATA_WF_COMPRESSED_DNAME,
-				       KNOT_RDATA_WF_COMPRESSED_DNAME,
-				       20, KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_COMPRESSED_DNAME,
+	                               20, KNOT_RDATA_WF_END }, "SOA" },
 	[KNOT_RRTYPE_PTR]        = { { KNOT_RDATA_WF_COMPRESSED_DNAME,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "PTR" },
 	[KNOT_RRTYPE_HINFO]      = { { KNOT_RDATA_WF_REMAINDER,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "HINFO" },
 	[KNOT_RRTYPE_MINFO]      = { { KNOT_RDATA_WF_COMPRESSED_DNAME,
-				       KNOT_RDATA_WF_COMPRESSED_DNAME,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_COMPRESSED_DNAME,
+	                               KNOT_RDATA_WF_END }, "MINFO" },
 	[KNOT_RRTYPE_MX]         = { { 2, KNOT_RDATA_WF_COMPRESSED_DNAME,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "MX" },
 	[KNOT_RRTYPE_TXT]        = { { KNOT_RDATA_WF_REMAINDER,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "TXT" },
 	[KNOT_RRTYPE_RP]         = { { KNOT_RDATA_WF_COMPRESSED_DNAME,
-				       KNOT_RDATA_WF_COMPRESSED_DNAME,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_COMPRESSED_DNAME,
+	                               KNOT_RDATA_WF_END }, "RP" },
 	[KNOT_RRTYPE_AFSDB]      = { { 2, KNOT_RDATA_WF_COMPRESSED_DNAME,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "AFSDB" },
 	[KNOT_RRTYPE_RT]         = { { 2, KNOT_RDATA_WF_COMPRESSED_DNAME,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "RT" },
 	[KNOT_RRTYPE_KEY]        = { { KNOT_RDATA_WF_REMAINDER,
-				       KNOT_RDATA_WF_END } },
-	[KNOT_RRTYPE_AAAA]       = { { 16, KNOT_RDATA_WF_END } },
-	[KNOT_RRTYPE_LOC]        = { { 16, KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "KEY" },
+	[KNOT_RRTYPE_AAAA]       = { { 16, KNOT_RDATA_WF_END }, "AAAA" },
+	[KNOT_RRTYPE_LOC]        = { { 16, KNOT_RDATA_WF_END }, "LOC" },
 	[KNOT_RRTYPE_SRV]        = { { 6, KNOT_RDATA_WF_UNCOMPRESSED_DNAME,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "SRV" },
 	[KNOT_RRTYPE_NAPTR]      = { { KNOT_RDATA_WF_NAPTR_HEADER,
-				       KNOT_RDATA_WF_UNCOMPRESSED_DNAME,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_UNCOMPRESSED_DNAME,
+	                               KNOT_RDATA_WF_END }, "NAPTR" },
 	[KNOT_RRTYPE_KX]         = { { 2, KNOT_RDATA_WF_COMPRESSED_DNAME,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "KX" },
 	[KNOT_RRTYPE_CERT]       = { { KNOT_RDATA_WF_REMAINDER,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "CERT" },
 	[KNOT_RRTYPE_DNAME]      = { { KNOT_RDATA_WF_UNCOMPRESSED_DNAME,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "DNAME" },
 	[KNOT_RRTYPE_OPT]        = { { KNOT_RDATA_WF_REMAINDER,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "OPT" },
 	[KNOT_RRTYPE_APL]        = { { KNOT_RDATA_WF_REMAINDER,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "APL" },
 	[KNOT_RRTYPE_DS]         = { { KNOT_RDATA_WF_REMAINDER,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "DS" },
 	[KNOT_RRTYPE_SSHFP]      = { { KNOT_RDATA_WF_REMAINDER,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "SSHFP" },
 	[KNOT_RRTYPE_IPSECKEY]   = { { KNOT_RDATA_WF_REMAINDER,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "IPSECKEY" },
 	[KNOT_RRTYPE_RRSIG]      = { { 18, KNOT_RDATA_WF_LITERAL_DNAME,
-				       KNOT_RDATA_WF_REMAINDER,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_REMAINDER,
+	                               KNOT_RDATA_WF_END }, "RRSIG" },
 	[KNOT_RRTYPE_NSEC]       = { { KNOT_RDATA_WF_LITERAL_DNAME,
-				       KNOT_RDATA_WF_REMAINDER,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_REMAINDER,
+	                               KNOT_RDATA_WF_END }, "NSEC" },
 	[KNOT_RRTYPE_DNSKEY]     = { { KNOT_RDATA_WF_REMAINDER,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "DNSKEY" },
 	[KNOT_RRTYPE_DHCID]      = { { KNOT_RDATA_WF_REMAINDER,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "DHCID" },
 	[KNOT_RRTYPE_NSEC3]      = { { KNOT_RDATA_WF_REMAINDER,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "NSEC3" },
 	[KNOT_RRTYPE_NSEC3PARAM] = { { KNOT_RDATA_WF_REMAINDER,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "NSEC3PARAM" },
 	[KNOT_RRTYPE_TLSA]       = { { KNOT_RDATA_WF_REMAINDER,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "TLSA" },
 	[KNOT_RRTYPE_SPF]        = { { KNOT_RDATA_WF_REMAINDER,
-				       KNOT_RDATA_WF_END } },
-	[KNOT_RRTYPE_TSIG]       = { { KNOT_RDATA_WF_UNCOMPRESSED_DNAME,
-				       KNOT_RDATA_WF_REMAINDER,
-				       KNOT_RDATA_WF_END } },
+	                               KNOT_RDATA_WF_END }, "SPF" },
+	[KNOT_RRTYPE_TKEY]       = { { KNOT_RDATA_WF_REMAINDER,
+	                               KNOT_RDATA_WF_END }, "TKEY" },
+	[KNOT_RRTYPE_TSIG]       = { { KNOT_RDATA_WF_REMAINDER,
+	                               KNOT_RDATA_WF_END }, "TSIG" },
+	[KNOT_RRTYPE_IXFR]       = { { KNOT_RDATA_WF_REMAINDER,
+	                               KNOT_RDATA_WF_END }, "IXFR" },
+	[KNOT_RRTYPE_AXFR]       = { { KNOT_RDATA_WF_REMAINDER,
+	                               KNOT_RDATA_WF_END }, "AXFR" },
+	[KNOT_RRTYPE_ANY]        = { { KNOT_RDATA_WF_REMAINDER,
+	                               KNOT_RDATA_WF_END }, "ANY" },
 };
 
 const rdata_descriptor_t *get_rdata_descriptor(const uint16_t type)
 {
-	if (type <= KNOT_RRTYPE_TSIG) {
+	if (type <= KNOT_RRTYPE_ANY && rdata_descriptors[type].type_name != 0) {
 		return &rdata_descriptors[type];
 	} else {
 		return &rdata_descriptors[0];
 	}
 }
 
-int descriptor_item_is_dname(int item)
+int knot_rrtype_to_string(const uint16_t rrtype,
+                          char           *out,
+                          const size_t   out_len)
+{
+	int ret;
+
+	const rdata_descriptor_t *descr = get_rdata_descriptor(rrtype);
+
+	if (descr->type_name != 0) {
+		ret = snprintf(out, out_len, "%s", descr->type_name);
+	} else {
+		ret = snprintf(out, out_len, "TYPE%u", rrtype);
+	}
+
+	if (ret <= 0 || ret >= out_len) {
+		return -1;
+	} else {
+		return ret;
+	}
+}
+
+int knot_rrtype_from_string(const char *name, uint16_t *num)
+{
+	char *end;
+	unsigned i;
+	unsigned long n;
+
+	// Try to find name in descriptors table.
+	for (i = 0; i <= KNOT_RRTYPE_LAST; i++) {
+		if (rdata_descriptors[i].type_name != 0 &&
+		    strcasecmp(rdata_descriptors[i].type_name, name) == 0) {
+			*num = i;
+			return 0;
+		}
+	}
+
+	// Type name must begin with TYPE.
+	if (strncasecmp(name, "TYPE", 4) != 0) {
+		return -1;
+	} else {
+		name += 4;
+	}
+
+	// The rest must be a number.
+	n = strtoul(name, &end, 10);
+	if (end == name || *end != '\0' || n > UINT16_MAX) {
+		return -1;
+	}
+
+	*num = n;
+	return 0;
+}
+
+int knot_rrclass_to_string(const uint16_t rrclass,
+                           char           *out,
+                           const size_t   out_len)
+{
+	int ret;
+
+	knot_lookup_table_t *entry = knot_lookup_by_id(dns_classes, rrclass);
+
+	if (entry != NULL) {
+		ret = snprintf(out, out_len, "%s", entry->name);
+	} else {
+		ret = snprintf(out, out_len, "CLASS%u", rrclass);
+	}
+
+	if (ret <= 0 || ret >= out_len) {
+		return -1;
+	} else {
+		return ret;
+	}
+}
+
+int knot_rrclass_from_string(const char *name, uint16_t *num)
+{
+	char *end;
+	unsigned long n;
+
+	// Try to find name in lookup table.
+	knot_lookup_table_t *entry = knot_lookup_by_name(dns_classes, name);
+
+	if (entry != NULL) {
+		*num = entry->id;
+		return 0;
+	}
+
+	// Class name must begin with CLASS.
+	if (strncasecmp(name, "CLASS", 5) != 0) {
+		return -1;
+	} else {
+		name += 5;
+	}
+
+	// The rest must be a number.
+	n = strtoul(name, &end, 10);
+	if (end == name || *end != '\0' || n > UINT16_MAX) {
+		return -1;
+	}
+
+	*num = n;
+	return 0;
+}
+
+int descriptor_item_is_dname(const int item)
 {
 	return item == KNOT_RDATA_WF_LITERAL_DNAME ||
 	       item == KNOT_RDATA_WF_COMPRESSED_DNAME ||
 	       item == KNOT_RDATA_WF_UNCOMPRESSED_DNAME;
 }
 
-int descriptor_item_is_compr_dname(int item)
+int descriptor_item_is_compr_dname(const int item)
 {
 	return item == KNOT_RDATA_WF_COMPRESSED_DNAME;
 }
 
-int descriptor_item_is_fixed(int item)
+int descriptor_item_is_fixed(const int item)
 {
 	if (item > 0) {
 		return 1;
@@ -126,7 +257,7 @@ int descriptor_item_is_fixed(int item)
 	}
 }
 
-int descriptor_item_is_remainder(int item)
+int descriptor_item_is_remainder(const int item)
 {
 	if (item == KNOT_RDATA_WF_REMAINDER) {
 		return 1;
@@ -135,13 +266,13 @@ int descriptor_item_is_remainder(int item)
 	}
 }
 
-int knot_rrtype_is_metatype(uint16_t type)
+int knot_rrtype_is_metatype(const uint16_t type)
 {
-	/*! \todo Check if there are some other metatypes. */
-	return (type == KNOT_RRTYPE_ANY
-	        || type == KNOT_RRTYPE_AXFR
-	        || type == KNOT_RRTYPE_IXFR
-	        || type == KNOT_RRTYPE_OPT);
+	return (type == KNOT_RRTYPE_OPT ||
+	        type == KNOT_RRTYPE_TKEY ||
+	        type == KNOT_RRTYPE_TSIG ||
+	        type == KNOT_RRTYPE_IXFR ||
+	        type == KNOT_RRTYPE_AXFR ||
+	        type == KNOT_RRTYPE_ANY);
 }
 
-
diff --git a/src/common/descriptor_new.h b/src/common/descriptor_new.h
index ef3b83f96..4bf23f8f4 100644
--- a/src/common/descriptor_new.h
+++ b/src/common/descriptor_new.h
@@ -18,13 +18,15 @@
  *
  * \author Jan Kadlec <jan.kadlec@nic.cz>
  *
+ * \addtogroup common_lib
  * @{
  */
 
 #ifndef _KNOT_DESCRIPTOR_NEW_H_
 #define _KNOT_DESCRIPTOR_NEW_H_
 
-#include <stdint.h>
+#include <stdint.h>			// uint16_t
+#include <stdio.h>			// size_t
 
 #define KNOT_MAX_RDATA_BLOCKS	8
 
@@ -71,7 +73,7 @@ enum knot_rr_type {
 
 	KNOT_RRTYPE_DNAME      =  39, /*!< Delegation name. */
 
-	KNOT_RRTYPE_OPT        =  41, /*!< Option for EDNS*/
+	KNOT_RRTYPE_OPT        =  41, /*!< METATYPE. Option for EDNS. */
 	KNOT_RRTYPE_APL        =  42, /*!< Address prefix list. */
 	KNOT_RRTYPE_DS         =  43, /*!< Delegation signer. */
 	KNOT_RRTYPE_SSHFP      =  44, /*!< SSH public key fingerprint. */
@@ -82,15 +84,16 @@ enum knot_rr_type {
 	KNOT_RRTYPE_DHCID      =  49, /*!< DHCP identifier. */
 	KNOT_RRTYPE_NSEC3      =  50, /*!< NSEC version 3. */
 	KNOT_RRTYPE_NSEC3PARAM =  51, /*!< NSEC3 parameters. */
-	KNOT_RRTYPE_TLSA       =  52, /*!< DANE. */
+	KNOT_RRTYPE_TLSA       =  52, /*!< DANE record. */
 
 	KNOT_RRTYPE_SPF        =  99, /*!< Sender policy framework. */
 
-	KNOT_RRTYPE_TSIG       = 250, /*!< Transaction signature. */
-	KNOT_RRTYPE_IXFR       = 251, /*!< Incremental zone transfer. */
-	KNOT_RRTYPE_AXFR       = 252, /*!< Authoritative zone transfer. */
+	KNOT_RRTYPE_TKEY       = 249, /*!< METATYPE. Transaction key. */
+	KNOT_RRTYPE_TSIG       = 250, /*!< METATYPE. Transaction signature. */
+	KNOT_RRTYPE_IXFR       = 251, /*!< QTYPE. Incremental zone transfer. */
+	KNOT_RRTYPE_AXFR       = 252, /*!< QTYPE. Authoritative zone transfer. */
 
-	KNOT_RRTYPE_ANY        = 255, /*!< Any record. */
+	KNOT_RRTYPE_ANY        = 255, /*!< QTYPE. Any record. */
 };
 
 /*!
@@ -115,7 +118,10 @@ enum knot_rdata_wireformat {
  * \brief Structure describing rdata.
  */
 typedef struct {
-	int block_types[KNOT_MAX_RDATA_BLOCKS];
+	/*!< Item types describing rdata. */
+	const int  block_types[KNOT_MAX_RDATA_BLOCKS];
+	/*!< RR type name. */
+	const char *type_name;
 } rdata_descriptor_t;
 
 /*!
@@ -128,12 +134,105 @@ typedef struct {
  */
 const rdata_descriptor_t *get_rdata_descriptor(const uint16_t type);
 
-int descriptor_item_is_dname(int item);
-int descriptor_item_is_fixed(int item);
-int descriptor_item_is_remainder(int item);
-int descriptor_item_is_compr_dname(int item);
-int knot_rrtype_is_metatype(uint16_t type);
+/*!
+ * \brief Converts numeric type representation to mnemonic string.
+ *
+ * \param rrtype  Type RR type code to be converted.
+ * \param out     Output buffer.
+ * \param out_len Length of the output buffer.
+ *
+ * \return Length of output string.
+ * \return -1 if error.
+ */
+int knot_rrtype_to_string(const uint16_t rrtype,
+                          char           *out,
+                          const size_t   out_len);
+
+/*!
+ * \brief Converts mnemonic string representation of a type to numeric one.
+ *
+ * \param name Mnemonic string to be converted.
+ * \param num  Output variable.
+ *
+ * \return  0 if OK.
+ * \return -1 if error.
+ */
+int knot_rrtype_from_string(const char *name, uint16_t *num);
+
+/*!
+ * \brief Converts numeric class representation to the string one.
+ *
+ * \param rrclass Class code to be converted.
+ * \param out     Output buffer.
+ * \param out_len Length of the output buffer.
+ *
+ * \return Length of output string.
+ * \return -1 if error.
+ */
+int knot_rrclass_to_string(const uint16_t rrclass,
+                           char           *out,
+                           const size_t   out_len);
 
+/*!
+ * \brief Converts string representation of a class to numeric one.
+ *
+ * \param name Mnemonic string to be converted.
+ * \param num  Output variable.
+ *
+ * \return  0 if OK.
+ * \return -1 if error.
+ */
+int knot_rrclass_from_string(const char *name, uint16_t *num);
+
+/*!
+ * \brief Checks if given item is one of dname types.
+ *
+ * \param item Item value.
+ *
+ * \return 1 if YES.
+ * \return 0 if NO.
+ */
+int descriptor_item_is_dname(const int item);
+
+/*!
+ * \brief Checks if given item is compressible dname.
+ *
+ * \param item Item value.
+ *
+ * \return 1 if YES.
+ * \return 0 if NO.
+ */
+int descriptor_item_is_compr_dname(const int item);
+
+/*!
+ * \brief Checks if given item has fixed size.
+ *
+ * \param item Item value.
+ *
+ * \return 1 if YES.
+ * \return 0 if NO.
+ */
+int descriptor_item_is_fixed(const int item);
+
+/*!
+ * \brief Checks if given item is remainder.
+ *
+ * \param item Item value.
+ *
+ * \return 1 if YES.
+ * \return 0 if NO.
+ */
+int descriptor_item_is_remainder(const int item);
+
+/*!
+ * \brief Checks if given item is one of metatypes or qtypes.
+ *
+ * \param item Item value.
+ *
+ * \return 1 if YES.
+ * \return 0 if NO.
+ */
+int knot_rrtype_is_metatype(const uint16_t type);
 
 #endif // _KNOT_DESCRIPTOR_NEW_H_
 
diff --git a/src/tests/common/descriptor_tests.c b/src/tests/common/descriptor_tests.c
new file mode 100644
index 000000000..83b4aca22
--- /dev/null
+++ b/src/tests/common/descriptor_tests.c
@@ -0,0 +1,234 @@
+/*  Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "tests/common/descriptor_tests.h"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "common/descriptor_new.h"
+
+#define BUF_LEN 256
+
+static int descriptor_tests_count(int argc, char *argv[]);
+static int descriptor_tests_run(int argc, char *argv[]);
+
+unit_api descriptor_tests_api = {
+	"RR descriptors",
+	&descriptor_tests_count,
+	&descriptor_tests_run
+};
+
+static int descriptor_tests_count(int argc, char *argv[])
+{
+	return 68;
+}
+
+static int descriptor_tests_run(int argc, char *argv[])
+{
+	const    rdata_descriptor_t *descr;
+	char     name[BUF_LEN];
+	int      ret;
+	uint16_t num;
+
+	// Get descriptor, type num to string:
+	// 1. TYPE0
+	descr = get_rdata_descriptor(0);
+	ok(descr->type_name == 0, "get TYPE0 descriptor name");
+	cmp_ok(descr->block_types[0], "==", KNOT_RDATA_WF_REMAINDER,
+	       "get TYPE0 descriptor 1. item type");
+	cmp_ok(descr->block_types[1], "==", KNOT_RDATA_WF_END,
+	       "get TYPE0 descriptor 2. item type");
+
+	ret = knot_rrtype_to_string(0, name, BUF_LEN);
+	cmp_ok(ret, "!=", -1, "get TYPE0 ret");
+	ok(strcmp(name, "TYPE0") == 0, "get TYPE0 name");
+
+	// 2. A
+	descr = get_rdata_descriptor(1);
+	ok(strcmp(descr->type_name, "A") == 0, "get A descriptor name");
+	cmp_ok(descr->block_types[0], "==", 4,
+	       "get A descriptor 1. item type");
+	cmp_ok(descr->block_types[1], "==", KNOT_RDATA_WF_END,
+	       "get A descriptor 2. item type");
+
+	ret = knot_rrtype_to_string(1, name, BUF_LEN);
+	cmp_ok(ret, "!=", -1, "get A ret");
+	ok(strcmp(name, "A") == 0, "get A name");
+
+	// 3. CNAME
+	descr = get_rdata_descriptor(5);
+	ok(strcmp(descr->type_name, "CNAME") == 0, "get CNAME descriptor name");
+	cmp_ok(descr->block_types[0], "==", KNOT_RDATA_WF_COMPRESSED_DNAME,
+	       "get CNAME descriptor 1. item type");
+	cmp_ok(descr->block_types[1], "==", KNOT_RDATA_WF_END,
+	       "get CNAME descriptor 2. item type");
+
+	ret = knot_rrtype_to_string(5, name, BUF_LEN);
+	cmp_ok(ret, "!=", -1, "get CNAME ret");
+	ok(strcmp(name, "CNAME") == 0, "get CNAME name");
+
+	// 4. TYPE38 (A6)
+	descr = get_rdata_descriptor(38);
+	ok(descr->type_name == 0, "get TYPE38 descriptor name");
+	cmp_ok(descr->block_types[0], "==", KNOT_RDATA_WF_REMAINDER,
+	       "get TYPE38 descriptor 1. item type");
+	cmp_ok(descr->block_types[1], "==", KNOT_RDATA_WF_END,
+	       "get TYPE38 descriptor 2. item type");
+
+	ret = knot_rrtype_to_string(38, name, BUF_LEN);
+	cmp_ok(ret, "!=", -1, "get TYPE38 ret");
+	ok(strcmp(name, "TYPE38") == 0, "get TYPE38 name");
+
+	// 5. ANY
+	descr = get_rdata_descriptor(255);
+	ok(strcmp(descr->type_name, "ANY") == 0, "get ANY descriptor name");
+	cmp_ok(descr->block_types[0], "==", KNOT_RDATA_WF_REMAINDER,
+	       "get ANY descriptor 1. item type");
+	cmp_ok(descr->block_types[1], "==", KNOT_RDATA_WF_END,
+	       "get ANY descriptor 2. item type");
+
+	ret = knot_rrtype_to_string(255, name, BUF_LEN);
+	cmp_ok(ret, "!=", -1, "get ANY ret");
+	ok(strcmp(name, "ANY") == 0, "get ANY name");
+
+	// 6. TYPE256
+	descr = get_rdata_descriptor(256);
+	ok(descr->type_name == 0, "get TYPE256 descriptor name");
+	cmp_ok(descr->block_types[0], "==", KNOT_RDATA_WF_REMAINDER,
+	       "get TYPE256 descriptor 1. item type");
+	cmp_ok(descr->block_types[1], "==", KNOT_RDATA_WF_END,
+	       "get TYPE256 descriptor 2. item type");
+
+	ret = knot_rrtype_to_string(256, name, BUF_LEN);
+	cmp_ok(ret, "!=", -1, "get TYPE256 ret");
+	ok(strcmp(name, "TYPE256") == 0, "get TYPE256 name");
+
+
+	// Class num to string:
+	// 7. CLASS0
+	ret = knot_rrclass_to_string(0, name, BUF_LEN);
+	cmp_ok(ret, "!=", -1, "get CLASS0 ret");
+	ok(strcmp(name, "CLASS0") == 0, "get CLASS0 name");
+
+	// 8. IN
+	ret = knot_rrclass_to_string(1, name, BUF_LEN);
+	cmp_ok(ret, "!=", -1, "get IN ret");
+	ok(strcmp(name, "IN") == 0, "get IN name");
+
+	// 9. ANY
+	ret = knot_rrclass_to_string(255, name, BUF_LEN);
+	cmp_ok(ret, "!=", -1, "get ANY ret");
+	ok(strcmp(name, "ANY") == 0, "get ANY name");
+
+	// 10. CLASS65535
+	ret = knot_rrclass_to_string(65535, name, BUF_LEN);
+	cmp_ok(ret, "!=", -1, "get CLASS65535 ret");
+	ok(strcmp(name, "CLASS65535") == 0, "get CLASS65535 name");
+
+	// String to type num:
+	// 11. A
+	ret = knot_rrtype_from_string("A", &num);
+	cmp_ok(ret, "!=", -1, "get A num ret");
+	cmp_ok(num, "==", 1, "get A num");
+
+	// 12. a
+	ret = knot_rrtype_from_string("a", &num);
+	cmp_ok(ret, "!=", -1, "get a num ret");
+	cmp_ok(num, "==", 1, "get a num");
+
+	// 13. AaAa
+	ret = knot_rrtype_from_string("AaAa", &num);
+	cmp_ok(ret, "!=", -1, "get AaAa num ret");
+	cmp_ok(num, "==", 28, "get AaAa num");
+
+	// 14. ""
+	ret = knot_rrtype_from_string("", &num);
+	cmp_ok(ret, "==", -1, "get "" num ret");
+
+	// 15. DUMMY
+	ret = knot_rrtype_from_string("DUMMY", &num);
+	cmp_ok(ret, "==", -1, "get DUMMY num ret");
+
+	// 16. TypE33
+	ret = knot_rrtype_from_string("TypE33", &num);
+	cmp_ok(ret, "!=", -1, "get TypE33 num ret");
+	cmp_ok(num, "==", 33, "get TypE33 num");
+
+	// 17. TYPE
+	ret = knot_rrtype_from_string("TYPE", &num);
+	cmp_ok(ret, "==", -1, "get TYPE num ret");
+
+	// 18. TYPE0
+	ret = knot_rrtype_from_string("TYPE0", &num);
+	cmp_ok(ret, "!=", -1, "get TYPE0 num ret");
+	cmp_ok(num, "==", 0, "get TYPE0 num");
+
+	// 19. TYPE65535
+	ret = knot_rrtype_from_string("TYPE65535", &num);
+	cmp_ok(ret, "!=", -1, "get TYPE65535 num ret");
+	cmp_ok(num, "==", 65535, "get TYPE65535 num");
+
+	// 20. TYPE65536
+	ret = knot_rrtype_from_string("TYPE65536", &num);
+	cmp_ok(ret, "==", -1, "get TYPE65536 num ret");
+
+	// String to class num:
+	// 21. In
+	ret = knot_rrclass_from_string("In", &num);
+	cmp_ok(ret, "!=", -1, "get In num ret");
+	cmp_ok(num, "==", 1, "get In num");
+
+	// 22. ANY
+	ret = knot_rrclass_from_string("ANY", &num);
+	cmp_ok(ret, "!=", -1, "get ANY num ret");
+	cmp_ok(num, "==", 255, "get ANY num");
+
+	// 23. ""
+	ret = knot_rrclass_from_string("", &num);
+	cmp_ok(ret, "==", -1, "get "" num ret");
+
+	// 24. DUMMY
+	ret = knot_rrclass_from_string("DUMMY", &num);
+	cmp_ok(ret, "==", -1, "get DUMMY num ret");
+
+	// 25. CLass33
+	ret = knot_rrclass_from_string("CLass33", &num);
+	cmp_ok(ret, "!=", -1, "get CLass33 num ret");
+	cmp_ok(num, "==", 33, "get CLass33 num");
+
+	// 26. CLASS
+	ret = knot_rrclass_from_string("CLASS", &num);
+	cmp_ok(ret, "==", -1, "get CLASS num ret");
+
+	// 27. CLASS0
+	ret = knot_rrclass_from_string("CLASS0", &num);
+	cmp_ok(ret, "!=", -1, "get CLASS0 num ret");
+	cmp_ok(num, "==", 0, "get CLASS0 num");
+
+	// 28. CLASS65535
+	ret = knot_rrclass_from_string("CLASS65535", &num);
+	cmp_ok(ret, "!=", -1, "get CLASS65535 num ret");
+	cmp_ok(num, "==", 65535, "get CLASS65535 num");
+
+	// 29. CLASS65536
+	ret = knot_rrclass_from_string("CLASS65536", &num);
+	cmp_ok(ret, "==", -1, "get CLASS65536 num ret");
+
+	return 0;
+}
+
diff --git a/src/tests/common/descriptor_tests.h b/src/tests/common/descriptor_tests.h
new file mode 100644
index 000000000..7b7f861a9
--- /dev/null
+++ b/src/tests/common/descriptor_tests.h
@@ -0,0 +1,25 @@
+/*  Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_DESCRIPTOR_TESTS_H_
+#define _KNOTD_DESCRIPTOR_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api descriptor_tests_api;
+
+#endif /* _KNOTD_DESCRIPTOR_TESTS_H_ */
diff --git a/src/tests/unittests_main.c b/src/tests/unittests_main.c
index c4c220ffb..bd59ab969 100644
--- a/src/tests/unittests_main.c
+++ b/src/tests/unittests_main.c
@@ -26,6 +26,7 @@
 #include "tests/common/fdset_tests.h"
 #include "tests/common/base64_tests.h"
 #include "tests/common/base32hex_tests.h"
+#include "tests/common/descriptor_tests.h"
 #include "tests/knot/dthreads_tests.h"
 #include "tests/knot/journal_tests.h"
 #include "tests/knot/server_tests.h"
@@ -54,6 +55,7 @@ int main(int argc, char *argv[])
 	        &fdset_tests_api,	//! FDSET polling wrapper
 	        &base64_tests_api,	//! Base64 encoding
 	        &base32hex_tests_api,	//! Base32hex encoding
+	        &descriptor_tests_api,	//! RR descriptors
 
 	        /* Library. */
 	        &wire_tests_api,
-- 
GitLab