Browse Source

created toJSON functions (which are mostly the old str() ones, str() is now a general Element function that calls toJSON)
toWire now also simply calls toJSON(), so str() and toWire are the same for now (in the future we could add formatting to str version)
Added NullElement, and support for reading of exponent format
updated tests


git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac172@2110 e5f2f494-b856-4b98-b285-d166d9295462

Jelte Jansen 15 years ago
parent
commit
2568b6c2fa

+ 35 - 36
src/bin/bind10/bind10.py.in

@@ -272,42 +272,41 @@ class BoB:
         if self.verbose:
             sys.stdout.write("[bind10] ccsession started\n")
 
-## TODO: UNCOMMENT (commented out, doing json for python first)
-#        # start the xfrout before auth-server, to make sure every xfr-query can
-#        # be processed properly.
-#        xfrout_args = ['b10-xfrout']
-#        if self.verbose:
-#            sys.stdout.write("[bind10] Starting b10-xfrout\n")
-#            xfrout_args += ['-v']
-#        try:
-#            xfrout = ProcessInfo("b10-xfrout", xfrout_args, 
-#                                 c_channel_env )
-#        except Exception as e:
-#            c_channel.process.kill()
-#            bind_cfgd.process.kill()
-#            return "Unable to start b10-xfrout; " + str(e)
-#        self.processes[xfrout.pid] = xfrout
-#        if self.verbose:
-#            sys.stdout.write("[bind10] Started b10-xfrout (PID %d)\n" % xfrout.pid)
-#
-#        # start b10-auth
-#        # XXX: this must be read from the configuration manager in the future
-#        authargs = ['b10-auth', '-p', str(self.auth_port)]
-#        if self.verbose:
-#            sys.stdout.write("[bind10] Starting b10-auth using port %d\n" %
-#                             self.auth_port)
-#            authargs += ['-v']
-#        try:
-#            auth = ProcessInfo("b10-auth", authargs,
-#                               c_channel_env)
-#        except Exception as e:
-#            c_channel.process.kill()
-#            bind_cfgd.process.kill()
-#            xfrout.process.kill()
-#            return "Unable to start b10-auth; " + str(e)
-#        self.processes[auth.pid] = auth
-#        if self.verbose:
-#            sys.stdout.write("[bind10] Started b10-auth (PID %d)\n" % auth.pid)
+        # start the xfrout before auth-server, to make sure every xfr-query can
+        # be processed properly.
+        xfrout_args = ['b10-xfrout']
+        if self.verbose:
+            sys.stdout.write("[bind10] Starting b10-xfrout\n")
+            xfrout_args += ['-v']
+        try:
+            xfrout = ProcessInfo("b10-xfrout", xfrout_args, 
+                                 c_channel_env )
+        except Exception as e:
+            c_channel.process.kill()
+            bind_cfgd.process.kill()
+            return "Unable to start b10-xfrout; " + str(e)
+        self.processes[xfrout.pid] = xfrout
+        if self.verbose:
+            sys.stdout.write("[bind10] Started b10-xfrout (PID %d)\n" % xfrout.pid)
+
+        # start b10-auth
+        # XXX: this must be read from the configuration manager in the future
+        authargs = ['b10-auth', '-p', str(self.auth_port)]
+        if self.verbose:
+            sys.stdout.write("[bind10] Starting b10-auth using port %d\n" %
+                             self.auth_port)
+            authargs += ['-v']
+        try:
+            auth = ProcessInfo("b10-auth", authargs,
+                               c_channel_env)
+        except Exception as e:
+            c_channel.process.kill()
+            bind_cfgd.process.kill()
+            xfrout.process.kill()
+            return "Unable to start b10-auth; " + str(e)
+        self.processes[auth.pid] = auth
+        if self.verbose:
+            sys.stdout.write("[bind10] Started b10-auth (PID %d)\n" % auth.pid)
 
         # start b10-xfrin
         xfrin_args = ['b10-xfrin']

+ 143 - 360
src/lib/cc/data.cc

