You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by cu...@apache.org on 2011/03/30 23:15:59 UTC

svn commit: r1087078 - in /avro/branches/branch-1.5: ./ lang/c++/ lang/c++/api/ lang/c++/impl/ lang/c++/impl/parsing/ lang/c++/jsonschemas/ lang/c++/parser/ lang/c++/test/

Author: cutting
Date: Wed Mar 30 21:15:58 2011
New Revision: 1087078

URL: http://svn.apache.org/viewvc?rev=1087078&view=rev
Log:
Merge 1083246, 1085921, 1086866, 1087076 from trunk to 1.5 branch.  Fixes: AVRO-781, AVRO-783, AVRO-789.

Added:
    avro/branches/branch-1.5/lang/c++/api/DataFile.hh
      - copied unchanged from r1086866, avro/trunk/lang/c++/api/DataFile.hh
    avro/branches/branch-1.5/lang/c++/api/Generic.hh
      - copied, changed from r1083246, avro/trunk/lang/c++/api/Generic.hh
    avro/branches/branch-1.5/lang/c++/api/Specific.hh
      - copied unchanged from r1085921, avro/trunk/lang/c++/api/Specific.hh
    avro/branches/branch-1.5/lang/c++/impl/DataFile.cc
      - copied unchanged from r1086866, avro/trunk/lang/c++/impl/DataFile.cc
    avro/branches/branch-1.5/lang/c++/impl/Generic.cc
      - copied, changed from r1083246, avro/trunk/lang/c++/impl/Generic.cc
    avro/branches/branch-1.5/lang/c++/impl/avrogencpp.cc
      - copied unchanged from r1085921, avro/trunk/lang/c++/impl/avrogencpp.cc
    avro/branches/branch-1.5/lang/c++/jsonschemas/union_array_union
      - copied unchanged from r1085921, avro/trunk/lang/c++/jsonschemas/union_array_union
    avro/branches/branch-1.5/lang/c++/jsonschemas/union_map_union
      - copied unchanged from r1085921, avro/trunk/lang/c++/jsonschemas/union_map_union
    avro/branches/branch-1.5/lang/c++/test/AvrogencppTests.cc
      - copied unchanged from r1085921, avro/trunk/lang/c++/test/AvrogencppTests.cc
    avro/branches/branch-1.5/lang/c++/test/DataFileTests.cc
      - copied unchanged from r1086866, avro/trunk/lang/c++/test/DataFileTests.cc
    avro/branches/branch-1.5/lang/c++/test/SpecificTests.cc
      - copied unchanged from r1085921, avro/trunk/lang/c++/test/SpecificTests.cc
Modified:
    avro/branches/branch-1.5/   (props changed)
    avro/branches/branch-1.5/CHANGES.txt
    avro/branches/branch-1.5/lang/c++/CMakeLists.txt
    avro/branches/branch-1.5/lang/c++/api/Stream.hh
    avro/branches/branch-1.5/lang/c++/build.sh
    avro/branches/branch-1.5/lang/c++/impl/FileStream.cc
    avro/branches/branch-1.5/lang/c++/impl/parsing/ResolvingDecoder.cc
    avro/branches/branch-1.5/lang/c++/impl/parsing/Symbol.hh
    avro/branches/branch-1.5/lang/c++/parser/AvroLex.ll
    avro/branches/branch-1.5/lang/c++/test/CodecTests.cc

Propchange: avro/branches/branch-1.5/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Wed Mar 30 21:15:58 2011
@@ -1 +1 @@
-/avro/trunk:1075938,1075993,1078917,1079055,1079060,1079063,1086727,1086730
+/avro/trunk:1075938,1075993,1078917,1079055,1079060,1079063,1083246,1085921,1086727,1086730,1086866,1087076

Modified: avro/branches/branch-1.5/CHANGES.txt
URL: http://svn.apache.org/viewvc/avro/branches/branch-1.5/CHANGES.txt?rev=1087078&r1=1087077&r2=1087078&view=diff
==============================================================================
--- avro/branches/branch-1.5/CHANGES.txt (original)
+++ avro/branches/branch-1.5/CHANGES.txt Wed Mar 30 21:15:58 2011
@@ -7,6 +7,12 @@ Avro 1.5.1 (unreleased)
     AVRO-785. Java: Squash a Velocity warning by upgrading to Velocity 1.7.
     (cutting)
 