@@ -50,6 +50,28 @@ const unsigned char ITEM_LENGTH_MASK = 0x30;
 namespace isc {
 namespace data {
 
+std::string
+Element::str()
+{
+    std::stringstream ss;
+    toJSON(ss);
+    return ss.str();
+}
+
+std::string
+Element::toWire()
+{
+    std::stringstream ss;
+    toJSON(ss);
+    return ss.str();
+}
+
+void
+Element::toWire(std::stringstream& ss)
+{
+    toJSON(ss);
+}
+
 //
 // The following methods are effectively empty, and their parameters are
 // unused.  To silence compilers that warn unused function parameters,
@@ -203,6 +225,11 @@ bool operator==(const isc::data::ElementPtr a, const isc::data::ElementPtr b) {
 // factory functions
 //
 ElementPtr
+Element::create() {
+    return ElementPtr(new NullElement());
+}
+
+ElementPtr
 Element::create(const int i) {
     return ElementPtr(new IntElement(i));
 }
@@ -306,6 +333,8 @@ skip_to(std::istream &in, const std::string& file, int& line,
     throwParseError(std::string("EOF read, one of \"") + chars + "\" expected", file, line, pos);
 }
 
+// TODO: Should we check for all other official escapes here (and
+// error on the rest)?
 std::string
 str_from_stringstream(std::istream &in, const std::string& file, const int line,
                       int& pos) throw (ParseError)
@@ -352,26 +381,57 @@ count_chars_i(int i) {
     return result;
 }
 
-inline int
-count_chars_d(double d) {
-    int result = 1;
-    while (d < 1.0) {
-        ++result;
-        d = d * 10;
-    }
-    return result;
-}
-
+// TODO: range checks
 ElementPtr
-from_stringstream_int_or_double(std::istream &in, int &pos) {
-    int i;
+from_stringstream_number(std::istream &in, int &pos) {
+    int i, d_i;
+    double d = 0.0;
+    bool is_double = false;
+
     in >> i;
     pos += count_chars_i(i);
     if (in.peek() == '.') {
-        double d;
-        in >> d;
-        pos += count_chars_d(i);
-        d += i;
+        is_double = true;
+        in.get();
+        pos++;
+        in >> d_i;
+        d = i + (double)d_i / 10;
+        pos += count_chars_i(d_i);
+    }
+    if (in.peek() == 'e' || in.peek() == 'E') {
+        int e;
+        in.get();
+        pos++;
+        in >> e;
+        pos += count_chars_i(e);
+        if (e == 0) {
+            d = 1;
+            i = 1;
+        } else if (e < 0) {
+            if (!is_double) {
+                is_double = true;
+                d = i;
+            }
+            while (e < 0) {
+                d = d / 10;
+                e++;
+            }
+        } else {
+            if (is_double) {
+                while (e > 0) {
+                    d = d * 10;
+                    e--;
+                }
+            } else {
+                while (e > 0) {
+                    i = i * 10;
+                    e--;
+                }
+            }
+        }
+    }
+
+    if (is_double) {
         return Element::create(d);
     } else {
         return Element::create(i);
@@ -395,6 +455,19 @@ from_stringstream_bool(std::istream &in, const std::string& file,
 }
 
 ElementPtr
+from_stringstream_null(std::istream &in, const std::string& file,
+                       const int line, int& pos)
+{
+    const std::string word = word_from_stringstream(in, pos);
+    if (boost::iequals(word, "null")) {
+        return Element::create();
+    } else {
+        throwParseError(std::string("Bad null value: ") + word, file, line, pos);
+        return ElementPtr();
+    }
+}
+
+ElementPtr
 from_stringstream_string(std::istream& in, const std::string& file, int& line, int& pos)
 {
     return Element::create(str_from_stringstream(in, file, line, pos));
@@ -491,7 +564,7 @@ Element::createFromString(std::istream &in, const std::string& file, int& line,
             case '9':
             case '0':
                 in.putback(c);
-                element = from_stringstream_int_or_double(in, pos);
+                element = from_stringstream_number(in, pos);
                 el_read = true;
                 break;
             case 't':
@@ -502,6 +575,11 @@ Element::createFromString(std::istream &in, const std::string& file, int& line,
                 element = from_stringstream_bool(in, file, line, pos);
                 el_read = true;
                 break;
+            case 'n':
+                in.putback(c);
+                element = from_stringstream_null(in, file, line, pos);
+                el_read = true;
+                break;
             case '"':
                 in.putback('"');
                 element = from_stringstream_string(in, file, line, pos);
@@ -536,44 +614,47 @@ Element::createFromString(const std::string &in) {
     return createFromString(ss, "<string>");
 }
 
-//
-// a general to_str() function
-//
-std::string
-IntElement::str() {
-    std::stringstream ss;
+// to JSON format
+
+void
+IntElement::toJSON(std::stringstream& ss)
+{
     ss << intValue();
-    return ss.str();
 }
 
-std::string
-DoubleElement::str() {
-    std::stringstream ss;
+void
+DoubleElement::toJSON(std::stringstream& ss)
+{
     ss << doubleValue();
-    return ss.str();
 }
 
-std::string
-BoolElement::str() {
+void
+BoolElement::toJSON(std::stringstream& ss)
+{
     if (b) {
-        return "True";
+        ss << "true";
     } else {
-        return "False";
+        ss << "false";
     }
 }
 
-std::string
-StringElement::str() {
-    std::stringstream ss;
+void
+NullElement::toJSON(std::stringstream& ss)
+{
+    ss << "null";
+}
+
+void
+StringElement::toJSON(std::stringstream& ss)
+{
     ss << "\"";
     ss << stringValue();
     ss << "\"";
-    return ss.str();
 }
 
-std::string
-ListElement::str() {
-    std::stringstream ss;
+void
+ListElement::toJSON(std::stringstream& ss)
+{
     ss << "[ ";
 
     const std::vector<ElementPtr>& v = listValue();
@@ -582,16 +663,15 @@ ListElement::str() {
         if (it != v.begin()) {
             ss << ", ";
         }
-        ss << (*it)->str();
+        (*it)->toJSON(ss);
     }
     ss << " ]";
-    return ss.str();
 }
 
-std::string
-MapElement::str() {
-    std::stringstream ss;
-    ss << "{";
+void
+MapElement::toJSON(std::stringstream& ss)
+{
+    ss << "{ ";
 
     const std::map<std::string, ElementPtr>& m = mapValue();
     for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
@@ -601,13 +681,12 @@ MapElement::str() {
         }
         ss << "\"" << (*it).first << "\": ";
         if ((*it).second) {
-            ss << (*it).second->str();
+            (*it).second->toJSON(ss);
         } else {
             ss << "None";
         }
     }
-    ss << "}";
-    return ss.str();
+    ss << " }";
 }
 
 // throws when one of the types in the path (except the one
@@ -634,169 +713,12 @@ MapElement::find(const std::string& id) {
     }
 }
 
-//
-// Decode from wire format.
-//
-namespace {
-ElementPtr decode_element(std::stringstream& in, int& in_length);
-
-unsigned char
-get_byte(std::stringstream& in) {
-    const int c = in.get();
-    if (c == EOF) {
-        throw DecodeError("End of data while decoding wire format message");
-    }
-
-    return c;
-}
-
-std::string
-decode_tag(std::stringstream& in, int& item_length) {
-    char buf[256];
-
-    const int len = get_byte(in);
-    item_length--;
-
-    in.read(buf, len);
-    if (in.fail()) {
-        throw DecodeError();
-    }
-    buf[len] = 0;
-    item_length -= len;
-
-    return std::string(buf, len);
-}
-
-ElementPtr
-decode_bool(std::stringstream& in) {
-    const char c = in.get();
-    
-    if (c == '1') {
-        return Element::create(true);
-    } else {
-        return Element::create(false);
-    }
-}
-
-ElementPtr
-decode_int(std::stringstream& in) {
-    int me;
-    return from_stringstream_int_or_double(in, me);
-}
-
-ElementPtr
-decode_real(std::stringstream& in) {
-    int me;
-    return from_stringstream_int_or_double(in, me);
-}
-
-ElementPtr
-decode_blob(std::stringstream& in, const int item_length) {
-    vector<char> buf(item_length + 1);
-
-    in.read(&buf[0], item_length);
-    if (in.fail()) {
-        throw DecodeError();
-    }
-    buf[item_length] = 0;
-
-    return Element::create(std::string(&buf[0], item_length));
-}
-
-ElementPtr
-decode_hash(std::stringstream& in, int item_length) {
-    std::map<std::string, ElementPtr> m;
-    std::pair<std::string, ElementPtr> p;
-
-    while (item_length > 0) {
-        p.first = decode_tag(in, item_length);
-        p.second = decode_element(in, item_length);
-        m.insert(p);
-    }
-
-    return Element::create(m);
-}
-
-ElementPtr
-decode_list(std::stringstream& in, int item_length) {
-    std::vector<ElementPtr> v;
-
-    while (item_length > 0) {
-        v.push_back(decode_element(in, item_length));
-    }
-    return Element::create(v);
-}
-
-ElementPtr
-decode_null() {
-    return Element::create("NULL");
-}
-
-ElementPtr
-decode_element(std::stringstream& in, int& in_length) {
-    ElementPtr element;
-
-    const unsigned char type_and_length = get_byte(in);
-    const unsigned char type = type_and_length & ITEM_MASK;
-    const unsigned char lenbytes = type_and_length & ITEM_LENGTH_MASK;
-    in_length--;
-
-    int item_length = 0;
-    switch (lenbytes) {
-    case ITEM_LENGTH_32:
-        item_length |= get_byte(in);
-        item_length <<= 8;
-        item_length |= get_byte(in);
-        item_length <<= 8;
-        in_length -= 2;  // only 2 here, we will get more later
-    case ITEM_LENGTH_16:
-        item_length |= get_byte(in);
-        item_length <<= 8;
-        in_length--;  // only 1 here
-    case ITEM_LENGTH_8:
-        item_length |= get_byte(in);
-        in_length--;
-    }
-
-    in_length -= item_length;
-
-    switch (type) {
-    case ITEM_BOOL:
-        element = decode_bool(in);
-        break;
-    case ITEM_INT:
-        element = decode_int(in);
-        break;
-    case ITEM_REAL:
-        element = decode_real(in);
-        break;
-    case ITEM_BLOB:
-        element = decode_blob(in, item_length);
-        break;
-    case ITEM_UTF8:
-        // XXXMLG currently identical to decode_blob
-        element = decode_blob(in, item_length);
-        break;
-    case ITEM_HASH:
-        element = decode_hash(in, item_length);
-        break;
-    case ITEM_LIST:
-        element = decode_list(in, item_length);
-        break;
-    case ITEM_NULL:
-        element = decode_null();
-        break;
-    }
-
-    return (element);
-}
-}
-
 ElementPtr
 Element::fromWire(const std::string& s) {
     std::stringstream ss;
     ss << s;
-    return fromWire(ss, s.length());
+    int line = 0, pos = 0;
+    return createFromString(ss, "<wire>", line, pos);
 }
 
 ElementPtr
@@ -804,159 +726,15 @@ Element::fromWire(std::stringstream& in, int length) {
     //
     // Check protocol version
     //
-    for (int i = 0 ; i < 4 ; ++i) {
-        const unsigned char version_byte = get_byte(in);
-        if (PROTOCOL_VERSION[i] != version_byte) {
-            throw DecodeError("Protocol version incorrect");
-        }
-    }
-    length -= 4;
-
-    return (decode_hash(in, length));
-}
-
-//
-// Encode into wire format.
-//
-
-std::string
-encode_length(const unsigned int length, unsigned char type) {
-    std::stringstream ss;
-
-    if (length <= 0x000000ff) {
-        const unsigned char val = (length & 0x000000ff);
-        type |= ITEM_LENGTH_8;
-        ss << type << val;
-    } else if (length <= 0x0000ffff) {
-        unsigned char val[2];
-        val[0] = (length & 0x0000ff00) >> 8;
-        val[1] = (length & 0x000000ff);
-        type |= ITEM_LENGTH_16;
-        ss << type << val[0] << val[1];
-    } else {
-        unsigned char val[4];
-        val[0] = (length & 0xff000000) >> 24;
-        val[1] = (length & 0x00ff0000) >> 16;
-        val[2] = (length & 0x0000ff00) >> 8;
-        val[3] = (length & 0x000000ff);
-        type |= ITEM_LENGTH_32;
-        ss << type << val[0] << val[1] << val[2] << val[3];
-    }
-    return ss.str();
-}
-
-std::string
-Element::toWire(const int omit_length) {
-    std::stringstream ss;
-    toWire(ss, omit_length);
-    return ss.str();
-}
-
-void
-StringElement::toWire(std::stringstream& ss,
-                      const int omit_length UNUSED_PARAM)
-{
-    unsigned int length = stringValue().length();
-    ss << encode_length(length, ITEM_UTF8) << stringValue();
-}
-
-void
-IntElement::toWire(std::stringstream& ss,
-                   const int omit_length UNUSED_PARAM)
-{
-    const std::string& s = str();
-    ss << encode_length(s.length(), ITEM_INT) << s;
-}
-
-void
-BoolElement::toWire(std::stringstream& ss,
-                    const int omit_length UNUSED_PARAM)
-{
-    ss << encode_length(1, ITEM_BOOL);
-    if (boolValue()) {
-        ss << '1';
-    } else {
-        ss << '0';
-    }
-}
-
-void
-DoubleElement::toWire(std::stringstream& ss,
-                      const int omit_length UNUSED_PARAM)
-{
-    std::stringstream text;
-
-    text << str();
-    const int length = text.str().length();
-    ss << encode_length(length, ITEM_REAL) << text.str();
-}
-
-void
-ListElement::toWire(std::stringstream& ss, const int omit_length) {
-    std::stringstream ss2;
-    const std::vector<ElementPtr>& v = listValue();
-    for (std::vector<ElementPtr>::const_iterator it = v.begin() ;
-         it != v.end() ; ++it) {
-        (*it)->toWire(ss2, 0);
-    }
-
-
-    if (omit_length) {
-        stringbuf *ss2_buf = ss2.rdbuf();
-        ss2_buf->pubseekpos(0);
-        if (ss2_buf->in_avail() > 0) {
-            ss << ss2_buf;
-        }
-    } else {
-        stringbuf *ss2_buf = ss2.rdbuf();
-        ss2_buf->pubseekpos(0);
-        ss << encode_length(ss2_buf->in_avail(), ITEM_LIST);
-        if (ss2_buf->in_avail() > 0) {
-            ss << ss2_buf;
-        }
-    }
-}
-
-void
-MapElement::toWire(std::stringstream& ss, int omit_length) {
-    std::stringstream ss2;
-
-    //
-    // If we don't want the length, we will want the protocol header
-    //
-    if (omit_length) {
-        ss2 << PROTOCOL_VERSION[0] << PROTOCOL_VERSION[1];
-        ss2 << PROTOCOL_VERSION[2] << PROTOCOL_VERSION[3];
-    }
-
-    const std::map<std::string, ElementPtr>& m = mapValue();
-    for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
-         it != m.end(); ++it) {
-        const size_t taglen = (*it).first.length();
-        assert(taglen <= 0xff);
-        const unsigned char val = (taglen & 0x000000ff);
-        ss2 << val << (*it).first;
-
-        (*it).second->toWire(ss2, 0);
-    }
-
-    //
-    // add length if needed
-    //
-    if (omit_length) {
-        stringbuf *ss2_buf = ss2.rdbuf();
-        ss2_buf->pubseekpos(0);
-        if (ss2_buf->in_avail()) {
-            ss << ss2_buf;
-        }
-    } else {
-        stringbuf *ss2_buf = ss2.rdbuf();
-        ss2_buf->pubseekpos(0);
-        ss << encode_length(ss2_buf->in_avail(), ITEM_HASH);
-        if (ss2_buf->in_avail()) {
-            ss << ss2_buf;
-        }
-    }
+    //for (int i = 0 ; i < 4 ; ++i) {
+    //    const unsigned char version_byte = get_byte(in);
+    //    if (PROTOCOL_VERSION[i] != version_byte) {
+    //        throw DecodeError("Protocol version incorrect");
+    //    }
+    //}
+    //length -= 4;
+    int line = 0, pos = 0;
+    return createFromString(in, "<wire>", line, pos);
 }
 
 bool
@@ -992,6 +770,11 @@ BoolElement::equals(ElementPtr other) {
 }
 
 bool
+NullElement::equals(ElementPtr other) {
+    return other->getType() == Element::null;
+}
+
+bool
 StringElement::equals(ElementPtr other) {
     return (other->getType() == Element::string) &&
            (s == other->stringValue());

+ 22 - 21
src/lib/cc/data.h

@@ -97,7 +97,7 @@ protected:
 public:
     // any is a special type used in list specifications, specifying
     // that the elements can be of any type
-    enum types { integer, real, boolean, string, list, map, any };
+    enum types { integer, real, boolean, null, string, list, map, any };
     // base class; make dtor virtual
     virtual ~Element() {};
 
@@ -110,6 +110,8 @@ public:
     
     // pure virtuals, every derived class must implement these
 
+    virtual void toJSON(std::stringstream& ss) = 0;
+
     /// Returns a string representing the Element and all its
     /// child elements; note that this is different from stringValue(),
     /// which only returns the single value of a StringElement
@@ -118,7 +120,7 @@ public:
     /// All other elements will be represented directly
     ///
     /// \return std::string containing the string representation
-    virtual std::string str() = 0;
+    std::string str();
 
     /// Returns the wireformat for the Element and all its child
     /// elements.
@@ -126,8 +128,8 @@ public:
     /// \param omit_length If this is non-zero, the item length will
     ///        be omitted from the wire format
     /// \return std::string containing the element in wire format
-    std::string toWire(int omit_length = 1);
-    virtual void toWire(std::stringstream& out, int omit_length = 1) = 0;
+    std::string toWire();
+    void toWire(std::stringstream& out);
 
     /// \name Type-specific getters
     ///
@@ -260,7 +262,10 @@ public:
     /// If there is a memory allocation problem, these functions will
     /// return a NULL ElementPtr, which can be checked with
     /// Element::is_null(ElementPtr ep).
+    /// (Note that that is different from an NullElement, which
+    /// represents an empty value, and is created with Element::create())
     //@{
+    static ElementPtr create();
     static ElementPtr create(const int i);
     static ElementPtr create(const double d);
     static ElementPtr create(const bool b);
@@ -334,8 +339,7 @@ public:
     bool getValue(int& t) { t = i; return true; };
     using Element::setValue;
     bool setValue(const int v) { i = v; return true; };
-    std::string str();
-    void toWire(std::stringstream& ss, int omit_length = 1);
+    void toJSON(std::stringstream& ss);
     bool equals(ElementPtr other);
 };
 
@@ -349,8 +353,7 @@ public:
     bool getValue(double& t) { t = d; return true; };
     using Element::setValue;
     bool setValue(const double v) { d = v; return true; };
-    std::string str();
-    void toWire(std::stringstream& ss, int omit_length = 1);
+    void toJSON(std::stringstream& ss);
     bool equals(ElementPtr other);
 };
 
@@ -364,8 +367,14 @@ public:
     bool getValue(bool& t) { t = b; return true; };
     using Element::setValue;
     bool setValue(const bool v) { b = v; return true; };
-    std::string str();
-    void toWire(std::stringstream& ss, int omit_length = 1);
+    void toJSON(std::stringstream& ss);
+    bool equals(ElementPtr other);
+};
+
+class NullElement : public Element {
+public:
+    NullElement() : Element(null) {};
+    void toJSON(std::stringstream& ss);
     bool equals(ElementPtr other);
 };
 
@@ -379,8 +388,7 @@ public:
     bool getValue(std::string& t) { t = s; return true; };
     using Element::setValue;
     bool setValue(const std::string& v) { s = v; return true; };
-    std::string str();
-    void toWire(std::stringstream& ss, int omit_length = 1);
+    void toJSON(std::stringstream& ss);
     bool equals(ElementPtr other);
 };
 
@@ -401,8 +409,7 @@ public:
     void add(ElementPtr e) { l.push_back(e); };
     using Element::remove;
     void remove(int i) { l.erase(l.begin() + i); };
-    std::string str();
-    void toWire(std::stringstream& ss, int omit_length = 1);
+    void toJSON(std::stringstream& ss);
     size_t size() { return l.size(); }
     bool equals(ElementPtr other);
 };
@@ -424,14 +431,8 @@ public:
     using Element::remove;
     void remove(const std::string& s) { m.erase(s); }
     bool contains(const std::string& s) { return m.find(s) != m.end(); }
-    std::string str();
-    void toWire(std::stringstream& ss, int omit_length = 1);
+    void toJSON(std::stringstream& ss);
     
-    //
-    // Encode into the CC wire format.
-    //
-    void toWire(std::ostream& ss);
-
     // we should name the two finds better...
     // find the element at id; raises TypeError if one of the
     // elements at path except the one we're looking for is not a

+ 27 - 81
src/lib/cc/data_unittests.cc

@@ -56,12 +56,13 @@ TEST(Element, from_and_to_str) {
 
     sv.push_back("12");
     sv.push_back("1.1");
-    sv.push_back("True");
-    sv.push_back("False");
+    sv.push_back("true");
+    sv.push_back("false");
     sv.push_back("\"asdf\"");
+    sv.push_back("null");
     sv.push_back("[ 1, 2, 3, 4 ]");
-    sv.push_back("{\"name\": \"foo\", \"value\": 47806}");
-    sv.push_back("[ {\"a\": 1, \"b\": \"c\"}, {\"a\": 2, \"b\": \"d\"} ]");
+    sv.push_back("{ \"name\": \"foo\", \"value\": 47806 }");
+    sv.push_back("[ { \"a\": 1, \"b\": \"c\" }, { \"a\": 2, \"b\": \"d\" } ]");
 
     BOOST_FOREACH(std::string s, sv) {
         // also test << operator, which uses Element::str()
@@ -93,6 +94,16 @@ TEST(Element, from_and_to_str) {
         EXPECT_THROW(el = Element::createFromString(s), isc::data::ParseError);
     }
 
+    // some json specific format tests, here the str() output is
+    // different from the string input
+    EXPECT_EQ("100", Element::createFromString("1e2")->str());
+    EXPECT_EQ("0.01", Element::createFromString("1e-2")->str());
+    EXPECT_EQ("1.2", Element::createFromString("1.2")->str());
+    EXPECT_EQ("1", Element::createFromString("1.0")->str());
+    EXPECT_EQ("120", Element::createFromString("1.2e2")->str());
+    EXPECT_EQ("100", Element::createFromString("1.0e2")->str());
+    EXPECT_EQ("0.01", Element::createFromString("1.0e-2")->str());
+    EXPECT_EQ("0.012", Element::createFromString("1.2e-2")->str());
 }
 
 TEST(Element, create_and_value_throws) {
@@ -233,83 +244,18 @@ TEST(Element, MapElement) {
 }
 
 TEST(Element, to_and_from_wire) {
-    ElementPtr el, decoded_el;
-    std::string wire;
-    std::vector<std::string> sv;
-    std::vector<std::string> sw;
-    std::stringstream bigstring, bigstring2;
-    std::stringstream bigwire, bigwire2;
-
-    sv.push_back("{\"name\": \"foo\"}");
-    sw.push_back("Skan\004name\050\003foo");
-    sv.push_back("{\"value2\": {\"number\": 42}}");
-    sw.push_back("Skan\006value2\042\013\006number\046\00242");
-    sv.push_back("{\"bool\": False, \"bool2\": True, \"real\": 2.34, \"string\": \"foo\"}");
-    sw.push_back("Skan\004bool\045\0010\005bool2\045\0011\004real\047\0042\05634\006string\050\003foo");
-    sv.push_back("{\"list\": [ 1, 2, 3, 4 ]}");
-    sw.push_back("Skan\004list\043\014\046\0011\046\0012\046\0013\046\0014");
-
-    // some big ones
-
-    bigstring << "{\"bigstring\": \"";
-    bigwire << "Skan\011bigstring\030\001\001";
-    for (size_t i = 0; i < 257; i++) {
-        bigstring << "x";
-        bigwire << "x";
-    }
-    bigstring << "\"}";
-    sv.push_back(bigstring.str());
-    sw.push_back(bigwire.str());
-
-
-    bigstring2 << "{\"bigstring2\": \"";
-    bigwire2 << "Skan\012bigstring2\010";
-    bigwire2 << '\000' << '\001' << '\000' << '\001';
-    for (size_t i = 0; i < 65537; i++) {
-        bigstring2 << "x";
-        bigwire2 << "x";
-    }
-    bigstring2 << "\"}";
-    sv.push_back(bigstring2.str());
-    sw.push_back(bigwire2.str());
-
-
-    BOOST_FOREACH(std::string s, sv) {
-        // also test << operator, which uses Element::str()
-        el = Element::createFromString(s);
-        EXPECT_EQ(s, el->str());
-        wire = el->toWire();
-        /*
-        std::cout << "Encoded wire format:" << std::endl;
-        my_print(wire);
-        std::cout << "Expecting:" << std::endl;
-        my_print(sw.at(0));
-        */
-        EXPECT_EQ(sw.at(0), wire);
-        sw.erase(sw.begin());
-        decoded_el = Element::fromWire(wire);
-        EXPECT_EQ(s, decoded_el->str());
-    }
-    
-    //EXPECT_THROW(Element::fromWire("Skan\004name\050\003foo"), DecodeError);
-    EXPECT_THROW(Element::fromWire("Skan\004name\050"), DecodeError);
-    EXPECT_THROW(Element::fromWire("Skan\004na"), DecodeError);
-    EXPECT_THROW(Element::fromWire("Skan\004name\050\003fo"), DecodeError);
-    EXPECT_NO_THROW(Element::fromWire("Skan\004name\041\003foo"));
-    EXPECT_THROW(Element::fromWire("Skan\004name\041\003fo"), DecodeError);
-    EXPECT_NO_THROW(Element::fromWire("Skan\004name\044\001a"));
-    EXPECT_THROW(Element::fromWire("Skab\004name\050\003foo"), DecodeError);
-
-    //EXPECT_EQ("\047\0031.2", Element::create(1.2)->toWire(0));
-    EXPECT_EQ("\046\0011", Element::createFromString("[ 1 ]")->toWire(1));
-
-    std::string ddef = "{\"data_specification\": {\"config_data\": [ {\"item_default\": \"Hello, world!\", \"item_name\": \"default_name\", \"item_optional\": False, \"item_type\": \"string\"}, {\"item_default\": [  ], \"item_name\": \"zone_list\", \"item_optional\": False, \"item_type\": \"list\", \"list_item_spec\": {\"item_name\": \"zone_name\", \"item_optional\": True, \"item_type\": \"string\"}} ], \"module_name\": \"Auth\"}}";
-    //std::string ddef = "{\"aaa\": 123, \"test\": [  ], \"zzz\": 123}";
-    ElementPtr ddef_el = Element::createFromString(ddef);
-    std::string ddef_wire = ddef_el->toWire();
-    ElementPtr ddef_el2 = Element::fromWire(ddef_wire);
-    std::string ddef2 = ddef_el2->str();
-    EXPECT_EQ(ddef, ddef2);
+    // Wire format is now plain JSON.
+    ElementPtr el;
+    EXPECT_EQ("1", Element::create(1)->toWire());
+    EXPECT_EQ("1.1", Element::create(1.1)->toWire());
+    EXPECT_EQ("true", Element::create(true)->toWire());
+    EXPECT_EQ("false", Element::create(false)->toWire());
+    EXPECT_EQ("null", Element::create()->toWire());
+    EXPECT_EQ("\"a string\"", Element::create("a string")->toWire());
+    EXPECT_EQ("[ \"a\", \"list\" ]", Element::createFromString("[ \"a\", \"list\" ]")->toWire());
+    EXPECT_EQ("{ \"a\": \"map\" }", Element::createFromString("{ \"a\": \"map\" }")->toWire());
+
+    EXPECT_EQ("1", Element::fromWire("1")->str());
 }
 
 ElementPtr efs(const std::string& str) {

File diff suppressed because it is too large
+ 39 - 39
src/lib/config/tests/ccsession_unittests.cc


+ 18 - 18
src/lib/config/tests/config_data_unittests.cc

@@ -62,9 +62,9 @@ TEST(ConfigData, getValue) {
     EXPECT_EQ("b", cd.getValue(is_default, "value5")->get(1)->stringValue());
     EXPECT_EQ("b", cd.getValue(is_default, "value5/")->get(1)->stringValue());
     EXPECT_TRUE(is_default);
-    EXPECT_EQ("{}", cd.getValue("value6")->str());
-    EXPECT_EQ("{}", cd.getValue(is_default, "value6")->str());
-    EXPECT_EQ("{}", cd.getValue(is_default, "value6/")->str());
+    EXPECT_EQ("{  }", cd.getValue("value6")->str());
+    EXPECT_EQ("{  }", cd.getValue(is_default, "value6")->str());
+    EXPECT_EQ("{  }", cd.getValue(is_default, "value6/")->str());
     EXPECT_TRUE(is_default);
     EXPECT_EQ("[  ]", cd.getValue("value8")->str());
 
@@ -87,34 +87,34 @@ TEST(ConfigData, setLocalConfig) {
     ConfigData cd = ConfigData(spec2);
     bool is_default;
 
-    ElementPtr my_config = Element::createFromString("{\"item1\": 2}");
-    ElementPtr my_config2 = Element::createFromString("{\"item6\": { \"value1\": \"a\" } }");
+    ElementPtr my_config = Element::createFromString("{ \"item1\": 2 }");
+    ElementPtr my_config2 = Element::createFromString("{ \"item6\": { \"value1\": \"a\" } }");
 
-    EXPECT_EQ("{}", cd.getValue("item6")->str());
+    EXPECT_EQ("{  }", cd.getValue("item6")->str());
 
     cd.setLocalConfig(my_config);
     EXPECT_EQ(2, cd.getValue(is_default, "item1")->intValue());
     EXPECT_FALSE(is_default);
-    EXPECT_EQ("{}", cd.getValue("item6")->str());
+    EXPECT_EQ("{  }", cd.getValue("item6")->str());
     EXPECT_EQ(1.1, cd.getValue(is_default, "item2")->doubleValue());
     EXPECT_TRUE(is_default);
 
     cd.setLocalConfig(my_config2);
-    EXPECT_EQ("{\"value1\": \"a\"}", cd.getValue("item6")->str());
+    EXPECT_EQ("{ \"value1\": \"a\" }", cd.getValue("item6")->str());
 }
 
 TEST(ConfigData, getLocalConfig) {
     ModuleSpec spec2 = moduleSpecFromFile(std::string(TEST_DATA_PATH) + "/spec2.spec");
     ConfigData cd = ConfigData(spec2);
-    EXPECT_EQ("{}", cd.getLocalConfig()->str());
+    EXPECT_EQ("{  }", cd.getLocalConfig()->str());
     
-    ElementPtr my_config = Element::createFromString("{\"item1\": 2}");
+    ElementPtr my_config = Element::createFromString("{ \"item1\": 2 }");
     cd.setLocalConfig(my_config);
-    EXPECT_EQ("{\"item1\": 2}", cd.getLocalConfig()->str());
+    EXPECT_EQ("{ \"item1\": 2 }", cd.getLocalConfig()->str());
 
-    ElementPtr my_config2 = Element::createFromString("{\"item6\": { \"value1\": \"a\" } }");
+    ElementPtr my_config2 = Element::createFromString("{ \"item6\": { \"value1\": \"a\" } }");
     cd.setLocalConfig(my_config2);
-    EXPECT_EQ("{\"item6\": {\"value1\": \"a\"}}", cd.getLocalConfig()->str());
+    EXPECT_EQ("{ \"item6\": { \"value1\": \"a\" } }", cd.getLocalConfig()->str());
 }
 
 TEST(ConfigData, getItemList) {
@@ -130,12 +130,12 @@ TEST(ConfigData, getFullConfig) {
     ModuleSpec spec2 = moduleSpecFromFile(std::string(TEST_DATA_PATH) + "/spec2.spec");
     ConfigData cd = ConfigData(spec2);
 
-    EXPECT_EQ("{\"item1\": 1, \"item2\": 1.1, \"item3\": True, \"item4\": \"test\", \"item5/\": [ \"a\", \"b\" ], \"item6/value1\": \"default\", \"item6/value2\": None}", cd.getFullConfig()->str());
-    ElementPtr my_config = Element::createFromString("{\"item1\": 2}");
+    EXPECT_EQ("{ \"item1\": 1, \"item2\": 1.1, \"item3\": true, \"item4\": \"test\", \"item5/\": [ \"a\", \"b\" ], \"item6/value1\": \"default\", \"item6/value2\": None }", cd.getFullConfig()->str());
+    ElementPtr my_config = Element::createFromString("{ \"item1\": 2 }");
     cd.setLocalConfig(my_config);
-    EXPECT_EQ("{\"item1\": 2, \"item2\": 1.1, \"item3\": True, \"item4\": \"test\", \"item5/\": [ \"a\", \"b\" ], \"item6/value1\": \"default\", \"item6/value2\": None}", cd.getFullConfig()->str());
-    ElementPtr my_config2 = Element::createFromString("{\"item6\": { \"value1\": \"a\" } }");
+    EXPECT_EQ("{ \"item1\": 2, \"item2\": 1.1, \"item3\": true, \"item4\": \"test\", \"item5/\": [ \"a\", \"b\" ], \"item6/value1\": \"default\", \"item6/value2\": None }", cd.getFullConfig()->str());
+    ElementPtr my_config2 = Element::createFromString("{ \"item6\": { \"value1\": \"a\" } }");
     cd.setLocalConfig(my_config2);
-    EXPECT_EQ("{\"item1\": 1, \"item2\": 1.1, \"item3\": True, \"item4\": \"test\", \"item5/\": [ \"a\", \"b\" ], \"item6/value1\": \"a\", \"item6/value2\": None}", cd.getFullConfig()->str());
+    EXPECT_EQ("{ \"item1\": 1, \"item2\": 1.1, \"item3\": true, \"item4\": \"test\", \"item5/\": [ \"a\", \"b\" ], \"item6/value1\": \"a\", \"item6/value2\": None }", cd.getFullConfig()->str());
 }
 

+ 8 - 8
src/lib/config/tests/module_spec_unittests.cc

@@ -58,7 +58,7 @@ TEST(ModuleSpec, ReadingSpecfiles) {
                    ": No such file or directory");
 
     dd = moduleSpecFromFile(specfile("spec2.spec"));
-    EXPECT_EQ("[ {\"command_args\": [ {\"item_default\": \"\", \"item_name\": \"message\", \"item_optional\": False, \"item_type\": \"string\"} ], \"command_description\": \"Print the given message to stdout\", \"command_name\": \"print_message\"}, {\"command_args\": [  ], \"command_description\": \"Shut down BIND 10\", \"command_name\": \"shutdown\"} ]", dd.getCommandsSpec()->str());
+    EXPECT_EQ("[ { \"command_args\": [ { \"item_default\": \"\", \"item_name\": \"message\", \"item_optional\": false, \"item_type\": \"string\" } ], \"command_description\": \"Print the given message to stdout\", \"command_name\": \"print_message\" }, { \"command_args\": [  ], \"command_description\": \"Shut down BIND 10\", \"command_name\": \"shutdown\" } ]", dd.getCommandsSpec()->str());
     EXPECT_EQ("Spec2", dd.getModuleName());
     EXPECT_EQ("", dd.getModuleDescription());
 
@@ -82,13 +82,13 @@ TEST(ModuleSpec, ReadingSpecfiles) {
 
 TEST(ModuleSpec, SpecfileItems) {
     module_spec_error("spec3.spec",
-                   "item_name missing in {\"item_default\": 1, \"item_optional\": False, \"item_type\": \"integer\"}");
+                   "item_name missing in { \"item_default\": 1, \"item_optional\": false, \"item_type\": \"integer\" }");
     module_spec_error("spec4.spec",
-                   "item_type missing in {\"item_default\": 1, \"item_name\": \"item1\", \"item_optional\": False}");
+                   "item_type missing in { \"item_default\": 1, \"item_name\": \"item1\", \"item_optional\": false }");
     module_spec_error("spec5.spec",
-                   "item_optional missing in {\"item_default\": 1, \"item_name\": \"item1\", \"item_type\": \"integer\"}");
+                   "item_optional missing in { \"item_default\": 1, \"item_name\": \"item1\", \"item_type\": \"integer\" }");
     module_spec_error("spec6.spec",
-                   "item_default missing in {\"item_name\": \"item1\", \"item_optional\": False, \"item_type\": \"integer\"}");
+                   "item_default missing in { \"item_name\": \"item1\", \"item_optional\": false, \"item_type\": \"integer\" }");
     module_spec_error("spec9.spec",
                    "item_default not of type integer");
     module_spec_error("spec10.spec",
@@ -108,7 +108,7 @@ TEST(ModuleSpec, SpecfileItems) {
 TEST(ModuleSpec, SpecfileConfigData)
 {
     module_spec_error("spec7.spec",
-                   "module_name missing in {}");
+                   "module_name missing in {  }");
     module_spec_error("spec8.spec",
                    "No module_spec in specification");
     module_spec_error("spec16.spec",
@@ -120,9 +120,9 @@ TEST(ModuleSpec, SpecfileConfigData)
 TEST(ModuleSpec, SpecfileCommands)
 {
     module_spec_error("spec17.spec",
-                   "command_name missing in {\"command_args\": [ {\"item_default\": \"\", \"item_name\": \"message\", \"item_optional\": False, \"item_type\": \"string\"} ], \"command_description\": \"Print the given message to stdout\"}");
+                   "command_name missing in { \"command_args\": [ { \"item_default\": \"\", \"item_name\": \"message\", \"item_optional\": false, \"item_type\": \"string\" } ], \"command_description\": \"Print the given message to stdout\" }");
     module_spec_error("spec18.spec",
-                   "command_args missing in {\"command_description\": \"Print the given message to stdout\", \"command_name\": \"print_message\"}");
+                   "command_args missing in { \"command_description\": \"Print the given message to stdout\", \"command_name\": \"print_message\" }");
     module_spec_error("spec19.spec",
                    "command_args not of type list");
     module_spec_error("spec20.spec",