+    AVRO-781. Generic data support in C++. (thiru)
+
+    AVRO-783. Specifc object support in C++. (thiru)
+
+    AVRO-789. Datafile support in C++. (thiru)
+
   BUG FIXES
 
     AVRO-786. Java: Fix equals() to work on objects containing maps. (cutting)

Modified: avro/branches/branch-1.5/lang/c++/CMakeLists.txt
URL: http://svn.apache.org/viewvc/avro/branches/branch-1.5/lang/c%2B%2B/CMakeLists.txt?rev=1087078&r1=1087077&r2=1087078&view=diff
==============================================================================
--- avro/branches/branch-1.5/lang/c++/CMakeLists.txt (original)
+++ avro/branches/branch-1.5/lang/c++/CMakeLists.txt Wed Mar 30 21:15:58 2011
@@ -34,15 +34,18 @@ set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${BU
 
 project (Avro-cpp)
 
-find_package (Boost 1.38 COMPONENTS regex filesystem system)
+find_package (Boost 1.38 COMPONENTS regex filesystem system program_options)
 
 include_directories (api ${BUILD_DIRECTORY})
-add_library (avrocpp SHARED impl/Compiler.cc
+
+add_library (avrocpp SHARED
         impl/Compiler.cc impl/CompilerNode.cc impl/Node.cc
         impl/NodeImpl.cc impl/Resolver.cc impl/ResolverSchema.cc impl/Schema.cc
         impl/Types.cc impl/Validator.cc impl/ValidSchema.cc impl/Zigzag.cc
         impl/BinaryEncoder.cc impl/BinaryDecoder.cc
         impl/Stream.cc impl/FileStream.cc
+        impl/Generic.cc
+        impl/DataFile.cc
         impl/parsing/Symbol.cc
         impl/parsing/ValidatingCodec.cc
         impl/parsing/JsonCodec.cc
@@ -80,13 +83,34 @@ add_custom_target (testgen2
 add_custom_command (OUTPUT ${BUILD_DIRECTORY}/AvroYacc.cc
     COMMAND bison --defines=AvroYacc.hh -o AvroYacc.cc ../parser/AvroYacc.yy
     WORKING_DIRECTORY ${BUILD_DIRECTORY})
+
 add_custom_command (OUTPUT ${BUILD_DIRECTORY}/AvroLex.cc
     COMMAND flex -oAvroLex.cc ../parser/AvroLex.ll
     WORKING_DIRECTORY ${BUILD_DIRECTORY})
     
+add_custom_target (bigrecord_hh
+    COMMAND avrogencpp -i jsonschemas/bigrecord
+        -o ${BUILD_DIRECTORY}/bigrecord.hh -n testgen
+    DEPENDS avrogencpp)
+
+add_custom_target (bigrecord2_hh
+    COMMAND avrogencpp -i jsonschemas/bigrecord2
+        -o ${BUILD_DIRECTORY}/bigrecord2.hh -n testgen2
+    DEPENDS avrogencpp)
+
+add_custom_target (union_array_union_hh
+    COMMAND avrogencpp -i jsonschemas/union_array_union
+        -o ${BUILD_DIRECTORY}/union_array_union.hh -n uau
+    DEPENDS avrogencpp)
+
+add_custom_target (union_map_union_hh
+    COMMAND avrogencpp -i jsonschemas/union_map_union
+        -o ${BUILD_DIRECTORY}/union_map_union.hh -n umu
+    DEPENDS avrogencpp)
+
 macro (test name)
     add_executable (${name} test/${name}.cc)
-    target_link_libraries (${name} avrocpp boost_regex-mt)
+    target_link_libraries (${name} avrocpp ${Boost_LIBRARIES})
 endmacro (test)
 
 test(buffertest)
@@ -98,9 +122,23 @@ target_link_libraries (CodecTests avrocp
 add_executable (StreamTests test/StreamTests.cc)
 target_link_libraries (StreamTests avrocpp ${Boost_LIBRARIES})
 
+add_executable (SpecificTests test/SpecificTests.cc)
+target_link_libraries (SpecificTests avrocpp ${Boost_LIBRARIES})
+
+add_executable (avrogencpp impl/avrogencpp.cc)
+target_link_libraries (avrogencpp avrocpp ${Boost_LIBRARIES})
+
 add_executable (testgentest test/testgen.cc)
 add_dependencies (testgentest testgen testgen2)
-target_link_libraries (testgentest avrocpp boost_regex-mt)
+target_link_libraries (testgentest avrocpp ${Boost_LIBRARIES})
+
+add_executable (AvrogencppTests test/AvrogencppTests.cc)
+add_dependencies (AvrogencppTests bigrecord_hh bigrecord2_hh
+    union_array_union_hh union_map_union_hh)
+target_link_libraries (AvrogencppTests avrocpp ${BOOST_LIBRARIES})
+
+add_executable (DataFileTests test/DataFileTests.cc)
+target_link_libraries (DataFileTests avrocpp ${Boost_LIBRARIES})
 
 include (InstallRequiredSystemLibraries)
 

Copied: avro/branches/branch-1.5/lang/c++/api/Generic.hh (from r1083246, avro/trunk/lang/c++/api/Generic.hh)
URL: http://svn.apache.org/viewvc/avro/branches/branch-1.5/lang/c%2B%2B/api/Generic.hh?p2=avro/branches/branch-1.5/lang/c%2B%2B/api/Generic.hh&p1=avro/trunk/lang/c%2B%2B/api/Generic.hh&r1=1083246&r2=1087078&rev=1087078&view=diff
==============================================================================
--- avro/trunk/lang/c++/api/Generic.hh (original)
+++ avro/branches/branch-1.5/lang/c++/api/Generic.hh Wed Mar 30 21:15:58 2011
@@ -23,8 +23,8 @@
 #include <map>
 #include <string>
 
-#include <boost/utility.hpp>
 #include <boost/any.hpp>
+#include <boost/utility.hpp>
 
 #include "Node.hh"
 #include "Types.hh"
@@ -237,6 +237,11 @@ public:
         const ValidSchema& readerSchema, const DecoderPtr& decoder);
 
     void read(GenericDatum& datum) const;
+
+    /**
+     * Reads a generic datum from the stream, using the given schema.
+     */
+    static void read(Decoder& d, GenericDatum& g, const ValidSchema& s);
 };
 
 
@@ -249,6 +254,24 @@ public:
     GenericWriter(const ValidSchema& s, const EncoderPtr& encoder);
 
     void write(const GenericDatum& datum) const;
+
+    /**
+     * Writes a generic datum on to the stream, using the given schema.
+     */
+    static void write(Encoder& e, const GenericDatum& g, const ValidSchema& s);
+};
+
+template <typename T> struct codec_traits;
+
+template <> struct codec_traits<std::pair<ValidSchema, GenericDatum> > {
+    static void encode(Encoder& e,
+        const std::pair<ValidSchema, GenericDatum>& p) {
+        GenericWriter::write(e, p.second, p.first);
+    }
+
+    static void decode(Decoder& d, std::pair<ValidSchema, GenericDatum>& p) {
+        GenericReader::read(d, p.second, p.first);
+    }
 };
 }   // namespace avro
 #endif

Modified: avro/branches/branch-1.5/lang/c++/api/Stream.hh
URL: http://svn.apache.org/viewvc/avro/branches/branch-1.5/lang/c%2B%2B/api/Stream.hh?rev=1087078&r1=1087077&r2=1087078&view=diff
==============================================================================
--- avro/branches/branch-1.5/lang/c++/api/Stream.hh (original)
+++ avro/branches/branch-1.5/lang/c++/api/Stream.hh Wed Mar 30 21:15:58 2011
@@ -136,6 +136,7 @@ struct StreamReader {
     const uint8_t* end_;
 
     StreamReader() : in_(0), next_(0), end_(0) { }
+    StreamReader(InputStream& in) : in_(0), next_(0), end_(0) { reset(in); }
 
     void reset(InputStream& is) {
         if (in_ != 0) {
@@ -209,6 +210,7 @@ struct StreamWriter {
     uint8_t* end_;
 
     StreamWriter() : out_(0), next_(0), end_(0) { }
+    StreamWriter(OutputStream& out) : out_(0), next_(0), end_(0) { reset(out); }
 
     void reset(OutputStream& os) {
         if (out_ != 0) {
@@ -260,6 +262,22 @@ struct StreamWriter {
         out_->flush();
     }
 };
+
+/**
+ * A convenience function to copy all the contents of an input stream into
+ * an output stream.
+ */
+inline void copy(InputStream& in, OutputStream& out)
+{
+    const uint8_t *p = 0;
+    size_t n = 0;
+    StreamWriter w(out);
+    while (in.next(&p, &n)) {
+        w.writeBytes(p, n);
+    }
+    w.flush();
+}
+
 }   // namespace avro
 #endif
 

Modified: avro/branches/branch-1.5/lang/c++/build.sh
URL: http://svn.apache.org/viewvc/avro/branches/branch-1.5/lang/c%2B%2B/build.sh?rev=1087078&r1=1087077&r2=1087078&view=diff
==============================================================================
--- avro/branches/branch-1.5/lang/c++/build.sh (original)
+++ avro/branches/branch-1.5/lang/c++/build.sh Wed Mar 30 21:15:58 2011
@@ -82,6 +82,9 @@ case "$target" in
     ./build/testgentest
     ./build/CodecTests
     ./build/StreamTests
+    ./build/SpecificTests
+    ./build/AvrogencppTests
+    ./build/DataFileTests
 	;;
 
     dist)

Modified: avro/branches/branch-1.5/lang/c++/impl/FileStream.cc
URL: http://svn.apache.org/viewvc/avro/branches/branch-1.5/lang/c%2B%2B/impl/FileStream.cc?rev=1087078&r1=1087077&r2=1087078&view=diff
==============================================================================
--- avro/branches/branch-1.5/lang/c++/impl/FileStream.cc (original)
+++ avro/branches/branch-1.5/lang/c++/impl/FileStream.cc Wed Mar 30 21:15:58 2011
@@ -113,16 +113,17 @@ class FileOutputStream : public OutputSt
     size_t available_;
     size_t byteCount_;
 
+    // Invaiant: byteCount_ == byteswritten + bufferSize_ - available_;
     bool next(uint8_t** data, size_t* len) {
         if (available_ == 0) {
             flush();
         }
         *data = next_;
         *len = available_;
-        byteCount_ += available_;
         next_ += available_;
         byteCount_ += available_;
         available_ = 0;
+        return true;
     }
 
     void backup(size_t len) {
@@ -150,7 +151,7 @@ public:
         buffer_(new uint8_t[bufferSize]),
         out_(::open(filename, O_WRONLY | O_CREAT | O_BINARY, 0644)),
         next_(buffer_),
-        available_(bufferSize_) { }
+        available_(bufferSize_), byteCount_(0) { }
 
     ~FileOutputStream() {
         if (out_ >= 0) {

Copied: avro/branches/branch-1.5/lang/c++/impl/Generic.cc (from r1083246, avro/trunk/lang/c++/impl/Generic.cc)
URL: http://svn.apache.org/viewvc/avro/branches/branch-1.5/lang/c%2B%2B/impl/Generic.cc?p2=avro/branches/branch-1.5/lang/c%2B%2B/impl/Generic.cc&p1=avro/trunk/lang/c%2B%2B/impl/Generic.cc&r1=1083246&r2=1087078&rev=1087078&view=diff
==============================================================================
--- avro/trunk/lang/c++/impl/Generic.cc (original)
+++ avro/branches/branch-1.5/lang/c++/impl/Generic.cc Wed Mar 30 21:15:58 2011
@@ -93,7 +93,8 @@ GenericRecord::GenericRecord(const NodeP
 }
 
 GenericReader::GenericReader(const ValidSchema& s, const DecoderPtr& decoder) :
-    schema_(s), isResolving_(false), decoder_(decoder)
+    schema_(s), isResolving_(dynamic_cast<ResolvingDecoder*>(&(*decoder)) != 0),
+    decoder_(decoder)
 {
 }
 
@@ -245,6 +246,11 @@ void GenericReader::read(GenericDatum& d
     }
 }
 
+void GenericReader::read(Decoder& d, GenericDatum& g, const ValidSchema& s)
+{
+    read(g, s.root(), d, dynamic_cast<ResolvingDecoder*>(&d) != 0);
+}
+
 static void typeMismatch(Type t, Type u)
 {
     throw Exception(boost::format("Type mismatch %1% v %2%") %
@@ -422,4 +428,10 @@ void GenericWriter::write(const GenericD
     }
 }
 
+void GenericWriter::write(Encoder& e, const GenericDatum& g,
+    const ValidSchema& s)
+{
+    write(g, s.root(), e);
+}
+
 }   // namespace avro

Modified: avro/branches/branch-1.5/lang/c++/impl/parsing/ResolvingDecoder.cc
URL: http://svn.apache.org/viewvc/avro/branches/branch-1.5/lang/c%2B%2B/impl/parsing/ResolvingDecoder.cc?rev=1087078&r1=1087077&r2=1087078&view=diff
==============================================================================
--- avro/branches/branch-1.5/lang/c++/impl/parsing/ResolvingDecoder.cc (original)
+++ avro/branches/branch-1.5/lang/c++/impl/parsing/ResolvingDecoder.cc Wed Mar 30 21:15:58 2011
@@ -450,6 +450,7 @@ template <typename P>
 void ResolvingDecoderImpl<P>::init(InputStream& is)
 {
     base_->init(is);
+    parser_.reset();
 }
 
 template <typename P>

Modified: avro/branches/branch-1.5/lang/c++/impl/parsing/Symbol.hh
URL: http://svn.apache.org/viewvc/avro/branches/branch-1.5/lang/c%2B%2B/impl/parsing/Symbol.hh?rev=1087078&r1=1087077&r2=1087078&view=diff
==============================================================================
--- avro/branches/branch-1.5/lang/c++/impl/parsing/Symbol.hh (original)
+++ avro/branches/branch-1.5/lang/c++/impl/parsing/Symbol.hh Wed Mar 30 21:15:58 2011
@@ -693,6 +693,12 @@ public:
         parsingStack.push(s);
     }
 
+    void reset() {
+        while (parsingStack.size() > 1) {
+            parsingStack.pop();
+        }
+    }
+
 };
 
 }   // namespace parsing

Modified: avro/branches/branch-1.5/lang/c++/parser/AvroLex.ll
URL: http://svn.apache.org/viewvc/avro/branches/branch-1.5/lang/c%2B%2B/parser/AvroLex.ll?rev=1087078&r1=1087077&r2=1087078&view=diff
==============================================================================
--- avro/branches/branch-1.5/lang/c++/parser/AvroLex.ll (original)
+++ avro/branches/branch-1.5/lang/c++/parser/AvroLex.ll Wed Mar 30 21:15:58 2011
@@ -109,7 +109,7 @@ anytext .*
 <READFIELD>\"name\"{delim}\"    yy_push_state(READFIELDNAME); 
 <READFIELD>\}                   yy_pop_state(); return AVRO_LEX_FIELD_END;
 <READFIELD>,                    return yytext[0];
-<READFIELD>{avrotext}+{delim}      yy_push_state(READMETADATA); return AVRO_LEX_METADATA;
+<READFIELD>\"{avrotext}\"+{delim}      yy_push_state(READMETADATA); return AVRO_LEX_METADATA;
 <READFIELD>{ws}                 ;
 
 <READFIELDS>\{                  yy_push_state(READFIELD); return AVRO_LEX_FIELD;
@@ -158,7 +158,7 @@ anytext .*
 <INOBJECT>\"symbols\"{delim}\[  yy_push_state(READSYMBOLS); return AVRO_LEX_SYMBOLS;
 <INOBJECT>,                     return yytext[0];
 <INOBJECT>\}                    yy_pop_state(); return yytext[0];
-<INOBJECT>{avrotext}+{delim}       yy_push_state(READMETADATA); return AVRO_LEX_METADATA;
+<INOBJECT>\"{avrotext}+\"{delim}       yy_push_state(READMETADATA); return AVRO_LEX_METADATA;
 <INOBJECT>{ws}                  ;
 
 <STARTTYPE>\"                   yy_pop_state(); yy_push_state(READTYPE); 

Modified: avro/branches/branch-1.5/lang/c++/test/CodecTests.cc
URL: http://svn.apache.org/viewvc/avro/branches/branch-1.5/lang/c%2B%2B/test/CodecTests.cc?rev=1087078&r1=1087077&r2=1087078&view=diff
==============================================================================
--- avro/branches/branch-1.5/lang/c++/test/CodecTests.cc (original)
+++ avro/branches/branch-1.5/lang/c++/test/CodecTests.cc Wed Mar 30 21:15:58 2011
@@ -22,6 +22,7 @@
 #include "Decoder.hh"
 #include "Compiler.hh"
 #include "ValidSchema.hh"
+#include "Generic.hh"
 
 #include <stdint.h>
 #include <vector>
@@ -53,6 +54,14 @@ static const unsigned int count = 10;
  * To test Json encoder and decoder, we use the same technqiue with only
  * one difference - we use JsonEncoder and JsonDecoder.
  *
+ * We also use the same infrastructure to test GenericReader and GenericWriter.
+ * In this case, avro binary is generated in the standard way. It is read
+ * into a GenericDatum, which in turn is written out. This newly serialized
+ * data is decoded in the standard way to check that it is what is written. The
+ * last step won't work if there is schema for reading is different from
+ * that for writing. This is because any reordering of fields would have
+ * got fixed by the GenericDatum's decoding and encoding step.
+ *
  * For most tests, the data is generated at random.
  */
 
@@ -611,7 +620,7 @@ void testCodec(const TestData& td) {
                 << " schema: " << td.schema
                 << " calls: " << td.calls
                 << " skip-level: " << skipLevel << std::endl;
-            */
+                */
             BOOST_TEST_CHECKPOINT("Test: " << testNo << ' '
                 << " schema: " << td.schema
                 << " calls: " << td.calls
@@ -736,6 +745,128 @@ void testWriterFail(const TestData2& td)
         td.incorrectCalls, v, p), Exception);
 }
 
+template<typename CodecFactory>
+void testGeneric(const TestData& td) {
+    static int testNo = 0;
+    testNo++;
+
+    ValidSchema vs = makeValidSchema(td.schema);
+
+    for (unsigned int i = 0; i < count; ++i) {
+        vector<string> v;
+        auto_ptr<OutputStream> p;
+        testEncoder(CodecFactory::newEncoder(vs), td.calls, v, p);
+        // dump(*p);
+        DecoderPtr d1 = CodecFactory::newDecoder(vs);
+        auto_ptr<InputStream> in1 = memoryInputStream(*p);
+        d1->init(*in1);
+        GenericReader gr(vs, d1);
+        GenericDatum datum;
+        gr.read(datum);
+
+        EncoderPtr e2 = CodecFactory::newEncoder(vs);
+        auto_ptr<OutputStream> ob = memoryOutputStream();
+        e2->init(*ob);
+
+        GenericWriter gw(vs, e2);
+        gw.write(datum);
+        e2->flush();
+
+        BOOST_TEST_CHECKPOINT("Test: " << testNo << ' '
+            << " schema: " << td.schema
+            << " calls: " << td.calls);
+        auto_ptr<InputStream> in2 = memoryInputStream(*ob);
+        testDecoder(CodecFactory::newDecoder(vs), v, *in2,
+            td.calls, td.depth);
+    }
+}
+
+template<typename CodecFactory>
+void testGenericResolving(const TestData3& td) {
+    static int testNo = 0;
+    testNo++;
+
+    BOOST_TEST_CHECKPOINT("Test: " << testNo << ' '
+        << " writer schema: " << td.writerSchema
+        << " writer calls: " << td.writerCalls
+        << " reader schema: " << td.readerSchema
+        << " reader calls: " << td.readerCalls);
+
+    ValidSchema wvs = makeValidSchema(td.writerSchema);
+    ValidSchema rvs = makeValidSchema(td.readerSchema);
+
+    for (unsigned int i = 0; i < count; ++i) {
+        vector<string> v;
+        auto_ptr<OutputStream> p;
+        testEncoder(CodecFactory::newEncoder(wvs), td.writerCalls, v, p);
+        // dump(*p);
+        DecoderPtr d1 = CodecFactory::newDecoder(wvs);
+        auto_ptr<InputStream> in1 = memoryInputStream(*p);
+        d1->init(*in1);
+
+        GenericReader gr(wvs, rvs, d1);
+        GenericDatum datum;
+        gr.read(datum);
+
+        EncoderPtr e2 = CodecFactory::newEncoder(rvs);
+        auto_ptr<OutputStream> ob = memoryOutputStream();
+        e2->init(*ob);
+
+        GenericWriter gw(rvs, e2);
+        gw.write(datum);
+        e2->flush();
+
+        BOOST_TEST_CHECKPOINT("Test: " << testNo << ' '
+            << " writer-schemai " << td.writerSchema
+            << " writer-calls: " << td.writerCalls 
+            << " reader-schema: " << td.readerSchema
+            << " calls: " << td.readerCalls);
+        auto_ptr<InputStream> in2 = memoryInputStream(*ob);
+        testDecoder(CodecFactory::newDecoder(rvs), v, *in2,
+            td.readerCalls, td.depth);
+    }
+}
+
+template<typename CodecFactory>
+void testGenericResolving2(const TestData4& td) {
+    static int testNo = 0;
+    testNo++;
+
+    BOOST_TEST_CHECKPOINT("Test: " << testNo << ' '
+        << " writer schema: " << td.writerSchema
+        << " writer calls: " << td.writerCalls
+        << " reader schema: " << td.readerSchema
+        << " reader calls: " << td.readerCalls);
+
+    ValidSchema wvs = makeValidSchema(td.writerSchema);
+    ValidSchema rvs = makeValidSchema(td.readerSchema);
+
+    const vector<string> wd = mkValues(td.writerValues);
+
+    auto_ptr<OutputStream> p = generate(*CodecFactory::newEncoder(wvs),
+        td.writerCalls, wd);
+    // dump(*p);
+    DecoderPtr d1 = CodecFactory::newDecoder(wvs);
+    auto_ptr<InputStream> in1 = memoryInputStream(*p);
+    d1->init(*in1);
+
+    GenericReader gr(wvs, rvs, d1);
+    GenericDatum datum;
+    gr.read(datum);
+
+    EncoderPtr e2 = CodecFactory::newEncoder(rvs);
+    auto_ptr<OutputStream> ob = memoryOutputStream();
+    e2->init(*ob);
+
+    GenericWriter gw(rvs, e2);
+    gw.write(datum);
+    e2->flush();
+    // We cannot verify with the reader calls because they are for
+    // the resolving decoder and hence could be in a different order than
+    // the "normal" data.
+}
+
+
 static const TestData data[] = {
     { "\"null\"", "N", 1 },
     { "\"boolean\"", "B", 1 },
@@ -1262,6 +1393,10 @@ void add_tests(boost::unit_test::test_su
         testCodecResolving2, data4);
     ADD_TESTS(ts, ValidatingEncoderResolvingDecoderFactory,
         testCodecResolving2, data4);
+
+    ADD_TESTS(ts, ValidatingCodecFactory, testGeneric, data);
+    ADD_TESTS(ts, ValidatingCodecFactory, testGenericResolving, data3);
+    ADD_TESTS(ts, ValidatingCodecFactory, testGenericResolving2, data4);
 }
 
 }   // namespace parsing